blob: 88ebbf4e9dc1e17c8197b4e0f5315d813a583670 [file] [log] [blame]
Ben Murdoch85b71792012-04-11 18:30:58 +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
Ben Murdoch85b71792012-04-11 18:30:58 +010056// 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;
Steve Blocka7e24c12009-10-30 11:49:00 +000060
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 Murdoch85b71792012-04-11 18:30:58 +0100135 if (IsSmi()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000136 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoch85b71792012-04-11 18:30:58 +0100137 holder = global_context->number_function()->instance_prototype();
138 } else {
139 HeapObject* heap_object = HeapObject::cast(this);
140 if (heap_object->IsJSObject()) {
141 return JSObject::cast(this)->Lookup(name, result);
142 } else if (heap_object->IsJSProxy()) {
143 return result->HandlerResult();
144 }
145 Context* global_context = Isolate::Current()->context()->global_context();
146 if (heap_object->IsString()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000147 holder = global_context->string_function()->instance_prototype();
Ben Murdoch85b71792012-04-11 18:30:58 +0100148 } else if (heap_object->IsHeapNumber()) {
149 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.
Ben Murdoch85b71792012-04-11 18:30:58 +0100155 JSObject::cast(holder)->Lookup(name, result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000156}
157
158
John Reck59135872010-11-02 12:39:01 -0700159MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
160 String* name,
161 PropertyAttributes* attributes) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100162 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000163 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
Ben Murdoch85b71792012-04-11 18:30:58 +0100170MaybeObject* 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*>(
Ben Murdoch85b71792012-04-11 18:30:58 +0100181 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);
Ben Murdoch85b71792012-04-11 18:30:58 +0100194 JSObject* holder_handle = JSObject::cast(holder);
Steve Blocka7e24c12009-10-30 11:49:00 +0000195 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +0100196 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
Ben Murdoch85b71792012-04-11 18:30:58 +0100197 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
Ben Murdoch85b71792012-04-11 18:30:58 +0100213 if (structure->IsFixedArray()) {
214 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
215 if (getter->IsJSFunction()) {
216 return Object::GetPropertyWithDefinedGetter(receiver,
217 JSFunction::cast(getter));
Steve Blocka7e24c12009-10-30 11:49:00 +0000218 }
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 Murdoch85b71792012-04-11 18:30:58 +0100228MaybeObject* 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);
Ben Murdoch85b71792012-04-11 18:30:58 +0100235 Handle<Object> handler(handler_raw);
Ben Murdoch257744e2011-11-30 15:57:28 +0000236
Ben Murdoch85b71792012-04-11 18:30:58 +0100237 // Extract trap function.
238 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 Murdoch85b71792012-04-11 18:30:58 +0100241 if (trap->IsUndefined()) {
242 // Get the derived `get' property.
243 trap = isolate->derived_get_trap();
244 }
245
246 // Call trap function.
247 Object** args[] = { receiver.location(), name.location() };
248 bool has_exception;
249 Handle<Object> result =
250 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
251 if (has_exception) return Failure::Exception();
Ben Murdoch257744e2011-11-30 15:57:28 +0000252
253 return *result;
254}
255
256
John Reck59135872010-11-02 12:39:01 -0700257MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
Ben Murdoch85b71792012-04-11 18:30:58 +0100258 JSFunction* getter) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000259 HandleScope scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100260 Handle<JSFunction> fun(JSFunction::cast(getter));
Steve Blocka7e24c12009-10-30 11:49:00 +0000261 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.
Ben Murdoch85b71792012-04-11 18:30:58 +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 =
Ben Murdoch85b71792012-04-11 18:30:58 +0100271 Execution::Call(fun, self, 0, NULL, &has_pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +0000272 // 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();
Ben Murdoch85b71792012-04-11 18:30:58 +0100293 return GetPropertyWithCallback(receiver,
294 result->GetCallbackObject(),
295 name,
296 result->holder());
Steve Blocka7e24c12009-10-30 11:49:00 +0000297 }
298 }
299 break;
300 }
301 case NORMAL:
302 case FIELD:
303 case CONSTANT_FUNCTION: {
304 // Search ALL_CAN_READ accessors in prototype chain.
Ben Murdoch85b71792012-04-11 18:30:58 +0100305 LookupResult r;
Steve Blocka7e24c12009-10-30 11:49:00 +0000306 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.
Ben Murdoch85b71792012-04-11 18:30:58 +0100318 LookupResult r;
Steve Blocka7e24c12009-10-30 11:49:00 +0000319 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.
Ben Murdoch85b71792012-04-11 18:30:58 +0100365 LookupResult r;
Steve Blocka7e24c12009-10-30 11:49:00 +0000366 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.
Ben Murdoch85b71792012-04-11 18:30:58 +0100379 LookupResult r;
Steve Blocka7e24c12009-10-30 11:49:00 +0000380 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 Murdoch85b71792012-04-11 18:30:58 +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 Murdoch85b71792012-04-11 18:30:58 +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()) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100540 Object* last = result->IsProperty() ? result->holder() : heap->null_value();
Ben Murdoch257744e2011-11-30 15:57:28 +0000541 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;
Ben Murdoch85b71792012-04-11 18:30:58 +0100569 JSObject* holder = result->holder();
Steve Blocka7e24c12009-10-30 11:49:00 +0000570 switch (result->type()) {
571 case NORMAL:
Ben Murdoch85b71792012-04-11 18:30:58 +0100572 value = holder->GetNormalizedProperty(result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 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:
Ben Murdoch85b71792012-04-11 18:30:58 +0100576 value = holder->FastPropertyAt(result->GetFieldIndex());
Steve Blocka7e24c12009-10-30 11:49:00 +0000577 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:
Ben Murdoch85b71792012-04-11 18:30:58 +0100582 return GetPropertyWithCallback(receiver,
583 result->GetCallbackObject(),
584 name,
585 holder);
586 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);
Ben Murdoch85b71792012-04-11 18:30:58 +0100592 return holder->GetPropertyWithInterceptor(recvr, name, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000593 }
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()) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100616 if (holder->IsSmi()) {
617 Context* global_context = Isolate::Current()->context()->global_context();
618 holder = global_context->number_function()->instance_prototype();
619 } else {
620 HeapObject* heap_object = HeapObject::cast(holder);
621 if (!heap_object->IsJSObject()) {
622 Isolate* isolate = heap->isolate();
623 Context* global_context = isolate->context()->global_context();
624 if (heap_object->IsString()) {
625 holder = global_context->string_function()->instance_prototype();
626 } else if (heap_object->IsHeapNumber()) {
627 holder = global_context->number_function()->instance_prototype();
628 } else if (heap_object->IsBoolean()) {
629 holder = global_context->boolean_function()->instance_prototype();
630 } else if (heap_object->IsJSProxy()) {
631 // TODO(rossberg): do something
632 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 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000638 }
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(
Ben Murdoch85b71792012-04-11 18:30:58 +0100661 js_object->elements(),
662 index,
663 js_object,
664 receiver);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000665 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);
Ben Murdoch85b71792012-04-11 18:30:58 +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.
Ben Murdoch85b71792012-04-11 18:30:58 +0100847 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.
Steve Blocka7e24c12009-10-30 11:49:00 +0000850 return false;
851 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100852 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();
Ben Murdoch85b71792012-04-11 18:30:58 +0100855 int length = this->length();
856 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.
Ben Murdoch85b71792012-04-11 18:30:58 +0100860 this->set_map(is_ascii ?
861 heap->external_string_with_ascii_data_map() :
862 heap->external_string_map());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000863 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
Ben Murdoch85b71792012-04-11 18:30:58 +0100864 self->set_length(length);
865 self->set_hash_field(hash_field);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000866 self->set_resource(resource);
Ben Murdoch85b71792012-04-11 18:30:58 +0100867 // 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.
872 this->set_map(is_ascii ?
873 heap->external_symbol_with_ascii_data_map() :
874 heap->external_symbol_map());
875 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000876
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.
Ben Murdoch85b71792012-04-11 18:30:58 +0100898 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.
Steve Blocka7e24c12009-10-30 11:49:00 +0000901 return false;
902 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100903 ASSERT(size >= ExternalString::kSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000904 bool is_symbol = this->IsSymbol();
Ben Murdoch85b71792012-04-11 18:30:58 +0100905 int length = this->length();
906 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
Ben Murdoch85b71792012-04-11 18:30:58 +0100909 // reinitializing the fields.
910 this->set_map(heap->external_ascii_string_map());
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000911 ExternalAsciiString* self = ExternalAsciiString::cast(this);
Ben Murdoch85b71792012-04-11 18:30:58 +0100912 self->set_length(length);
913 self->set_hash_field(hash_field);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000914 self->set_resource(resource);
Ben Murdoch85b71792012-04-11 18:30:58 +0100915 // 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.
920 this->set_map(heap->external_ascii_symbol_map());
921 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000922
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();
Ben Murdoch85b71792012-04-11 18:30:58 +0100997 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
Steve Blocka7e24c12009-10-30 11:49:00 +0000998 break;
999 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001000 case JS_WEAK_MAP_TYPE: {
Ben Murdoch85b71792012-04-11 18:30:58 +01001001 int elements = JSWeakMap::cast(this)->table()->NumberOfElements();
1002 accumulator->Add("<JS WeakMap[%d]>", elements);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001003 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();
Ben Murdoch85b71792012-04-11 18:30:58 +01001030 Heap* heap = map_of_this->heap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001031 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 Murdoch85b71792012-04-11 18:30:58 +01001052 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) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001074 // if (!HEAP->InNewSpace(this)) PrintF("*", this);
Steve Block44f0eee2011-05-26 01:26:41 +01001075 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:
Ben Murdoch85b71792012-04-11 18:30:58 +01001097 accumulator->Add("<Map>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001098 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 Murdoch85b71792012-04-11 18:30:58 +01001511 ASSERT(!GetHeap()->InNewSpace(function));
1512
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 Murdoch85b71792012-04-11 18:30:58 +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();
Ben Murdoch85b71792012-04-11 18:30:58 +01001612 Heap* heap = map_of_this->heap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001613 if (!map_of_this->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001614 if (strict_mode == kNonStrictMode) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001615 return heap->undefined_value();
Steve Block44f0eee2011-05-26 01:26:41 +01001616 } 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) {
Ben Murdoch85b71792012-04-11 18:30:58 +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.
Ben Murdoch85b71792012-04-11 18:30:58 +01001654 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001655 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.
Ben Murdoch85b71792012-04-11 18:30:58 +01001674 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
Steve Blocka7e24c12009-10-30 11:49:00 +00001675 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 Murdoch85b71792012-04-11 18:30:58 +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) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001828 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001829 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*>(
Ben Murdoch85b71792012-04-11 18:30:58 +01001853 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
Ben Murdoch85b71792012-04-11 18:30:58 +01001881 if (structure->IsFixedArray()) {
1882 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
1883 if (setter->IsJSFunction()) {
1884 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001885 } 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
Ben Murdoch85b71792012-04-11 18:30:58 +01001903MaybeObject* 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);
Ben Murdoch85b71792012-04-11 18:30:58 +01001907 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.
Ben Murdoch85b71792012-04-11 18:30:58 +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;
Ben Murdoch85b71792012-04-11 18:30:58 +01001917 Object** argv[] = { value_handle.location() };
1918 Execution::Call(fun, self, 1, argv, &has_pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +00001919 // 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 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00001954 SeededNumberDictionary* dictionary =
1955 JSObject::cast(pt)->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +00001956 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00001957 if (entry != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001958 PropertyDetails details = dictionary->DetailsAt(entry);
1959 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01001960 *found = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001961 return SetElementWithCallback(dictionary->ValueAt(entry),
1962 index,
1963 value,
1964 JSObject::cast(pt),
1965 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001966 }
1967 }
1968 }
Steve Block1e0659c2011-05-24 12:43:12 +01001969 *found = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001970 return heap->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001971}
1972
1973
1974void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1975 DescriptorArray* descriptors = map()->instance_descriptors();
Iain Merrick75681382010-08-19 15:07:18 +01001976 int number = descriptors->SearchWithCache(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001977 if (number != DescriptorArray::kNotFound) {
1978 result->DescriptorResult(this, descriptors->GetDetails(number), number);
1979 } else {
1980 result->NotFound();
1981 }
1982}
1983
1984
Ben Murdochb0fe1622011-05-05 13:52:32 +01001985void Map::LookupInDescriptors(JSObject* holder,
1986 String* name,
1987 LookupResult* result) {
1988 DescriptorArray* descriptors = instance_descriptors();
Ben Murdoch85b71792012-04-11 18:30:58 +01001989 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
Steve Block44f0eee2011-05-26 01:26:41 +01001990 int number = cache->Lookup(descriptors, name);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001991 if (number == DescriptorLookupCache::kAbsent) {
1992 number = descriptors->Search(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001993 cache->Update(descriptors, name, number);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001994 }
1995 if (number != DescriptorArray::kNotFound) {
1996 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
1997 } else {
1998 result->NotFound();
1999 }
2000}
2001
2002
Ben Murdoch85b71792012-04-11 18:30:58 +01002003MaybeObject* Map::GetElementsTransitionMap(ElementsKind elements_kind,
2004 bool safe_to_add_transition) {
2005 Heap* current_heap = heap();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002006 DescriptorArray* descriptors = instance_descriptors();
Ben Murdoch85b71792012-04-11 18:30:58 +01002007 String* elements_transition_sentinel_name = current_heap->empty_symbol();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002008
2009 if (safe_to_add_transition) {
2010 // It's only safe to manipulate the descriptor array if it would be
2011 // safe to add a transition.
Ben Murdoch85b71792012-04-11 18:30:58 +01002012
2013 ASSERT(!is_shared()); // no transitions can be added to shared maps.
2014 // Check if the elements transition already exists.
2015 DescriptorLookupCache* cache =
2016 current_heap->isolate()->descriptor_lookup_cache();
2017 int index = cache->Lookup(descriptors, elements_transition_sentinel_name);
2018 if (index == DescriptorLookupCache::kAbsent) {
2019 index = descriptors->Search(elements_transition_sentinel_name);
2020 cache->Update(descriptors,
2021 elements_transition_sentinel_name,
2022 index);
2023 }
2024
2025 // If the transition already exists, check the type. If there is a match,
2026 // return it.
2027 if (index != DescriptorArray::kNotFound) {
2028 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
2029 if (details.type() == ELEMENTS_TRANSITION &&
2030 details.elements_kind() == elements_kind) {
2031 return descriptors->GetValue(index);
2032 } else {
2033 safe_to_add_transition = false;
2034 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002035 }
2036 }
2037
Ben Murdoch589d6972011-11-30 16:04:58 +00002038 // No transition to an existing map for the given ElementsKind. Make a new
2039 // one.
Ben Murdoch85b71792012-04-11 18:30:58 +01002040 Object* obj;
2041 { MaybeObject* maybe_map = CopyDropTransitions();
2042 if (!maybe_map->ToObject(&obj)) return maybe_map;
Steve Block44f0eee2011-05-26 01:26:41 +01002043 }
Ben Murdoch85b71792012-04-11 18:30:58 +01002044 Map* new_map = Map::cast(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01002045
Ben Murdoch85b71792012-04-11 18:30:58 +01002046 new_map->set_elements_kind(elements_kind);
2047 GetIsolate()->counters()->map_to_external_array_elements()->Increment();
Steve Block44f0eee2011-05-26 01:26:41 +01002048
2049 // Only remember the map transition if the object's map is NOT equal to the
2050 // global object_function's map and there is not an already existing
Ben Murdoch589d6972011-11-30 16:04:58 +00002051 // non-matching element transition.
Ben Murdoch85b71792012-04-11 18:30:58 +01002052 bool allow_map_transition =
2053 safe_to_add_transition &&
2054 (GetIsolate()->context()->global_context()->object_function()->map() !=
2055 map());
Steve Block44f0eee2011-05-26 01:26:41 +01002056 if (allow_map_transition) {
Ben Murdoch85b71792012-04-11 18:30:58 +01002057 // Allocate new instance descriptors for the old map with map transition.
2058 ElementsTransitionDescriptor desc(elements_transition_sentinel_name,
2059 Map::cast(new_map),
2060 elements_kind);
2061 Object* new_descriptors;
2062 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
2063 &desc,
2064 KEEP_TRANSITIONS);
2065 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2066 return maybe_new_descriptors;
2067 }
2068 descriptors = DescriptorArray::cast(new_descriptors);
2069 set_instance_descriptors(descriptors);
Steve Block44f0eee2011-05-26 01:26:41 +01002070 }
Ben Murdoch85b71792012-04-11 18:30:58 +01002071
Steve Block44f0eee2011-05-26 01:26:41 +01002072 return new_map;
2073}
2074
2075
Steve Blocka7e24c12009-10-30 11:49:00 +00002076void JSObject::LocalLookupRealNamedProperty(String* name,
2077 LookupResult* result) {
2078 if (IsJSGlobalProxy()) {
2079 Object* proto = GetPrototype();
2080 if (proto->IsNull()) return result->NotFound();
2081 ASSERT(proto->IsJSGlobalObject());
2082 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2083 }
2084
2085 if (HasFastProperties()) {
2086 LookupInDescriptor(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002087 if (result->IsFound()) {
2088 // A property, a map transition or a null descriptor was found.
2089 // We return all of these result types because
2090 // LocalLookupRealNamedProperty is used when setting properties
2091 // where map transitions and null descriptors are handled.
Steve Blocka7e24c12009-10-30 11:49:00 +00002092 ASSERT(result->holder() == this && result->type() != NORMAL);
2093 // Disallow caching for uninitialized constants. These can only
2094 // occur as fields.
2095 if (result->IsReadOnly() && result->type() == FIELD &&
2096 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2097 result->DisallowCaching();
2098 }
2099 return;
2100 }
2101 } else {
2102 int entry = property_dictionary()->FindEntry(name);
2103 if (entry != StringDictionary::kNotFound) {
2104 Object* value = property_dictionary()->ValueAt(entry);
2105 if (IsGlobalObject()) {
2106 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2107 if (d.IsDeleted()) {
2108 result->NotFound();
2109 return;
2110 }
2111 value = JSGlobalPropertyCell::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002112 }
2113 // Make sure to disallow caching for uninitialized constants
2114 // found in the dictionary-mode objects.
2115 if (value->IsTheHole()) result->DisallowCaching();
2116 result->DictionaryResult(this, entry);
2117 return;
2118 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002119 }
2120 result->NotFound();
2121}
2122
2123
2124void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2125 LocalLookupRealNamedProperty(name, result);
2126 if (result->IsProperty()) return;
2127
2128 LookupRealNamedPropertyInPrototypes(name, result);
2129}
2130
2131
2132void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2133 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01002134 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002135 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002136 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002137 pt = JSObject::cast(pt)->GetPrototype()) {
2138 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002139 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002140 }
2141 result->NotFound();
2142}
2143
2144
2145// We only need to deal with CALLBACKS and INTERCEPTORS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002146MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2147 LookupResult* result,
2148 String* name,
2149 Object* value,
2150 bool check_prototype,
2151 StrictModeFlag strict_mode) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002152 if (check_prototype && !result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002153 LookupCallbackSetterInPrototypes(name, result);
2154 }
2155
2156 if (result->IsProperty()) {
2157 if (!result->IsReadOnly()) {
2158 switch (result->type()) {
2159 case CALLBACKS: {
2160 Object* obj = result->GetCallbackObject();
2161 if (obj->IsAccessorInfo()) {
2162 AccessorInfo* info = AccessorInfo::cast(obj);
2163 if (info->all_can_write()) {
2164 return SetPropertyWithCallback(result->GetCallbackObject(),
2165 name,
2166 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002167 result->holder(),
2168 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002169 }
2170 }
2171 break;
2172 }
2173 case INTERCEPTOR: {
2174 // Try lookup real named properties. Note that only property can be
2175 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
Ben Murdoch85b71792012-04-11 18:30:58 +01002176 LookupResult r;
Steve Blocka7e24c12009-10-30 11:49:00 +00002177 LookupRealNamedProperty(name, &r);
2178 if (r.IsProperty()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002179 return SetPropertyWithFailedAccessCheck(&r,
2180 name,
2181 value,
2182 check_prototype,
2183 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002184 }
2185 break;
2186 }
2187 default: {
2188 break;
2189 }
2190 }
2191 }
2192 }
2193
Ben Murdoch85b71792012-04-11 18:30:58 +01002194 Heap* heap = GetHeap();
2195 HandleScope scope(heap->isolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002196 Handle<Object> value_handle(value);
Ben Murdoch85b71792012-04-11 18:30:58 +01002197 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
Iain Merrick75681382010-08-19 15:07:18 +01002198 return *value_handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00002199}
2200
2201
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002202MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2203 String* key,
2204 Object* value,
2205 PropertyAttributes attributes,
2206 StrictModeFlag strict_mode) {
2207 if (result->IsFound() && result->type() == HANDLER) {
Ben Murdoch85b71792012-04-11 18:30:58 +01002208 return JSProxy::cast(this)->SetPropertyWithHandler(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002209 key, value, attributes, strict_mode);
2210 } else {
2211 return JSObject::cast(this)->SetPropertyForResult(
2212 result, key, value, attributes, strict_mode);
2213 }
2214}
2215
2216
2217bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2218 Isolate* isolate = GetIsolate();
2219 HandleScope scope(isolate);
2220 Handle<Object> receiver(this);
2221 Handle<Object> name(name_raw);
Ben Murdoch85b71792012-04-11 18:30:58 +01002222 Handle<Object> handler(this->handler());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002223
Ben Murdoch85b71792012-04-11 18:30:58 +01002224 // Extract trap function.
2225 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
2226 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
Ben Murdoch589d6972011-11-30 16:04:58 +00002227 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch85b71792012-04-11 18:30:58 +01002228 if (trap->IsUndefined()) {
2229 trap = isolate->derived_has_trap();
2230 }
2231
2232 // Call trap function.
2233 Object** args[] = { name.location() };
2234 bool has_exception;
2235 Handle<Object> result =
2236 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2237 if (has_exception) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002238
2239 return result->ToBoolean()->IsTrue();
2240}
2241
2242
2243MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2244 String* name_raw,
2245 Object* value_raw,
2246 PropertyAttributes attributes,
2247 StrictModeFlag strict_mode) {
2248 Isolate* isolate = GetIsolate();
2249 HandleScope scope(isolate);
2250 Handle<Object> receiver(this);
2251 Handle<Object> name(name_raw);
2252 Handle<Object> value(value_raw);
Ben Murdoch85b71792012-04-11 18:30:58 +01002253 Handle<Object> handler(this->handler());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002254
Ben Murdoch85b71792012-04-11 18:30:58 +01002255 // Extract trap function.
2256 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set");
2257 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
Ben Murdoch589d6972011-11-30 16:04:58 +00002258 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch85b71792012-04-11 18:30:58 +01002259 if (trap->IsUndefined()) {
2260 trap = isolate->derived_set_trap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002261 }
2262
Ben Murdoch85b71792012-04-11 18:30:58 +01002263 // Call trap function.
2264 Object** args[] = {
2265 receiver.location(), name.location(), value.location()
2266 };
2267 bool has_exception;
2268 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2269 if (has_exception) return Failure::Exception();
2270
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002271 return *value;
2272}
2273
2274
2275MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2276 String* name_raw, DeleteMode mode) {
2277 Isolate* isolate = GetIsolate();
2278 HandleScope scope(isolate);
2279 Handle<Object> receiver(this);
2280 Handle<Object> name(name_raw);
Ben Murdoch85b71792012-04-11 18:30:58 +01002281 Handle<Object> handler(this->handler());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002282
Ben Murdoch85b71792012-04-11 18:30:58 +01002283 // Extract trap function.
2284 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2285 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
Ben Murdoch589d6972011-11-30 16:04:58 +00002286 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch85b71792012-04-11 18:30:58 +01002287 if (trap->IsUndefined()) {
2288 Handle<Object> args[] = { handler, trap_name };
2289 Handle<Object> error = isolate->factory()->NewTypeError(
2290 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2291 isolate->Throw(*error);
2292 return Failure::Exception();
2293 }
2294
2295 // Call trap function.
2296 Object** args[] = { name.location() };
2297 bool has_exception;
2298 Handle<Object> result =
2299 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2300 if (has_exception) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002301
2302 Object* bool_result = result->ToBoolean();
Ben Murdoch85b71792012-04-11 18:30:58 +01002303 if (mode == STRICT_DELETION &&
2304 bool_result == isolate->heap()->false_value()) {
2305 Handle<Object> args[] = { handler, trap_name };
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002306 Handle<Object> error = isolate->factory()->NewTypeError(
2307 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2308 isolate->Throw(*error);
2309 return Failure::Exception();
2310 }
2311 return bool_result;
2312}
2313
2314
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002315MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2316 JSReceiver* receiver_raw,
Ben Murdoch85b71792012-04-11 18:30:58 +01002317 String* name_raw,
2318 bool* has_exception) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002319 Isolate* isolate = GetIsolate();
2320 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002321 Handle<JSReceiver> receiver(receiver_raw);
2322 Handle<Object> name(name_raw);
Ben Murdoch85b71792012-04-11 18:30:58 +01002323 Handle<Object> handler(this->handler());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002324
Ben Murdoch85b71792012-04-11 18:30:58 +01002325 // Extract trap function.
2326 Handle<String> trap_name =
2327 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2328 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
Ben Murdoch589d6972011-11-30 16:04:58 +00002329 if (isolate->has_pending_exception()) return NONE;
Ben Murdoch85b71792012-04-11 18:30:58 +01002330 if (trap->IsUndefined()) {
2331 Handle<Object> args[] = { handler, trap_name };
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002332 Handle<Object> error = isolate->factory()->NewTypeError(
Ben Murdoch85b71792012-04-11 18:30:58 +01002333 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002334 isolate->Throw(*error);
Ben Murdoch85b71792012-04-11 18:30:58 +01002335 *has_exception = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002336 return NONE;
2337 }
2338
Ben Murdoch85b71792012-04-11 18:30:58 +01002339 // Call trap function.
2340 Object** args[] = { name.location() };
2341 Handle<Object> result =
2342 Execution::Call(trap, handler, ARRAY_SIZE(args), args, has_exception);
2343 if (has_exception) return NONE;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002344
Ben Murdoch85b71792012-04-11 18:30:58 +01002345 // TODO(rossberg): convert result to PropertyAttributes
2346 USE(result);
2347 return NONE;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002348}
2349
2350
2351void JSProxy::Fix() {
2352 Isolate* isolate = GetIsolate();
2353 HandleScope scope(isolate);
2354 Handle<JSProxy> self(this);
2355
Ben Murdoch589d6972011-11-30 16:04:58 +00002356 if (IsJSFunctionProxy()) {
2357 isolate->factory()->BecomeJSFunction(self);
2358 // Code will be set on the JavaScript side.
2359 } else {
2360 isolate->factory()->BecomeJSObject(self);
2361 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002362 ASSERT(self->IsJSObject());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002363}
2364
2365
2366
2367MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
2368 String* name,
2369 Object* value,
2370 PropertyAttributes attributes,
2371 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002372 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002373 // Make sure that the top context does not change when doing callbacks or
2374 // interceptor calls.
2375 AssertNoContextChange ncc;
2376
Steve Blockd0582a62009-12-15 09:54:21 +00002377 // Optimization for 2-byte strings often used as keys in a decompression
2378 // dictionary. We make these short keys into symbols to avoid constantly
2379 // reallocating them.
2380 if (!name->IsSymbol() && name->length() <= 2) {
John Reck59135872010-11-02 12:39:01 -07002381 Object* symbol_version;
Steve Block44f0eee2011-05-26 01:26:41 +01002382 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
John Reck59135872010-11-02 12:39:01 -07002383 if (maybe_symbol_version->ToObject(&symbol_version)) {
2384 name = String::cast(symbol_version);
2385 }
2386 }
Steve Blockd0582a62009-12-15 09:54:21 +00002387 }
2388
Steve Blocka7e24c12009-10-30 11:49:00 +00002389 // Check access rights if needed.
Ben Murdoch85b71792012-04-11 18:30:58 +01002390 if (IsAccessCheckNeeded()
2391 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
2392 return SetPropertyWithFailedAccessCheck(result,
2393 name,
2394 value,
2395 true,
2396 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002397 }
2398
2399 if (IsJSGlobalProxy()) {
2400 Object* proto = GetPrototype();
2401 if (proto->IsNull()) return value;
2402 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch85b71792012-04-11 18:30:58 +01002403 return JSObject::cast(proto)->SetProperty(
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002404 result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002405 }
2406
2407 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01002408 // We could not find a local property so let's check whether there is an
2409 // accessor that wants to handle the property.
2410 LookupResult accessor_result;
2411 LookupCallbackSetterInPrototypes(name, &accessor_result);
2412 if (accessor_result.IsProperty()) {
2413 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2414 name,
2415 value,
2416 accessor_result.holder(),
2417 strict_mode);
2418 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002419 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002420 if (!result->IsFound()) {
2421 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002422 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002423 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002424 if (result->IsReadOnly() && result->IsProperty()) {
2425 if (strict_mode == kStrictMode) {
Ben Murdoch85b71792012-04-11 18:30:58 +01002426 HandleScope scope(heap->isolate());
2427 Handle<String> key(name);
2428 Handle<Object> holder(this);
2429 Handle<Object> args[2] = { key, holder };
Steve Block44f0eee2011-05-26 01:26:41 +01002430 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
Ben Murdoch85b71792012-04-11 18:30:58 +01002431 "strict_read_only_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002432 } else {
2433 return value;
2434 }
2435 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002436 // This is a real property that is not read-only, or it is a
2437 // transition or null descriptor and there are no setters in the prototypes.
2438 switch (result->type()) {
2439 case NORMAL:
2440 return SetNormalizedProperty(result, value);
2441 case FIELD:
2442 return FastPropertyAtPut(result->GetFieldIndex(), value);
2443 case MAP_TRANSITION:
2444 if (attributes == result->GetAttributes()) {
2445 // Only use map transition if the attributes match.
2446 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2447 name,
2448 value);
2449 }
2450 return ConvertDescriptorToField(name, value, attributes);
2451 case CONSTANT_FUNCTION:
2452 // Only replace the function if necessary.
2453 if (value == result->GetConstantFunction()) return value;
2454 // Preserve the attributes of this existing property.
2455 attributes = result->GetAttributes();
2456 return ConvertDescriptorToField(name, value, attributes);
2457 case CALLBACKS:
2458 return SetPropertyWithCallback(result->GetCallbackObject(),
2459 name,
2460 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002461 result->holder(),
2462 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002463 case INTERCEPTOR:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002464 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
Iain Merrick75681382010-08-19 15:07:18 +01002465 case CONSTANT_TRANSITION: {
2466 // If the same constant function is being added we can simply
2467 // transition to the target map.
2468 Map* target_map = result->GetTransitionMap();
2469 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2470 int number = target_descriptors->SearchWithCache(name);
2471 ASSERT(number != DescriptorArray::kNotFound);
2472 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2473 JSFunction* function =
2474 JSFunction::cast(target_descriptors->GetValue(number));
Ben Murdoch85b71792012-04-11 18:30:58 +01002475 ASSERT(!HEAP->InNewSpace(function));
Iain Merrick75681382010-08-19 15:07:18 +01002476 if (value == function) {
2477 set_map(target_map);
2478 return value;
2479 }
2480 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2481 // FIELD, even if the value is a constant function.
Steve Blocka7e24c12009-10-30 11:49:00 +00002482 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Iain Merrick75681382010-08-19 15:07:18 +01002483 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002484 case NULL_DESCRIPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00002485 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002486 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Ben Murdoch85b71792012-04-11 18:30:58 +01002487 default:
Steve Blocka7e24c12009-10-30 11:49:00 +00002488 UNREACHABLE();
2489 }
Ben Murdoch85b71792012-04-11 18:30:58 +01002490 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002491 return value;
2492}
2493
2494
2495// Set a real local property, even if it is READ_ONLY. If the property is not
2496// present, add it with attributes NONE. This code is an exact clone of
2497// SetProperty, with the check for IsReadOnly and the check for a
2498// callback setter removed. The two lines looking up the LookupResult
2499// result are also added. If one of the functions is changed, the other
2500// should be.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002501// Note that this method cannot be used to set the prototype of a function
2502// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
2503// doesn't handle function prototypes correctly.
Ben Murdoch086aeea2011-05-13 15:57:08 +01002504MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002505 String* name,
2506 Object* value,
2507 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01002508
Steve Blocka7e24c12009-10-30 11:49:00 +00002509 // Make sure that the top context does not change when doing callbacks or
2510 // interceptor calls.
2511 AssertNoContextChange ncc;
Ben Murdoch85b71792012-04-11 18:30:58 +01002512 LookupResult result;
Andrei Popescu402d9372010-02-26 13:31:12 +00002513 LocalLookup(name, &result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002514 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002515 if (IsAccessCheckNeeded()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01002516 Heap* heap = GetHeap();
2517 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002518 return SetPropertyWithFailedAccessCheck(&result,
2519 name,
2520 value,
2521 false,
2522 kNonStrictMode);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002523 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002524 }
2525
2526 if (IsJSGlobalProxy()) {
2527 Object* proto = GetPrototype();
2528 if (proto->IsNull()) return value;
2529 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch086aeea2011-05-13 15:57:08 +01002530 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002531 name,
2532 value,
2533 attributes);
2534 }
2535
2536 // Check for accessor in prototype chain removed here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002537 if (!result.IsFound()) {
2538 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002539 return AddProperty(name, value, attributes, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002540 }
Steve Block6ded16b2010-05-10 14:33:55 +01002541
Andrei Popescu402d9372010-02-26 13:31:12 +00002542 PropertyDetails details = PropertyDetails(attributes, NORMAL);
2543
Steve Blocka7e24c12009-10-30 11:49:00 +00002544 // Check of IsReadOnly removed from here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002545 switch (result.type()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002546 case NORMAL:
Andrei Popescu402d9372010-02-26 13:31:12 +00002547 return SetNormalizedProperty(name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00002548 case FIELD:
Andrei Popescu402d9372010-02-26 13:31:12 +00002549 return FastPropertyAtPut(result.GetFieldIndex(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002550 case MAP_TRANSITION:
Andrei Popescu402d9372010-02-26 13:31:12 +00002551 if (attributes == result.GetAttributes()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002552 // Only use map transition if the attributes match.
Andrei Popescu402d9372010-02-26 13:31:12 +00002553 return AddFastPropertyUsingMap(result.GetTransitionMap(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002554 name,
2555 value);
2556 }
2557 return ConvertDescriptorToField(name, value, attributes);
2558 case CONSTANT_FUNCTION:
2559 // Only replace the function if necessary.
Andrei Popescu402d9372010-02-26 13:31:12 +00002560 if (value == result.GetConstantFunction()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00002561 // Preserve the attributes of this existing property.
Andrei Popescu402d9372010-02-26 13:31:12 +00002562 attributes = result.GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +00002563 return ConvertDescriptorToField(name, value, attributes);
2564 case CALLBACKS:
2565 case INTERCEPTOR:
2566 // Override callback in clone
2567 return ConvertDescriptorToField(name, value, attributes);
2568 case CONSTANT_TRANSITION:
2569 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
2570 // if the value is a function.
2571 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2572 case NULL_DESCRIPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00002573 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002574 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Ben Murdoch85b71792012-04-11 18:30:58 +01002575 default:
Steve Blocka7e24c12009-10-30 11:49:00 +00002576 UNREACHABLE();
2577 }
Ben Murdoch85b71792012-04-11 18:30:58 +01002578 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002579 return value;
2580}
2581
2582
2583PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
2584 JSObject* receiver,
2585 String* name,
2586 bool continue_search) {
2587 // Check local property, ignore interceptor.
Ben Murdoch85b71792012-04-11 18:30:58 +01002588 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002589 LocalLookupRealNamedProperty(name, &result);
2590 if (result.IsProperty()) return result.GetAttributes();
2591
2592 if (continue_search) {
2593 // Continue searching via the prototype chain.
2594 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002595 if (!pt->IsNull()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002596 return JSObject::cast(pt)->
2597 GetPropertyAttributeWithReceiver(receiver, name);
2598 }
2599 }
2600 return ABSENT;
2601}
2602
2603
2604PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2605 JSObject* receiver,
2606 String* name,
2607 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +01002608 Isolate* isolate = GetIsolate();
2609
Steve Blocka7e24c12009-10-30 11:49:00 +00002610 // Make sure that the top context does not change when doing
2611 // callbacks or interceptor calls.
2612 AssertNoContextChange ncc;
2613
Steve Block44f0eee2011-05-26 01:26:41 +01002614 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002615 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2616 Handle<JSObject> receiver_handle(receiver);
2617 Handle<JSObject> holder_handle(this);
2618 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002619 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002620 v8::AccessorInfo info(args.end());
2621 if (!interceptor->query()->IsUndefined()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002622 v8::NamedPropertyQuery query =
2623 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01002624 LOG(isolate,
2625 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002626 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002627 {
2628 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002629 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002630 result = query(v8::Utils::ToLocal(name_handle), info);
2631 }
2632 if (!result.IsEmpty()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002633 ASSERT(result->IsInt32());
2634 return static_cast<PropertyAttributes>(result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002635 }
2636 } else if (!interceptor->getter()->IsUndefined()) {
2637 v8::NamedPropertyGetter getter =
2638 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01002639 LOG(isolate,
2640 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
Steve Blocka7e24c12009-10-30 11:49:00 +00002641 v8::Handle<v8::Value> result;
2642 {
2643 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002644 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002645 result = getter(v8::Utils::ToLocal(name_handle), info);
2646 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002647 if (!result.IsEmpty()) return DONT_ENUM;
Steve Blocka7e24c12009-10-30 11:49:00 +00002648 }
2649 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2650 *name_handle,
2651 continue_search);
2652}
2653
2654
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002655PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
2656 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00002657 String* key) {
2658 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002659 if (IsJSObject() && key->AsArrayIndex(&index)) {
Ben Murdoch85b71792012-04-11 18:30:58 +01002660 if (JSObject::cast(this)->HasElementWithReceiver(receiver, index))
2661 return NONE;
2662 return ABSENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00002663 }
2664 // Named property.
Ben Murdoch85b71792012-04-11 18:30:58 +01002665 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002666 Lookup(key, &result);
2667 return GetPropertyAttribute(receiver, &result, key, true);
2668}
2669
2670
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002671PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
2672 LookupResult* result,
2673 String* name,
2674 bool continue_search) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002675 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002676 if (IsAccessCheckNeeded()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002677 JSObject* this_obj = JSObject::cast(this);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002678 Heap* heap = GetHeap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002679 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
2680 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
2681 receiver, result, name, continue_search);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002682 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002683 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002684 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002685 switch (result->type()) {
2686 case NORMAL: // fall through
2687 case FIELD:
2688 case CONSTANT_FUNCTION:
2689 case CALLBACKS:
2690 return result->GetAttributes();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002691 case HANDLER: {
Ben Murdoch85b71792012-04-11 18:30:58 +01002692 // TODO(rossberg): propagate exceptions properly.
2693 bool has_exception = false;
2694 return JSProxy::cast(this)->GetPropertyAttributeWithHandler(
2695 receiver, name, &has_exception);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002696 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002697 case INTERCEPTOR:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002698 return result->holder()->GetPropertyAttributeWithInterceptor(
2699 JSObject::cast(receiver), name, continue_search);
Steve Blocka7e24c12009-10-30 11:49:00 +00002700 default:
2701 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002702 }
2703 }
2704 return ABSENT;
2705}
2706
2707
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002708PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002709 // Check whether the name is an array index.
2710 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002711 if (IsJSObject() && name->AsArrayIndex(&index)) {
2712 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
Steve Blocka7e24c12009-10-30 11:49:00 +00002713 return ABSENT;
2714 }
2715 // Named property.
Ben Murdoch85b71792012-04-11 18:30:58 +01002716 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002717 LocalLookup(name, &result);
2718 return GetPropertyAttribute(this, &result, name, false);
2719}
2720
2721
John Reck59135872010-11-02 12:39:01 -07002722MaybeObject* NormalizedMapCache::Get(JSObject* obj,
2723 PropertyNormalizationMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002724 Isolate* isolate = obj->GetIsolate();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002725 Map* fast = obj->map();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002726 int index = fast->Hash() % kEntries;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002727 Object* result = get(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002728 if (result->IsMap() &&
2729 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002730#ifdef DEBUG
Ben Murdoch85b71792012-04-11 18:30:58 +01002731 Map::cast(result)->SharedMapVerify();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002732 if (FLAG_enable_slow_asserts) {
2733 // The cached map should match newly created normalized map bit-by-bit.
John Reck59135872010-11-02 12:39:01 -07002734 Object* fresh;
2735 { MaybeObject* maybe_fresh =
2736 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2737 if (maybe_fresh->ToObject(&fresh)) {
2738 ASSERT(memcmp(Map::cast(fresh)->address(),
2739 Map::cast(result)->address(),
2740 Map::kSize) == 0);
2741 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002742 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002743 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002744#endif
2745 return result;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002746 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002747
John Reck59135872010-11-02 12:39:01 -07002748 { MaybeObject* maybe_result =
2749 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2750 if (!maybe_result->ToObject(&result)) return maybe_result;
2751 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002752 set(index, result);
Steve Block44f0eee2011-05-26 01:26:41 +01002753 isolate->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002754
2755 return result;
2756}
2757
2758
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002759void NormalizedMapCache::Clear() {
2760 int entries = length();
2761 for (int i = 0; i != entries; i++) {
2762 set_undefined(i);
2763 }
2764}
2765
2766
John Reck59135872010-11-02 12:39:01 -07002767MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002768 if (map()->is_shared()) {
2769 // Fast case maps are never marked as shared.
2770 ASSERT(!HasFastProperties());
2771 // Replace the map with an identical copy that can be safely modified.
John Reck59135872010-11-02 12:39:01 -07002772 Object* obj;
2773 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2774 UNIQUE_NORMALIZED_MAP);
2775 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2776 }
Steve Block44f0eee2011-05-26 01:26:41 +01002777 GetIsolate()->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002778
2779 set_map(Map::cast(obj));
2780 }
2781 return map()->UpdateCodeCache(name, code);
2782}
2783
2784
John Reck59135872010-11-02 12:39:01 -07002785MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
2786 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002787 if (!HasFastProperties()) return this;
2788
2789 // The global object is always normalized.
2790 ASSERT(!IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01002791 // JSGlobalProxy must never be normalized
2792 ASSERT(!IsJSGlobalProxy());
2793
Ben Murdoch8b112d22011-06-08 16:22:53 +01002794 Map* map_of_this = map();
Steve Block44f0eee2011-05-26 01:26:41 +01002795
Steve Blocka7e24c12009-10-30 11:49:00 +00002796 // Allocate new content.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002797 int property_count = map_of_this->NumberOfDescribedProperties();
Steve Blocka7e24c12009-10-30 11:49:00 +00002798 if (expected_additional_properties > 0) {
2799 property_count += expected_additional_properties;
2800 } else {
2801 property_count += 2; // Make space for two more properties.
2802 }
Ben Murdoch85b71792012-04-11 18:30:58 +01002803 Object* obj;
2804 { MaybeObject* maybe_obj =
2805 StringDictionary::Allocate(property_count);
2806 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
John Reck59135872010-11-02 12:39:01 -07002807 }
Ben Murdoch85b71792012-04-11 18:30:58 +01002808 StringDictionary* dictionary = StringDictionary::cast(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00002809
Ben Murdoch8b112d22011-06-08 16:22:53 +01002810 DescriptorArray* descs = map_of_this->instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00002811 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002812 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00002813 switch (details.type()) {
2814 case CONSTANT_FUNCTION: {
2815 PropertyDetails d =
2816 PropertyDetails(details.attributes(), NORMAL, details.index());
2817 Object* value = descs->GetConstantFunction(i);
Ben Murdoch85b71792012-04-11 18:30:58 +01002818 Object* result;
2819 { MaybeObject* maybe_result =
2820 dictionary->Add(descs->GetKey(i), value, d);
2821 if (!maybe_result->ToObject(&result)) return maybe_result;
2822 }
2823 dictionary = StringDictionary::cast(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002824 break;
2825 }
2826 case FIELD: {
2827 PropertyDetails d =
2828 PropertyDetails(details.attributes(), NORMAL, details.index());
2829 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
Ben Murdoch85b71792012-04-11 18:30:58 +01002830 Object* result;
2831 { MaybeObject* maybe_result =
2832 dictionary->Add(descs->GetKey(i), value, d);
2833 if (!maybe_result->ToObject(&result)) return maybe_result;
2834 }
2835 dictionary = StringDictionary::cast(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002836 break;
2837 }
2838 case CALLBACKS: {
Ben Murdoch85b71792012-04-11 18:30:58 +01002839 PropertyDetails d =
2840 PropertyDetails(details.attributes(), CALLBACKS, details.index());
Steve Blocka7e24c12009-10-30 11:49:00 +00002841 Object* value = descs->GetCallbacksObject(i);
Ben Murdoch85b71792012-04-11 18:30:58 +01002842 Object* result;
2843 { MaybeObject* maybe_result =
2844 dictionary->Add(descs->GetKey(i), value, d);
2845 if (!maybe_result->ToObject(&result)) return maybe_result;
John Reck59135872010-11-02 12:39:01 -07002846 }
Ben Murdoch85b71792012-04-11 18:30:58 +01002847 dictionary = StringDictionary::cast(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002848 break;
2849 }
2850 case MAP_TRANSITION:
2851 case CONSTANT_TRANSITION:
2852 case NULL_DESCRIPTOR:
2853 case INTERCEPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00002854 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002855 break;
Ben Murdoch85b71792012-04-11 18:30:58 +01002856 default:
Steve Blocka7e24c12009-10-30 11:49:00 +00002857 UNREACHABLE();
2858 }
2859 }
2860
Ben Murdoch85b71792012-04-11 18:30:58 +01002861 Heap* current_heap = map_of_this->heap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01002862
Steve Blocka7e24c12009-10-30 11:49:00 +00002863 // Copy the next enumeration index from instance descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002864 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002865 dictionary->SetNextEnumerationIndex(index);
2866
Ben Murdoch85b71792012-04-11 18:30:58 +01002867 { MaybeObject* maybe_obj =
Ben Murdoch8b112d22011-06-08 16:22:53 +01002868 current_heap->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01002869 normalized_map_cache()->Get(this, mode);
Ben Murdoch85b71792012-04-11 18:30:58 +01002870 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
John Reck59135872010-11-02 12:39:01 -07002871 }
Ben Murdoch85b71792012-04-11 18:30:58 +01002872 Map* new_map = Map::cast(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00002873
Steve Blocka7e24c12009-10-30 11:49:00 +00002874 // We have now successfully allocated all the necessary objects.
2875 // Changes can now be made with the guarantee that all of them take effect.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002876
2877 // Resize the object in the heap if necessary.
2878 int new_instance_size = new_map->instance_size();
Ben Murdoch8b112d22011-06-08 16:22:53 +01002879 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002880 ASSERT(instance_size_delta >= 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002881 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
2882 instance_size_delta);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002883
Steve Blocka7e24c12009-10-30 11:49:00 +00002884 set_map(new_map);
Ben Murdoch257744e2011-11-30 15:57:28 +00002885 new_map->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00002886
2887 set_properties(dictionary);
2888
Ben Murdoch8b112d22011-06-08 16:22:53 +01002889 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002890
2891#ifdef DEBUG
2892 if (FLAG_trace_normalization) {
2893 PrintF("Object properties have been normalized:\n");
2894 Print();
2895 }
2896#endif
2897 return this;
2898}
2899
2900
John Reck59135872010-11-02 12:39:01 -07002901MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002902 if (HasFastProperties()) return this;
2903 ASSERT(!IsGlobalObject());
2904 return property_dictionary()->
2905 TransformPropertiesToFastFor(this, unused_property_fields);
2906}
2907
2908
John Reck59135872010-11-02 12:39:01 -07002909MaybeObject* JSObject::NormalizeElements() {
Steve Block44f0eee2011-05-26 01:26:41 +01002910 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01002911
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002912 // Find the backing store.
2913 FixedArrayBase* array = FixedArrayBase::cast(elements());
2914 Map* old_map = array->map();
2915 bool is_arguments =
Ben Murdoch85b71792012-04-11 18:30:58 +01002916 (old_map == old_map->heap()->non_strict_arguments_elements_map());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002917 if (is_arguments) {
2918 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
John Reck59135872010-11-02 12:39:01 -07002919 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002920 if (array->IsDictionary()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00002921
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002922 ASSERT(HasFastElements() ||
2923 HasFastDoubleElements() ||
2924 HasFastArgumentsElements());
2925 // Compute the effective length and allocate a new backing store.
2926 int length = IsJSArray()
2927 ? Smi::cast(JSArray::cast(this)->length())->value()
2928 : array->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002929 int old_capacity = 0;
2930 int used_elements = 0;
2931 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdochc7cc0282012-03-05 14:35:55 +00002932 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002933 { Object* object;
Ben Murdochc7cc0282012-03-05 14:35:55 +00002934 MaybeObject* maybe = SeededNumberDictionary::Allocate(used_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002935 if (!maybe->ToObject(&object)) return maybe;
Ben Murdochc7cc0282012-03-05 14:35:55 +00002936 dictionary = SeededNumberDictionary::cast(object);
John Reck59135872010-11-02 12:39:01 -07002937 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002938
2939 // Copy the elements to the new backing store.
2940 bool has_double_elements = array->IsFixedDoubleArray();
Steve Blocka7e24c12009-10-30 11:49:00 +00002941 for (int i = 0; i < length; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002942 Object* value = NULL;
2943 if (has_double_elements) {
2944 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
2945 if (double_array->is_the_hole(i)) {
2946 value = GetIsolate()->heap()->the_hole_value();
2947 } else {
2948 // Objects must be allocated in the old object space, since the
2949 // overall number of HeapNumbers needed for the conversion might
2950 // exceed the capacity of new space, and we would fail repeatedly
2951 // trying to convert the FixedDoubleArray.
2952 MaybeObject* maybe_value_object =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002953 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002954 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
John Reck59135872010-11-02 12:39:01 -07002955 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002956 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +01002957 ASSERT(old_map->has_fast_elements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002958 value = FixedArray::cast(array)->get(i);
2959 }
2960 PropertyDetails details = PropertyDetails(NONE, NORMAL);
2961 if (!value->IsTheHole()) {
2962 Object* result;
2963 MaybeObject* maybe_result =
2964 dictionary->AddNumberEntry(i, value, details);
2965 if (!maybe_result->ToObject(&result)) return maybe_result;
Ben Murdochc7cc0282012-03-05 14:35:55 +00002966 dictionary = SeededNumberDictionary::cast(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002967 }
2968 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002969
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002970 // Switch to using the dictionary as the backing storage for elements.
2971 if (is_arguments) {
2972 FixedArray::cast(elements())->set(1, dictionary);
2973 } else {
2974 // Set the new map first to satify the elements type assert in
2975 // set_elements().
2976 Object* new_map;
Ben Murdoch85b71792012-04-11 18:30:58 +01002977 MaybeObject* maybe = map()->GetSlowElementsMap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002978 if (!maybe->ToObject(&new_map)) return maybe;
2979 set_map(Map::cast(new_map));
2980 set_elements(dictionary);
2981 }
2982
Ben Murdoch85b71792012-04-11 18:30:58 +01002983 old_map->isolate()->counters()->elements_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002984
2985#ifdef DEBUG
2986 if (FLAG_trace_normalization) {
2987 PrintF("Object elements have been normalized:\n");
2988 Print();
2989 }
2990#endif
2991
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002992 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
2993 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00002994}
2995
2996
Ben Murdoch85b71792012-04-11 18:30:58 +01002997MaybeObject* JSObject::GetHiddenProperties(HiddenPropertiesFlag flag) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002998 Isolate* isolate = GetIsolate();
Ben Murdoch85b71792012-04-11 18:30:58 +01002999 Heap* heap = isolate->heap();
3000 Object* holder = BypassGlobalProxy();
3001 if (holder->IsUndefined()) return heap->undefined_value();
3002 JSObject* obj = JSObject::cast(holder);
3003 if (obj->HasFastProperties()) {
3004 // If the object has fast properties, check whether the first slot
3005 // in the descriptor array matches the hidden symbol. Since the
3006 // hidden symbols hash code is zero (and no other string has hash
3007 // code zero) it will always occupy the first entry if present.
3008 DescriptorArray* descriptors = obj->map()->instance_descriptors();
3009 if ((descriptors->number_of_descriptors() > 0) &&
3010 (descriptors->GetKey(0) == heap->hidden_symbol()) &&
3011 descriptors->IsProperty(0)) {
3012 ASSERT(descriptors->GetType(0) == FIELD);
3013 return obj->FastPropertyAt(descriptors->GetFieldIndex(0));
3014 }
3015 }
3016
3017 // Only attempt to find the hidden properties in the local object and not
3018 // in the prototype chain.
3019 if (!obj->HasHiddenPropertiesObject()) {
3020 // Hidden properties object not found. Allocate a new hidden properties
3021 // object if requested. Otherwise return the undefined value.
3022 if (flag == ALLOW_CREATION) {
3023 Object* hidden_obj;
3024 { MaybeObject* maybe_obj = heap->AllocateJSObject(
3025 isolate->context()->global_context()->object_function());
3026 if (!maybe_obj->ToObject(&hidden_obj)) return maybe_obj;
3027 }
3028 // Don't allow leakage of the hidden object through accessors
3029 // on Object.prototype.
3030 {
3031 MaybeObject* maybe_obj =
3032 JSObject::cast(hidden_obj)->SetPrototype(heap->null_value(), false);
3033 if (maybe_obj->IsFailure()) return maybe_obj;
3034 }
3035 return obj->SetHiddenPropertiesObject(hidden_obj);
3036 } else {
3037 return heap->undefined_value();
3038 }
3039 }
3040 return obj->GetHiddenPropertiesObject();
3041}
3042
3043
3044MaybeObject* JSObject::GetIdentityHash(HiddenPropertiesFlag flag) {
3045 Isolate* isolate = GetIsolate();
3046 Object* hidden_props_obj;
3047 { MaybeObject* maybe_obj = GetHiddenProperties(flag);
3048 if (!maybe_obj->ToObject(&hidden_props_obj)) return maybe_obj;
3049 }
3050 if (!hidden_props_obj->IsJSObject()) {
3051 // We failed to create hidden properties. That's a detached
3052 // global proxy.
3053 ASSERT(hidden_props_obj->IsUndefined());
3054 return Smi::FromInt(0);
3055 }
3056 JSObject* hidden_props = JSObject::cast(hidden_props_obj);
3057 String* hash_symbol = isolate->heap()->identity_hash_symbol();
3058 {
3059 // Note that HasLocalProperty() can cause a GC in the general case in the
3060 // presence of interceptors.
3061 AssertNoAllocation no_alloc;
3062 if (hidden_props->HasLocalProperty(hash_symbol)) {
3063 MaybeObject* hash = hidden_props->GetProperty(hash_symbol);
3064 return Smi::cast(hash->ToObjectChecked());
3065 }
3066 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003067
3068 int hash_value;
3069 int attempts = 0;
3070 do {
3071 // Generate a random 32-bit hash value but limit range to fit
3072 // within a smi.
Ben Murdoch85b71792012-04-11 18:30:58 +01003073 hash_value = V8::Random(isolate) & Smi::kMaxValue;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003074 attempts++;
3075 } while (hash_value == 0 && attempts < 30);
3076 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
3077
Ben Murdoch85b71792012-04-11 18:30:58 +01003078 Smi* hash = Smi::FromInt(hash_value);
3079 { MaybeObject* result = hidden_props->SetLocalPropertyIgnoreAttributes(
3080 hash_symbol,
3081 hash,
3082 static_cast<PropertyAttributes>(None));
3083 if (result->IsFailure()) return result;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003084 }
3085 return hash;
3086}
3087
3088
John Reck59135872010-11-02 12:39:01 -07003089MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3090 DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003091 // Check local property, ignore interceptor.
Ben Murdoch85b71792012-04-11 18:30:58 +01003092 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003093 LocalLookupRealNamedProperty(name, &result);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003094 if (!result.IsProperty()) return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003095
3096 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003097 Object* obj;
3098 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3099 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3100 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003101
3102 return DeleteNormalizedProperty(name, mode);
3103}
3104
3105
John Reck59135872010-11-02 12:39:01 -07003106MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +01003107 Isolate* isolate = GetIsolate();
3108 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003109 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3110 Handle<String> name_handle(name);
3111 Handle<JSObject> this_handle(this);
3112 if (!interceptor->deleter()->IsUndefined()) {
3113 v8::NamedPropertyDeleter deleter =
3114 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
Steve Block44f0eee2011-05-26 01:26:41 +01003115 LOG(isolate,
3116 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3117 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003118 v8::AccessorInfo info(args.end());
3119 v8::Handle<v8::Boolean> result;
3120 {
3121 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003122 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003123 result = deleter(v8::Utils::ToLocal(name_handle), info);
3124 }
Steve Block44f0eee2011-05-26 01:26:41 +01003125 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003126 if (!result.IsEmpty()) {
3127 ASSERT(result->IsBoolean());
3128 return *v8::Utils::OpenHandle(*result);
3129 }
3130 }
John Reck59135872010-11-02 12:39:01 -07003131 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00003132 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003133 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003134 return raw_result;
3135}
3136
3137
John Reck59135872010-11-02 12:39:01 -07003138MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01003139 Isolate* isolate = GetIsolate();
3140 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003141 // Make sure that the top context does not change when doing
3142 // callbacks or interceptor calls.
3143 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01003144 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003145 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Steve Block44f0eee2011-05-26 01:26:41 +01003146 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003147 v8::IndexedPropertyDeleter deleter =
3148 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3149 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01003150 LOG(isolate,
3151 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3152 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003153 v8::AccessorInfo info(args.end());
3154 v8::Handle<v8::Boolean> result;
3155 {
3156 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003157 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003158 result = deleter(index, info);
3159 }
Steve Block44f0eee2011-05-26 01:26:41 +01003160 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003161 if (!result.IsEmpty()) {
3162 ASSERT(result->IsBoolean());
3163 return *v8::Utils::OpenHandle(*result);
3164 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003165 MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3166 *this_handle,
3167 index,
3168 NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003169 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003170 return raw_result;
3171}
3172
3173
John Reck59135872010-11-02 12:39:01 -07003174MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003175 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003176 // Check access rights if needed.
3177 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003178 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3179 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3180 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003181 }
3182
3183 if (IsJSGlobalProxy()) {
3184 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003185 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003186 ASSERT(proto->IsJSGlobalObject());
3187 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
3188 }
3189
3190 if (HasIndexedInterceptor()) {
3191 // Skip interceptor if forcing deletion.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003192 if (mode != FORCE_DELETION) {
3193 return DeleteElementWithInterceptor(index);
3194 }
3195 mode = JSReceiver::FORCE_DELETION;
Steve Blocka7e24c12009-10-30 11:49:00 +00003196 }
3197
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003198 return GetElementsAccessor()->Delete(this, index, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003199}
3200
3201
Ben Murdoch85b71792012-04-11 18:30:58 +01003202MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3203 if (IsJSProxy()) {
3204 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
3205 } else {
3206 return JSObject::cast(this)->DeleteProperty(name, mode);
3207 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003208}
3209
3210
John Reck59135872010-11-02 12:39:01 -07003211MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003212 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003213 // ECMA-262, 3rd, 8.6.2.5
3214 ASSERT(name->IsString());
3215
3216 // Check access rights if needed.
3217 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003218 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3219 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3220 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003221 }
3222
3223 if (IsJSGlobalProxy()) {
3224 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003225 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003226 ASSERT(proto->IsJSGlobalObject());
3227 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
3228 }
3229
3230 uint32_t index = 0;
3231 if (name->AsArrayIndex(&index)) {
3232 return DeleteElement(index, mode);
3233 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +01003234 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003235 LocalLookup(name, &result);
Steve Block44f0eee2011-05-26 01:26:41 +01003236 if (!result.IsProperty()) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003237 // Ignore attributes if forcing a deletion.
3238 if (result.IsDontDelete() && mode != FORCE_DELETION) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003239 if (mode == STRICT_DELETION) {
3240 // Deleting a non-configurable property in strict mode.
Steve Block44f0eee2011-05-26 01:26:41 +01003241 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003242 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01003243 return isolate->Throw(*isolate->factory()->NewTypeError(
3244 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003245 }
Steve Block44f0eee2011-05-26 01:26:41 +01003246 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003247 }
3248 // Check for interceptor.
3249 if (result.type() == INTERCEPTOR) {
3250 // Skip interceptor if forcing a deletion.
3251 if (mode == FORCE_DELETION) {
3252 return DeletePropertyPostInterceptor(name, mode);
3253 }
3254 return DeletePropertyWithInterceptor(name);
3255 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003256 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003257 Object* obj;
3258 { MaybeObject* maybe_obj =
3259 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3260 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3261 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003262 // Make sure the properties are normalized before removing the entry.
3263 return DeleteNormalizedProperty(name, mode);
3264 }
3265}
3266
3267
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003268bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
3269 ElementsKind kind,
3270 Object* object) {
Ben Murdoch85b71792012-04-11 18:30:58 +01003271 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003272 if (kind == FAST_ELEMENTS) {
3273 int length = IsJSArray()
3274 ? Smi::cast(JSArray::cast(this)->length())->value()
3275 : elements->length();
3276 for (int i = 0; i < length; ++i) {
3277 Object* element = elements->get(i);
3278 if (!element->IsTheHole() && element == object) return true;
3279 }
3280 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00003281 Object* key =
3282 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003283 if (!key->IsUndefined()) return true;
3284 }
3285 return false;
3286}
3287
3288
Steve Blocka7e24c12009-10-30 11:49:00 +00003289// Check whether this object references another object.
3290bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01003291 Map* map_of_this = map();
Ben Murdoch85b71792012-04-11 18:30:58 +01003292 Heap* heap = map_of_this->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003293 AssertNoAllocation no_alloc;
3294
3295 // Is the object the constructor for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01003296 if (map_of_this->constructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003297 return true;
3298 }
3299
3300 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01003301 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003302 return true;
3303 }
3304
3305 // Check if the object is among the named properties.
3306 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01003307 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003308 return true;
3309 }
3310
3311 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003312 ElementsKind kind = GetElementsKind();
3313 switch (kind) {
Steve Block44f0eee2011-05-26 01:26:41 +01003314 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003315 case EXTERNAL_BYTE_ELEMENTS:
3316 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3317 case EXTERNAL_SHORT_ELEMENTS:
3318 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3319 case EXTERNAL_INT_ELEMENTS:
3320 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3321 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003322 case EXTERNAL_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003323 case FAST_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003324 // Raw pixels and external arrays do not reference other
3325 // objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00003326 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003327 case FAST_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00003328 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003329 FixedArray* elements = FixedArray::cast(this->elements());
3330 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00003331 break;
3332 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003333 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3334 FixedArray* parameter_map = FixedArray::cast(elements());
3335 // Check the mapped parameters.
3336 int length = parameter_map->length();
3337 for (int i = 2; i < length; ++i) {
3338 Object* value = parameter_map->get(i);
3339 if (!value->IsTheHole() && value == obj) return true;
3340 }
3341 // Check the arguments.
3342 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3343 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
3344 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00003345 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003346 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003347 }
3348
Steve Block6ded16b2010-05-10 14:33:55 +01003349 // For functions check the context.
3350 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003351 // Get the constructor function for arguments array.
3352 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +01003353 heap->isolate()->context()->global_context()->
3354 arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003355 JSFunction* arguments_function =
3356 JSFunction::cast(arguments_boilerplate->map()->constructor());
3357
3358 // Get the context and don't check if it is the global context.
3359 JSFunction* f = JSFunction::cast(this);
3360 Context* context = f->context();
3361 if (context->IsGlobalContext()) {
3362 return false;
3363 }
3364
3365 // Check the non-special context slots.
3366 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
3367 // Only check JS objects.
3368 if (context->get(i)->IsJSObject()) {
3369 JSObject* ctxobj = JSObject::cast(context->get(i));
3370 // If it is an arguments array check the content.
3371 if (ctxobj->map()->constructor() == arguments_function) {
3372 if (ctxobj->ReferencesObject(obj)) {
3373 return true;
3374 }
3375 } else if (ctxobj == obj) {
3376 return true;
3377 }
3378 }
3379 }
3380
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003381 // Check the context extension (if any) if it can have references.
3382 if (context->has_extension() && !context->IsCatchContext()) {
3383 return JSObject::cast(context->extension())->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00003384 }
3385 }
3386
3387 // No references to object.
3388 return false;
3389}
3390
3391
John Reck59135872010-11-02 12:39:01 -07003392MaybeObject* JSObject::PreventExtensions() {
Steve Block44f0eee2011-05-26 01:26:41 +01003393 Isolate* isolate = GetIsolate();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003394 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003395 !isolate->MayNamedAccess(this,
3396 isolate->heap()->undefined_value(),
3397 v8::ACCESS_KEYS)) {
3398 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
3399 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003400 }
3401
Steve Block1e0659c2011-05-24 12:43:12 +01003402 if (IsJSGlobalProxy()) {
3403 Object* proto = GetPrototype();
3404 if (proto->IsNull()) return this;
3405 ASSERT(proto->IsJSGlobalObject());
3406 return JSObject::cast(proto)->PreventExtensions();
3407 }
3408
Ben Murdoch257744e2011-11-30 15:57:28 +00003409 // It's not possible to seal objects with external array elements
3410 if (HasExternalArrayElements()) {
3411 HandleScope scope(isolate);
3412 Handle<Object> object(this);
3413 Handle<Object> error =
3414 isolate->factory()->NewTypeError(
3415 "cant_prevent_ext_external_array_elements",
3416 HandleVector(&object, 1));
3417 return isolate->Throw(*error);
3418 }
3419
Steve Block8defd9f2010-07-08 12:39:36 +01003420 // If there are fast elements we normalize.
Ben Murdochc7cc0282012-03-05 14:35:55 +00003421 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003422 { MaybeObject* maybe = NormalizeElements();
Ben Murdochc7cc0282012-03-05 14:35:55 +00003423 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
Steve Block8defd9f2010-07-08 12:39:36 +01003424 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003425 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Block8defd9f2010-07-08 12:39:36 +01003426 // Make sure that we never go back to fast case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003427 dictionary->set_requires_slow_elements();
Steve Block8defd9f2010-07-08 12:39:36 +01003428
3429 // Do a map transition, other objects with this map may still
3430 // be extensible.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003431 Map* new_map;
3432 { MaybeObject* maybe = map()->CopyDropTransitions();
3433 if (!maybe->To<Map>(&new_map)) return maybe;
John Reck59135872010-11-02 12:39:01 -07003434 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003435 new_map->set_is_extensible(false);
3436 set_map(new_map);
Steve Block8defd9f2010-07-08 12:39:36 +01003437 ASSERT(!map()->is_extensible());
3438 return new_map;
3439}
3440
3441
Steve Blocka7e24c12009-10-30 11:49:00 +00003442// Tests for the fast common case for property enumeration:
Ben Murdoch85b71792012-04-11 18:30:58 +01003443// - This object and all prototypes has an enum cache (which means that it has
3444// no interceptors and needs no access checks).
Steve Blockd0582a62009-12-15 09:54:21 +00003445// - This object has no elements.
3446// - No prototype has enumerable properties/elements.
Ben Murdoch85b71792012-04-11 18:30:58 +01003447bool JSObject::IsSimpleEnum() {
Steve Block44f0eee2011-05-26 01:26:41 +01003448 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003449 for (Object* o = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003450 o != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003451 o = JSObject::cast(o)->GetPrototype()) {
3452 JSObject* curr = JSObject::cast(o);
Steve Blocka7e24c12009-10-30 11:49:00 +00003453 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00003454 ASSERT(!curr->HasNamedInterceptor());
3455 ASSERT(!curr->HasIndexedInterceptor());
3456 ASSERT(!curr->IsAccessCheckNeeded());
Steve Blocka7e24c12009-10-30 11:49:00 +00003457 if (curr->NumberOfEnumElements() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003458 if (curr != this) {
3459 FixedArray* curr_fixed_array =
3460 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
Steve Blockd0582a62009-12-15 09:54:21 +00003461 if (curr_fixed_array->length() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003462 }
3463 }
3464 return true;
3465}
3466
3467
Ben Murdoch85b71792012-04-11 18:30:58 +01003468int Map::NumberOfDescribedProperties() {
Steve Blocka7e24c12009-10-30 11:49:00 +00003469 int result = 0;
3470 DescriptorArray* descs = instance_descriptors();
3471 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch85b71792012-04-11 18:30:58 +01003472 if (descs->IsProperty(i)) result++;
Steve Blocka7e24c12009-10-30 11:49:00 +00003473 }
3474 return result;
3475}
3476
3477
3478int Map::PropertyIndexFor(String* name) {
3479 DescriptorArray* descs = instance_descriptors();
3480 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3481 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
3482 return descs->GetFieldIndex(i);
3483 }
3484 }
3485 return -1;
3486}
3487
3488
3489int Map::NextFreePropertyIndex() {
3490 int max_index = -1;
3491 DescriptorArray* descs = instance_descriptors();
3492 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3493 if (descs->GetType(i) == FIELD) {
3494 int current_index = descs->GetFieldIndex(i);
3495 if (current_index > max_index) max_index = current_index;
3496 }
3497 }
3498 return max_index + 1;
3499}
3500
3501
3502AccessorDescriptor* Map::FindAccessor(String* name) {
3503 DescriptorArray* descs = instance_descriptors();
3504 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3505 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
3506 return descs->GetCallbacks(i);
3507 }
3508 }
3509 return NULL;
3510}
3511
3512
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003513void JSReceiver::LocalLookup(String* name, LookupResult* result) {
Ben Murdoch85b71792012-04-11 18:30:58 +01003514 if (IsJSProxy()) {
3515 result->HandlerResult();
3516 } else {
3517 JSObject::cast(this)->LocalLookup(name, result);
3518 }
3519}
3520
3521
3522void JSObject::LocalLookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003523 ASSERT(name->IsString());
3524
Steve Block44f0eee2011-05-26 01:26:41 +01003525 Heap* heap = GetHeap();
3526
Steve Blocka7e24c12009-10-30 11:49:00 +00003527 if (IsJSGlobalProxy()) {
3528 Object* proto = GetPrototype();
3529 if (proto->IsNull()) return result->NotFound();
3530 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch85b71792012-04-11 18:30:58 +01003531 return JSObject::cast(proto)->LocalLookup(name, result);
Steve Blocka7e24c12009-10-30 11:49:00 +00003532 }
3533
3534 // Do not use inline caching if the object is a non-global object
3535 // that requires access checks.
Ben Murdoch85b71792012-04-11 18:30:58 +01003536 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003537 result->DisallowCaching();
3538 }
3539
3540 // Check __proto__ before interceptor.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003541 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01003542 result->ConstantResult(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003543 return;
3544 }
3545
3546 // Check for lookup interceptor except when bootstrapping.
Ben Murdoch85b71792012-04-11 18:30:58 +01003547 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
3548 result->InterceptorResult(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003549 return;
3550 }
3551
Ben Murdoch85b71792012-04-11 18:30:58 +01003552 LocalLookupRealNamedProperty(name, result);
Steve Blocka7e24c12009-10-30 11:49:00 +00003553}
3554
3555
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003556void JSReceiver::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003557 // Ecma-262 3rd 8.6.2.4
Steve Block44f0eee2011-05-26 01:26:41 +01003558 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003559 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003560 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003561 current = JSObject::cast(current)->GetPrototype()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01003562 JSObject::cast(current)->LocalLookup(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003563 if (result->IsProperty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003564 }
3565 result->NotFound();
3566}
3567
3568
3569// Search object and it's prototype chain for callback properties.
3570void JSObject::LookupCallback(String* name, LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01003571 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003572 for (Object* current = this;
Ben Murdoch85b71792012-04-11 18:30:58 +01003573 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003574 current = JSObject::cast(current)->GetPrototype()) {
3575 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
Ben Murdoch85b71792012-04-11 18:30:58 +01003576 if (result->IsProperty() && result->type() == CALLBACKS) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003577 }
3578 result->NotFound();
3579}
3580
3581
Ben Murdoch85b71792012-04-11 18:30:58 +01003582// Search for a getter or setter in an elements dictionary. Returns either
3583// undefined if the element is read-only, or the getter/setter pair (fixed
3584// array) if there is an existing one, or the hole value if the element does
3585// not exist or is a normal non-getter/setter data element.
3586static Object* FindGetterSetterInDictionary(SeededNumberDictionary* dictionary,
3587 uint32_t index,
3588 Heap* heap) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003589 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00003590 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003591 Object* result = dictionary->ValueAt(entry);
3592 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdoch85b71792012-04-11 18:30:58 +01003593 if (details.IsReadOnly()) return heap->undefined_value();
3594 if (details.type() == CALLBACKS && result->IsFixedArray()) return result;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003595 }
Ben Murdoch85b71792012-04-11 18:30:58 +01003596 return heap->the_hole_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003597}
3598
3599
Ben Murdoch85b71792012-04-11 18:30:58 +01003600MaybeObject* JSObject::DefineGetterSetter(String* name,
3601 PropertyAttributes attributes) {
3602 Heap* heap = GetHeap();
3603 // Make sure that the top context does not change when doing callbacks or
3604 // interceptor calls.
3605 AssertNoContextChange ncc;
3606
3607 // Try to flatten before operating on the string.
3608 name->TryFlatten();
3609
3610 if (!CanSetCallback(name)) {
3611 return heap->undefined_value();
3612 }
3613
3614 uint32_t index = 0;
3615 bool is_element = name->AsArrayIndex(&index);
3616
3617 if (is_element) {
3618 switch (GetElementsKind()) {
3619 case FAST_ELEMENTS:
3620 case FAST_DOUBLE_ELEMENTS:
3621 break;
3622 case EXTERNAL_PIXEL_ELEMENTS:
3623 case EXTERNAL_BYTE_ELEMENTS:
3624 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3625 case EXTERNAL_SHORT_ELEMENTS:
3626 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3627 case EXTERNAL_INT_ELEMENTS:
3628 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3629 case EXTERNAL_FLOAT_ELEMENTS:
3630 case EXTERNAL_DOUBLE_ELEMENTS:
3631 // Ignore getters and setters on pixel and external array
3632 // elements.
3633 return heap->undefined_value();
3634 case DICTIONARY_ELEMENTS: {
3635 Object* probe =
3636 FindGetterSetterInDictionary(element_dictionary(), index, heap);
3637 if (!probe->IsTheHole()) return probe;
3638 // Otherwise allow to override it.
3639 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003640 }
Ben Murdoch85b71792012-04-11 18:30:58 +01003641 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3642 // Ascertain whether we have read-only properties or an existing
3643 // getter/setter pair in an arguments elements dictionary backing
3644 // store.
3645 FixedArray* parameter_map = FixedArray::cast(elements());
3646 uint32_t length = parameter_map->length();
3647 Object* probe =
3648 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
3649 if (probe == NULL || probe->IsTheHole()) {
3650 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3651 if (arguments->IsDictionary()) {
3652 SeededNumberDictionary* dictionary =
3653 SeededNumberDictionary::cast(arguments);
3654 probe = FindGetterSetterInDictionary(dictionary, index, heap);
3655 if (!probe->IsTheHole()) return probe;
Steve Blocka7e24c12009-10-30 11:49:00 +00003656 }
3657 }
Ben Murdoch85b71792012-04-11 18:30:58 +01003658 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00003659 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003660 }
Ben Murdoch85b71792012-04-11 18:30:58 +01003661 } else {
3662 // Lookup the name.
3663 LookupResult result;
3664 LocalLookup(name, &result);
3665 if (result.IsProperty()) {
3666 if (result.IsReadOnly()) return heap->undefined_value();
3667 if (result.type() == CALLBACKS) {
3668 Object* obj = result.GetCallbackObject();
3669 // Need to preserve old getters/setters.
3670 if (obj->IsFixedArray()) {
3671 // Use set to update attributes.
3672 return SetPropertyCallback(name, obj, attributes);
Leon Clarked91b9f72010-01-27 17:25:45 +00003673 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003674 }
3675 }
3676 }
3677
Ben Murdoch85b71792012-04-11 18:30:58 +01003678 // Allocate the fixed array to hold getter and setter.
3679 Object* structure;
3680 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
3681 if (!maybe_structure->ToObject(&structure)) return maybe_structure;
John Reck59135872010-11-02 12:39:01 -07003682 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003683
Ben Murdoch85b71792012-04-11 18:30:58 +01003684 if (is_element) {
3685 return SetElementCallback(index, structure, attributes);
3686 } else {
3687 return SetPropertyCallback(name, structure, attributes);
3688 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003689}
3690
3691
3692bool JSObject::CanSetCallback(String* name) {
Ben Murdoch85b71792012-04-11 18:30:58 +01003693 ASSERT(!IsAccessCheckNeeded()
3694 || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
Leon Clarkef7060e22010-06-03 12:02:55 +01003695
3696 // Check if there is an API defined callback object which prohibits
3697 // callback overwriting in this object or it's prototype chain.
3698 // This mechanism is needed for instance in a browser setting, where
3699 // certain accessors such as window.location should not be allowed
3700 // to be overwritten because allowing overwriting could potentially
3701 // cause security problems.
Ben Murdoch85b71792012-04-11 18:30:58 +01003702 LookupResult callback_result;
Leon Clarkef7060e22010-06-03 12:02:55 +01003703 LookupCallback(name, &callback_result);
3704 if (callback_result.IsProperty()) {
3705 Object* obj = callback_result.GetCallbackObject();
3706 if (obj->IsAccessorInfo() &&
3707 AccessorInfo::cast(obj)->prohibits_overwriting()) {
3708 return false;
3709 }
3710 }
3711
3712 return true;
3713}
3714
3715
John Reck59135872010-11-02 12:39:01 -07003716MaybeObject* JSObject::SetElementCallback(uint32_t index,
3717 Object* structure,
3718 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003719 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3720
3721 // Normalize elements to make this operation simple.
Ben Murdoch85b71792012-04-11 18:30:58 +01003722 SeededNumberDictionary* dictionary = NULL;
3723 { Object* result;
3724 MaybeObject* maybe = NormalizeElements();
3725 if (!maybe->ToObject(&result)) return maybe;
3726 dictionary = SeededNumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07003727 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003728 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Leon Clarkef7060e22010-06-03 12:02:55 +01003729
3730 // Update the dictionary with the new CALLBACKS property.
Ben Murdoch85b71792012-04-11 18:30:58 +01003731 { Object* result;
3732 MaybeObject* maybe = dictionary->Set(index, structure, details);
3733 if (!maybe->ToObject(&result)) return maybe;
3734 dictionary = SeededNumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07003735 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003736
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003737 dictionary->set_requires_slow_elements();
3738 // Update the dictionary backing store on the object.
3739 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
3740 // Also delete any parameter alias.
3741 //
3742 // TODO(kmillikin): when deleting the last parameter alias we could
3743 // switch to a direct backing store without the parameter map. This
3744 // would allow GC of the context.
3745 FixedArray* parameter_map = FixedArray::cast(elements());
Ben Murdoch85b71792012-04-11 18:30:58 +01003746 uint32_t length = parameter_map->length();
3747 if (index < length - 2) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003748 parameter_map->set(index + 2, GetHeap()->the_hole_value());
3749 }
3750 parameter_map->set(1, dictionary);
3751 } else {
3752 set_elements(dictionary);
3753 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003754
Ben Murdoch85b71792012-04-11 18:30:58 +01003755 return structure;
Steve Blocka7e24c12009-10-30 11:49:00 +00003756}
3757
3758
John Reck59135872010-11-02 12:39:01 -07003759MaybeObject* JSObject::SetPropertyCallback(String* name,
3760 Object* structure,
3761 PropertyAttributes attributes) {
Ben Murdoch85b71792012-04-11 18:30:58 +01003762 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3763
3764 bool convert_back_to_fast = HasFastProperties() &&
3765 (map()->instance_descriptors()->number_of_descriptors()
3766 < DescriptorArray::kMaxNumberOfDescriptors);
3767
Leon Clarkef7060e22010-06-03 12:02:55 +01003768 // Normalize object to make this operation simple.
Ben Murdoch85b71792012-04-11 18:30:58 +01003769 Object* ok;
John Reck59135872010-11-02 12:39:01 -07003770 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
Ben Murdoch85b71792012-04-11 18:30:58 +01003771 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
John Reck59135872010-11-02 12:39:01 -07003772 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003773
3774 // For the global object allocate a new map to invalidate the global inline
3775 // caches which have a global property cell reference directly in the code.
3776 if (IsGlobalObject()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01003777 Object* new_map;
John Reck59135872010-11-02 12:39:01 -07003778 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
Ben Murdoch85b71792012-04-11 18:30:58 +01003779 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07003780 }
Ben Murdoch85b71792012-04-11 18:30:58 +01003781 set_map(Map::cast(new_map));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003782 // When running crankshaft, changing the map is not enough. We
3783 // need to deoptimize all functions that rely on this global
3784 // object.
3785 Deoptimizer::DeoptimizeGlobalObject(this);
Leon Clarkef7060e22010-06-03 12:02:55 +01003786 }
3787
3788 // Update the dictionary with the new CALLBACKS property.
Ben Murdoch85b71792012-04-11 18:30:58 +01003789 Object* result;
3790 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
3791 if (!maybe_result->ToObject(&result)) return maybe_result;
John Reck59135872010-11-02 12:39:01 -07003792 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003793
Ben Murdoch85b71792012-04-11 18:30:58 +01003794 if (convert_back_to_fast) {
3795 { MaybeObject* maybe_ok = TransformToFastProperties(0);
3796 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3797 }
3798 }
3799 return result;
Leon Clarkef7060e22010-06-03 12:02:55 +01003800}
3801
John Reck59135872010-11-02 12:39:01 -07003802MaybeObject* JSObject::DefineAccessor(String* name,
Ben Murdoch85b71792012-04-11 18:30:58 +01003803 bool is_getter,
3804 Object* fun,
John Reck59135872010-11-02 12:39:01 -07003805 PropertyAttributes attributes) {
Ben Murdoch85b71792012-04-11 18:30:58 +01003806 ASSERT(fun->IsJSFunction() || fun->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01003807 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003808 // Check access rights if needed.
3809 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003810 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3811 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3812 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003813 }
3814
3815 if (IsJSGlobalProxy()) {
3816 Object* proto = GetPrototype();
3817 if (proto->IsNull()) return this;
3818 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch85b71792012-04-11 18:30:58 +01003819 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
3820 fun, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003821 }
3822
Ben Murdoch85b71792012-04-11 18:30:58 +01003823 Object* array;
3824 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
3825 if (!maybe_array->ToObject(&array)) return maybe_array;
3826 }
3827 if (array->IsUndefined()) return array;
3828 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
3829 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00003830}
3831
3832
John Reck59135872010-11-02 12:39:01 -07003833MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Steve Block44f0eee2011-05-26 01:26:41 +01003834 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01003835 String* name = String::cast(info->name());
3836 // Check access rights if needed.
3837 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003838 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3839 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3840 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003841 }
3842
3843 if (IsJSGlobalProxy()) {
3844 Object* proto = GetPrototype();
3845 if (proto->IsNull()) return this;
3846 ASSERT(proto->IsJSGlobalObject());
3847 return JSObject::cast(proto)->DefineAccessor(info);
3848 }
3849
3850 // Make sure that the top context does not change when doing callbacks or
3851 // interceptor calls.
3852 AssertNoContextChange ncc;
3853
3854 // Try to flatten before operating on the string.
3855 name->TryFlatten();
3856
3857 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003858 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003859 }
3860
3861 uint32_t index = 0;
3862 bool is_element = name->AsArrayIndex(&index);
3863
3864 if (is_element) {
Steve Block44f0eee2011-05-26 01:26:41 +01003865 if (IsJSArray()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003866
3867 // Accessors overwrite previous callbacks (cf. with getters/setters).
3868 switch (GetElementsKind()) {
3869 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003870 case FAST_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003871 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003872 case EXTERNAL_PIXEL_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003873 case EXTERNAL_BYTE_ELEMENTS:
3874 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3875 case EXTERNAL_SHORT_ELEMENTS:
3876 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3877 case EXTERNAL_INT_ELEMENTS:
3878 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3879 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003880 case EXTERNAL_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003881 // Ignore getters and setters on pixel and external array
3882 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003883 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003884 case DICTIONARY_ELEMENTS:
3885 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003886 case NON_STRICT_ARGUMENTS_ELEMENTS:
3887 UNIMPLEMENTED();
Leon Clarkef7060e22010-06-03 12:02:55 +01003888 break;
3889 }
3890
Ben Murdoch85b71792012-04-11 18:30:58 +01003891 Object* ok;
John Reck59135872010-11-02 12:39:01 -07003892 { MaybeObject* maybe_ok =
3893 SetElementCallback(index, info, info->property_attributes());
Ben Murdoch85b71792012-04-11 18:30:58 +01003894 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
John Reck59135872010-11-02 12:39:01 -07003895 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003896 } else {
3897 // Lookup the name.
Ben Murdoch85b71792012-04-11 18:30:58 +01003898 LookupResult result;
Leon Clarkef7060e22010-06-03 12:02:55 +01003899 LocalLookup(name, &result);
3900 // ES5 forbids turning a property into an accessor if it's not
3901 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
3902 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
Steve Block44f0eee2011-05-26 01:26:41 +01003903 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003904 }
Ben Murdoch85b71792012-04-11 18:30:58 +01003905 Object* ok;
John Reck59135872010-11-02 12:39:01 -07003906 { MaybeObject* maybe_ok =
3907 SetPropertyCallback(name, info, info->property_attributes());
Ben Murdoch85b71792012-04-11 18:30:58 +01003908 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
John Reck59135872010-11-02 12:39:01 -07003909 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003910 }
3911
3912 return this;
3913}
3914
3915
Ben Murdoch85b71792012-04-11 18:30:58 +01003916Object* JSObject::LookupAccessor(String* name, bool is_getter) {
Steve Block44f0eee2011-05-26 01:26:41 +01003917 Heap* heap = GetHeap();
3918
Steve Blocka7e24c12009-10-30 11:49:00 +00003919 // Make sure that the top context does not change when doing callbacks or
3920 // interceptor calls.
3921 AssertNoContextChange ncc;
3922
3923 // Check access rights if needed.
3924 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003925 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
3926 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
3927 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003928 }
3929
3930 // Make the lookup and include prototypes.
Ben Murdoch85b71792012-04-11 18:30:58 +01003931 int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003932 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003933 if (name->AsArrayIndex(&index)) {
3934 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003935 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003936 obj = JSObject::cast(obj)->GetPrototype()) {
3937 JSObject* js_object = JSObject::cast(obj);
3938 if (js_object->HasDictionaryElements()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00003939 SeededNumberDictionary* dictionary = js_object->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +00003940 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00003941 if (entry != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003942 Object* element = dictionary->ValueAt(entry);
Ben Murdoch85b71792012-04-11 18:30:58 +01003943 PropertyDetails details = dictionary->DetailsAt(entry);
3944 if (details.type() == CALLBACKS) {
3945 if (element->IsFixedArray()) {
3946 return FixedArray::cast(element)->get(accessor_index);
3947 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003948 }
3949 }
3950 }
3951 }
3952 } else {
3953 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003954 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003955 obj = JSObject::cast(obj)->GetPrototype()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01003956 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003957 JSObject::cast(obj)->LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003958 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003959 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003960 if (result.type() == CALLBACKS) {
3961 Object* obj = result.GetCallbackObject();
Ben Murdoch85b71792012-04-11 18:30:58 +01003962 if (obj->IsFixedArray()) {
3963 return FixedArray::cast(obj)->get(accessor_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003964 }
3965 }
3966 }
3967 }
3968 }
Steve Block44f0eee2011-05-26 01:26:41 +01003969 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003970}
3971
3972
3973Object* JSObject::SlowReverseLookup(Object* value) {
3974 if (HasFastProperties()) {
3975 DescriptorArray* descs = map()->instance_descriptors();
3976 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3977 if (descs->GetType(i) == FIELD) {
3978 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
3979 return descs->GetKey(i);
3980 }
3981 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
3982 if (descs->GetConstantFunction(i) == value) {
3983 return descs->GetKey(i);
3984 }
3985 }
3986 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003987 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003988 } else {
3989 return property_dictionary()->SlowReverseLookup(value);
3990 }
3991}
3992
3993
John Reck59135872010-11-02 12:39:01 -07003994MaybeObject* Map::CopyDropDescriptors() {
Steve Block44f0eee2011-05-26 01:26:41 +01003995 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07003996 Object* result;
3997 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01003998 heap->AllocateMap(instance_type(), instance_size());
John Reck59135872010-11-02 12:39:01 -07003999 if (!maybe_result->ToObject(&result)) return maybe_result;
4000 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004001 Map::cast(result)->set_prototype(prototype());
4002 Map::cast(result)->set_constructor(constructor());
4003 // Don't copy descriptors, so map transitions always remain a forest.
4004 // If we retained the same descriptors we would have two maps
4005 // pointing to the same transition which is bad because the garbage
4006 // collector relies on being able to reverse pointers from transitions
4007 // to maps. If properties need to be retained use CopyDropTransitions.
Ben Murdoch257744e2011-11-30 15:57:28 +00004008 Map::cast(result)->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00004009 // Please note instance_type and instance_size are set when allocated.
4010 Map::cast(result)->set_inobject_properties(inobject_properties());
4011 Map::cast(result)->set_unused_property_fields(unused_property_fields());
4012
4013 // If the map has pre-allocated properties always start out with a descriptor
4014 // array describing these properties.
4015 if (pre_allocated_property_fields() > 0) {
4016 ASSERT(constructor()->IsJSFunction());
4017 JSFunction* ctor = JSFunction::cast(constructor());
John Reck59135872010-11-02 12:39:01 -07004018 Object* descriptors;
4019 { MaybeObject* maybe_descriptors =
4020 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4021 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4022 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004023 Map::cast(result)->set_instance_descriptors(
4024 DescriptorArray::cast(descriptors));
4025 Map::cast(result)->set_pre_allocated_property_fields(
4026 pre_allocated_property_fields());
4027 }
4028 Map::cast(result)->set_bit_field(bit_field());
4029 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004030 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004031 Map::cast(result)->set_is_shared(false);
Steve Block44f0eee2011-05-26 01:26:41 +01004032 Map::cast(result)->ClearCodeCache(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00004033 return result;
4034}
4035
4036
John Reck59135872010-11-02 12:39:01 -07004037MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4038 NormalizedMapSharingMode sharing) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004039 int new_instance_size = instance_size();
4040 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4041 new_instance_size -= inobject_properties() * kPointerSize;
4042 }
4043
John Reck59135872010-11-02 12:39:01 -07004044 Object* result;
4045 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004046 GetHeap()->AllocateMap(instance_type(), new_instance_size);
John Reck59135872010-11-02 12:39:01 -07004047 if (!maybe_result->ToObject(&result)) return maybe_result;
4048 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004049
4050 if (mode != CLEAR_INOBJECT_PROPERTIES) {
4051 Map::cast(result)->set_inobject_properties(inobject_properties());
4052 }
4053
4054 Map::cast(result)->set_prototype(prototype());
4055 Map::cast(result)->set_constructor(constructor());
4056
4057 Map::cast(result)->set_bit_field(bit_field());
4058 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004059 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004060
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004061 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4062
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004063#ifdef DEBUG
Ben Murdoch85b71792012-04-11 18:30:58 +01004064 if (Map::cast(result)->is_shared()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004065 Map::cast(result)->SharedMapVerify();
4066 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004067#endif
4068
4069 return result;
4070}
4071
4072
John Reck59135872010-11-02 12:39:01 -07004073MaybeObject* Map::CopyDropTransitions() {
4074 Object* new_map;
4075 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4076 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4077 }
4078 Object* descriptors;
4079 { MaybeObject* maybe_descriptors =
4080 instance_descriptors()->RemoveTransitions();
4081 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4082 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004083 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
Steve Block8defd9f2010-07-08 12:39:36 +01004084 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00004085}
4086
4087
John Reck59135872010-11-02 12:39:01 -07004088MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004089 // Allocate the code cache if not present.
4090 if (code_cache()->IsFixedArray()) {
John Reck59135872010-11-02 12:39:01 -07004091 Object* result;
Ben Murdoch85b71792012-04-11 18:30:58 +01004092 { MaybeObject* maybe_result = code->heap()->AllocateCodeCache();
John Reck59135872010-11-02 12:39:01 -07004093 if (!maybe_result->ToObject(&result)) return maybe_result;
4094 }
Steve Block6ded16b2010-05-10 14:33:55 +01004095 set_code_cache(result);
4096 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004097
Steve Block6ded16b2010-05-10 14:33:55 +01004098 // Update the code cache.
4099 return CodeCache::cast(code_cache())->Update(name, code);
4100}
4101
4102
4103Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4104 // Do a lookup if a code cache exists.
4105 if (!code_cache()->IsFixedArray()) {
4106 return CodeCache::cast(code_cache())->Lookup(name, flags);
4107 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004108 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004109 }
4110}
4111
4112
4113int Map::IndexInCodeCache(Object* name, Code* code) {
4114 // Get the internal index if a code cache exists.
4115 if (!code_cache()->IsFixedArray()) {
4116 return CodeCache::cast(code_cache())->GetIndex(name, code);
4117 }
4118 return -1;
4119}
4120
4121
4122void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4123 // No GC is supposed to happen between a call to IndexInCodeCache and
4124 // RemoveFromCodeCache so the code cache must be there.
4125 ASSERT(!code_cache()->IsFixedArray());
4126 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4127}
4128
4129
Ben Murdoch85b71792012-04-11 18:30:58 +01004130void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
4131 // Traverse the transition tree without using a stack. We do this by
4132 // reversing the pointers in the maps and descriptor arrays.
4133 Map* current = this;
4134 Map* meta_map = heap()->meta_map();
4135 Object** map_or_index_field = NULL;
4136 while (current != meta_map) {
4137 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
4138 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
4139 if (!d->IsEmpty()) {
4140 FixedArray* contents = reinterpret_cast<FixedArray*>(
4141 d->get(DescriptorArray::kContentArrayIndex));
4142 map_or_index_field = RawField(contents, HeapObject::kMapOffset);
4143 Object* map_or_index = *map_or_index_field;
4144 bool map_done = true; // Controls a nested continue statement.
4145 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
4146 i < contents->length();
4147 i += 2) {
4148 PropertyDetails details(Smi::cast(contents->get(i + 1)));
4149 if (details.IsTransition()) {
4150 // Found a map in the transition array. We record our progress in
4151 // the transition array by recording the current map in the map field
4152 // of the next map and recording the index in the transition array in
4153 // the map field of the array.
4154 Map* next = Map::cast(contents->get(i));
4155 next->set_map(current);
4156 *map_or_index_field = Smi::FromInt(i + 2);
4157 current = next;
4158 map_done = false;
Steve Block053d10c2011-06-13 19:13:29 +01004159 break;
4160 }
Ben Murdoch85b71792012-04-11 18:30:58 +01004161 }
4162 if (!map_done) continue;
4163 } else {
4164 map_or_index_field = NULL;
4165 }
4166 // That was the regular transitions, now for the prototype transitions.
4167 FixedArray* prototype_transitions =
4168 current->unchecked_prototype_transitions();
4169 Object** proto_map_or_index_field =
4170 RawField(prototype_transitions, HeapObject::kMapOffset);
4171 Object* map_or_index = *proto_map_or_index_field;
4172 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
4173 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
4174 if (i < prototype_transitions->length()) {
4175 // Found a map in the prototype transition array. Record progress in
4176 // an analogous way to the regular transitions array above.
4177 Object* perhaps_map = prototype_transitions->get(i);
4178 if (perhaps_map->IsMap()) {
4179 Map* next = Map::cast(perhaps_map);
4180 next->set_map(current);
4181 *proto_map_or_index_field =
4182 Smi::FromInt(i + kProtoTransitionElementsPerEntry);
4183 current = next;
4184 continue;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004185 }
4186 }
Ben Murdoch85b71792012-04-11 18:30:58 +01004187 *proto_map_or_index_field = heap()->fixed_array_map();
4188 if (map_or_index_field != NULL) {
4189 *map_or_index_field = heap()->fixed_array_map();
Ben Murdochc7cc0282012-03-05 14:35:55 +00004190 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00004191
Ben Murdoch85b71792012-04-11 18:30:58 +01004192 // The callback expects a map to have a real map as its map, so we save
4193 // the map field, which is being used to track the traversal and put the
4194 // correct map (the meta_map) in place while we do the callback.
4195 Map* prev = current->map();
4196 current->set_map(meta_map);
4197 callback(current, data);
4198 current = prev;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004199 }
4200}
4201
4202
John Reck59135872010-11-02 12:39:01 -07004203MaybeObject* CodeCache::Update(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004204 // The number of monomorphic stubs for normal load/store/call IC's can grow to
4205 // a large number and therefore they need to go into a hash table. They are
4206 // used to load global properties from cells.
4207 if (code->type() == NORMAL) {
4208 // Make sure that a hash table is allocated for the normal load code cache.
4209 if (normal_type_cache()->IsUndefined()) {
John Reck59135872010-11-02 12:39:01 -07004210 Object* result;
4211 { MaybeObject* maybe_result =
4212 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
4213 if (!maybe_result->ToObject(&result)) return maybe_result;
4214 }
Steve Block6ded16b2010-05-10 14:33:55 +01004215 set_normal_type_cache(result);
4216 }
4217 return UpdateNormalTypeCache(name, code);
4218 } else {
4219 ASSERT(default_cache()->IsFixedArray());
4220 return UpdateDefaultCache(name, code);
4221 }
4222}
4223
4224
John Reck59135872010-11-02 12:39:01 -07004225MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004226 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00004227 // flags. This allows call constant stubs to overwrite call field
4228 // stubs, etc.
4229 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
4230
4231 // First check whether we can update existing code cache without
4232 // extending it.
Steve Block6ded16b2010-05-10 14:33:55 +01004233 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004234 int length = cache->length();
4235 int deleted_index = -1;
Steve Block6ded16b2010-05-10 14:33:55 +01004236 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004237 Object* key = cache->get(i);
4238 if (key->IsNull()) {
4239 if (deleted_index < 0) deleted_index = i;
4240 continue;
4241 }
4242 if (key->IsUndefined()) {
4243 if (deleted_index >= 0) i = deleted_index;
Steve Block6ded16b2010-05-10 14:33:55 +01004244 cache->set(i + kCodeCacheEntryNameOffset, name);
4245 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004246 return this;
4247 }
4248 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01004249 Code::Flags found =
4250 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
Steve Blocka7e24c12009-10-30 11:49:00 +00004251 if (Code::RemoveTypeFromFlags(found) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01004252 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004253 return this;
4254 }
4255 }
4256 }
4257
4258 // Reached the end of the code cache. If there were deleted
4259 // elements, reuse the space for the first of them.
4260 if (deleted_index >= 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01004261 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
4262 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004263 return this;
4264 }
4265
Steve Block6ded16b2010-05-10 14:33:55 +01004266 // Extend the code cache with some new entries (at least one). Must be a
4267 // multiple of the entry size.
4268 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
4269 new_length = new_length - new_length % kCodeCacheEntrySize;
4270 ASSERT((new_length % kCodeCacheEntrySize) == 0);
John Reck59135872010-11-02 12:39:01 -07004271 Object* result;
4272 { MaybeObject* maybe_result = cache->CopySize(new_length);
4273 if (!maybe_result->ToObject(&result)) return maybe_result;
4274 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004275
4276 // Add the (name, code) pair to the new cache.
4277 cache = FixedArray::cast(result);
Steve Block6ded16b2010-05-10 14:33:55 +01004278 cache->set(length + kCodeCacheEntryNameOffset, name);
4279 cache->set(length + kCodeCacheEntryCodeOffset, code);
4280 set_default_cache(cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00004281 return this;
4282}
4283
4284
John Reck59135872010-11-02 12:39:01 -07004285MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004286 // Adding a new entry can cause a new cache to be allocated.
4287 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
John Reck59135872010-11-02 12:39:01 -07004288 Object* new_cache;
4289 { MaybeObject* maybe_new_cache = cache->Put(name, code);
4290 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4291 }
Steve Block6ded16b2010-05-10 14:33:55 +01004292 set_normal_type_cache(new_cache);
4293 return this;
4294}
4295
4296
4297Object* CodeCache::Lookup(String* name, Code::Flags flags) {
4298 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
4299 return LookupNormalTypeCache(name, flags);
4300 } else {
4301 return LookupDefaultCache(name, flags);
4302 }
4303}
4304
4305
4306Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
4307 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004308 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01004309 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
4310 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00004311 // Skip deleted elements.
4312 if (key->IsNull()) continue;
4313 if (key->IsUndefined()) return key;
4314 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01004315 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
4316 if (code->flags() == flags) {
4317 return code;
4318 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004319 }
4320 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01004321 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004322}
4323
4324
Steve Block6ded16b2010-05-10 14:33:55 +01004325Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
4326 if (!normal_type_cache()->IsUndefined()) {
4327 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4328 return cache->Lookup(name, flags);
4329 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004330 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004331 }
4332}
4333
4334
4335int CodeCache::GetIndex(Object* name, Code* code) {
4336 if (code->type() == NORMAL) {
4337 if (normal_type_cache()->IsUndefined()) return -1;
4338 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4339 return cache->GetIndex(String::cast(name), code->flags());
4340 }
4341
4342 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004343 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01004344 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
4345 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00004346 }
4347 return -1;
4348}
4349
4350
Steve Block6ded16b2010-05-10 14:33:55 +01004351void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
4352 if (code->type() == NORMAL) {
4353 ASSERT(!normal_type_cache()->IsUndefined());
4354 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4355 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
4356 cache->RemoveByIndex(index);
4357 } else {
4358 FixedArray* array = default_cache();
4359 ASSERT(array->length() >= index && array->get(index)->IsCode());
4360 // Use null instead of undefined for deleted elements to distinguish
4361 // deleted elements from unused elements. This distinction is used
4362 // when looking up in the cache and when updating the cache.
4363 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
4364 array->set_null(index - 1); // Name.
4365 array->set_null(index); // Code.
4366 }
4367}
4368
4369
4370// The key in the code cache hash table consists of the property name and the
4371// code object. The actual match is on the name and the code flags. If a key
4372// is created using the flags and not a code object it can only be used for
4373// lookup not to create a new entry.
4374class CodeCacheHashTableKey : public HashTableKey {
4375 public:
4376 CodeCacheHashTableKey(String* name, Code::Flags flags)
4377 : name_(name), flags_(flags), code_(NULL) { }
4378
4379 CodeCacheHashTableKey(String* name, Code* code)
4380 : name_(name),
4381 flags_(code->flags()),
4382 code_(code) { }
4383
4384
4385 bool IsMatch(Object* other) {
4386 if (!other->IsFixedArray()) return false;
4387 FixedArray* pair = FixedArray::cast(other);
4388 String* name = String::cast(pair->get(0));
4389 Code::Flags flags = Code::cast(pair->get(1))->flags();
4390 if (flags != flags_) {
4391 return false;
4392 }
4393 return name_->Equals(name);
4394 }
4395
4396 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
4397 return name->Hash() ^ flags;
4398 }
4399
4400 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
4401
4402 uint32_t HashForObject(Object* obj) {
4403 FixedArray* pair = FixedArray::cast(obj);
4404 String* name = String::cast(pair->get(0));
4405 Code* code = Code::cast(pair->get(1));
4406 return NameFlagsHashHelper(name, code->flags());
4407 }
4408
John Reck59135872010-11-02 12:39:01 -07004409 MUST_USE_RESULT MaybeObject* AsObject() {
Steve Block6ded16b2010-05-10 14:33:55 +01004410 ASSERT(code_ != NULL);
John Reck59135872010-11-02 12:39:01 -07004411 Object* obj;
Ben Murdoch85b71792012-04-11 18:30:58 +01004412 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07004413 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4414 }
Steve Block6ded16b2010-05-10 14:33:55 +01004415 FixedArray* pair = FixedArray::cast(obj);
4416 pair->set(0, name_);
4417 pair->set(1, code_);
4418 return pair;
4419 }
4420
4421 private:
4422 String* name_;
4423 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004424 // TODO(jkummerow): We should be able to get by without this.
Steve Block6ded16b2010-05-10 14:33:55 +01004425 Code* code_;
4426};
4427
4428
4429Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
4430 CodeCacheHashTableKey key(name, flags);
4431 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01004432 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004433 return get(EntryToIndex(entry) + 1);
4434}
4435
4436
John Reck59135872010-11-02 12:39:01 -07004437MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004438 CodeCacheHashTableKey key(name, code);
John Reck59135872010-11-02 12:39:01 -07004439 Object* obj;
4440 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4441 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4442 }
Steve Block6ded16b2010-05-10 14:33:55 +01004443
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004444 // Don't use |this|, as the table might have grown.
Steve Block6ded16b2010-05-10 14:33:55 +01004445 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4446
4447 int entry = cache->FindInsertionEntry(key.Hash());
John Reck59135872010-11-02 12:39:01 -07004448 Object* k;
4449 { MaybeObject* maybe_k = key.AsObject();
4450 if (!maybe_k->ToObject(&k)) return maybe_k;
4451 }
Steve Block6ded16b2010-05-10 14:33:55 +01004452
4453 cache->set(EntryToIndex(entry), k);
4454 cache->set(EntryToIndex(entry) + 1, code);
4455 cache->ElementAdded();
4456 return cache;
4457}
4458
4459
4460int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
4461 CodeCacheHashTableKey key(name, flags);
4462 int entry = FindEntry(&key);
4463 return (entry == kNotFound) ? -1 : entry;
4464}
4465
4466
4467void CodeCacheHashTable::RemoveByIndex(int index) {
4468 ASSERT(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004469 Heap* heap = GetHeap();
Ben Murdoch85b71792012-04-11 18:30:58 +01004470 set(EntryToIndex(index), heap->null_value());
4471 set(EntryToIndex(index) + 1, heap->null_value());
Steve Block6ded16b2010-05-10 14:33:55 +01004472 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00004473}
4474
4475
Ben Murdoch85b71792012-04-11 18:30:58 +01004476MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004477 Code::Flags flags,
4478 Code* code) {
4479 // Initialize cache if necessary.
4480 if (cache()->IsUndefined()) {
4481 Object* result;
4482 { MaybeObject* maybe_result =
4483 PolymorphicCodeCacheHashTable::Allocate(
4484 PolymorphicCodeCacheHashTable::kInitialSize);
4485 if (!maybe_result->ToObject(&result)) return maybe_result;
4486 }
4487 set_cache(result);
4488 } else {
4489 // This entry shouldn't be contained in the cache yet.
4490 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
4491 ->Lookup(maps, flags)->IsUndefined());
4492 }
4493 PolymorphicCodeCacheHashTable* hash_table =
4494 PolymorphicCodeCacheHashTable::cast(cache());
4495 Object* new_cache;
4496 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
4497 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4498 }
4499 set_cache(new_cache);
4500 return this;
4501}
4502
4503
Ben Murdoch85b71792012-04-11 18:30:58 +01004504Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004505 if (!cache()->IsUndefined()) {
4506 PolymorphicCodeCacheHashTable* hash_table =
4507 PolymorphicCodeCacheHashTable::cast(cache());
Ben Murdoch85b71792012-04-11 18:30:58 +01004508 return hash_table->Lookup(maps, flags);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004509 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +01004510 return GetHeap()->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004511 }
4512}
4513
4514
4515// Despite their name, object of this class are not stored in the actual
4516// hash table; instead they're temporarily used for lookups. It is therefore
4517// safe to have a weak (non-owning) pointer to a MapList as a member field.
4518class PolymorphicCodeCacheHashTableKey : public HashTableKey {
4519 public:
4520 // Callers must ensure that |maps| outlives the newly constructed object.
Ben Murdoch85b71792012-04-11 18:30:58 +01004521 PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004522 : maps_(maps),
4523 code_flags_(code_flags) {}
4524
4525 bool IsMatch(Object* other) {
Ben Murdoch85b71792012-04-11 18:30:58 +01004526 MapList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004527 int other_flags;
4528 FromObject(other, &other_flags, &other_maps);
4529 if (code_flags_ != other_flags) return false;
4530 if (maps_->length() != other_maps.length()) return false;
4531 // Compare just the hashes first because it's faster.
4532 int this_hash = MapsHashHelper(maps_, code_flags_);
4533 int other_hash = MapsHashHelper(&other_maps, other_flags);
4534 if (this_hash != other_hash) return false;
4535
4536 // Full comparison: for each map in maps_, look for an equivalent map in
4537 // other_maps. This implementation is slow, but probably good enough for
4538 // now because the lists are short (<= 4 elements currently).
4539 for (int i = 0; i < maps_->length(); ++i) {
4540 bool match_found = false;
4541 for (int j = 0; j < other_maps.length(); ++j) {
Ben Murdoch85b71792012-04-11 18:30:58 +01004542 if (maps_->at(i)->EquivalentTo(other_maps.at(j))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004543 match_found = true;
4544 break;
4545 }
4546 }
4547 if (!match_found) return false;
4548 }
4549 return true;
4550 }
4551
Ben Murdoch85b71792012-04-11 18:30:58 +01004552 static uint32_t MapsHashHelper(MapList* maps, int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004553 uint32_t hash = code_flags;
4554 for (int i = 0; i < maps->length(); ++i) {
4555 hash ^= maps->at(i)->Hash();
4556 }
4557 return hash;
4558 }
4559
4560 uint32_t Hash() {
4561 return MapsHashHelper(maps_, code_flags_);
4562 }
4563
4564 uint32_t HashForObject(Object* obj) {
Ben Murdoch85b71792012-04-11 18:30:58 +01004565 MapList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004566 int other_flags;
4567 FromObject(obj, &other_flags, &other_maps);
4568 return MapsHashHelper(&other_maps, other_flags);
4569 }
4570
4571 MUST_USE_RESULT MaybeObject* AsObject() {
4572 Object* obj;
4573 // The maps in |maps_| must be copied to a newly allocated FixedArray,
4574 // both because the referenced MapList is short-lived, and because C++
4575 // objects can't be stored in the heap anyway.
4576 { MaybeObject* maybe_obj =
4577 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
4578 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4579 }
4580 FixedArray* list = FixedArray::cast(obj);
4581 list->set(0, Smi::FromInt(code_flags_));
4582 for (int i = 0; i < maps_->length(); ++i) {
Ben Murdoch85b71792012-04-11 18:30:58 +01004583 list->set(i + 1, maps_->at(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004584 }
4585 return list;
4586 }
4587
4588 private:
Ben Murdoch85b71792012-04-11 18:30:58 +01004589 static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004590 FixedArray* list = FixedArray::cast(obj);
4591 maps->Rewind(0);
4592 *code_flags = Smi::cast(list->get(0))->value();
4593 for (int i = 1; i < list->length(); ++i) {
Ben Murdoch85b71792012-04-11 18:30:58 +01004594 maps->Add(Map::cast(list->get(i)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004595 }
4596 return maps;
4597 }
4598
Ben Murdoch85b71792012-04-11 18:30:58 +01004599 MapList* maps_; // weak.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004600 int code_flags_;
4601 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
4602};
4603
4604
Ben Murdoch85b71792012-04-11 18:30:58 +01004605Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004606 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4607 int entry = FindEntry(&key);
4608 if (entry == kNotFound) return GetHeap()->undefined_value();
4609 return get(EntryToIndex(entry) + 1);
4610}
4611
4612
Ben Murdoch85b71792012-04-11 18:30:58 +01004613MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004614 int code_flags,
4615 Code* code) {
4616 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4617 Object* obj;
4618 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4619 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4620 }
4621 PolymorphicCodeCacheHashTable* cache =
4622 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
4623 int entry = cache->FindInsertionEntry(key.Hash());
4624 { MaybeObject* maybe_obj = key.AsObject();
4625 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4626 }
4627 cache->set(EntryToIndex(entry), obj);
4628 cache->set(EntryToIndex(entry) + 1, code);
4629 cache->ElementAdded();
4630 return cache;
4631}
4632
4633
John Reck59135872010-11-02 12:39:01 -07004634MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004635 ElementsAccessor* accessor = array->GetElementsAccessor();
4636 MaybeObject* maybe_result =
Ben Murdoch85b71792012-04-11 18:30:58 +01004637 accessor->AddElementsToFixedArray(array->elements(), this, array, array);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004638 FixedArray* result;
4639 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
4640#ifdef DEBUG
4641 if (FLAG_enable_slow_asserts) {
4642 for (int i = 0; i < result->length(); i++) {
4643 Object* current = result->get(i);
4644 ASSERT(current->IsNumber() || current->IsString());
Steve Blocka7e24c12009-10-30 11:49:00 +00004645 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004646 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004647#endif
4648 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00004649}
4650
4651
John Reck59135872010-11-02 12:39:01 -07004652MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004653 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
4654 MaybeObject* maybe_result =
Ben Murdoch85b71792012-04-11 18:30:58 +01004655 accessor->AddElementsToFixedArray(other, this, NULL, NULL);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004656 FixedArray* result;
4657 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
Ben Murdochf87a2032010-10-22 12:50:53 +01004658#ifdef DEBUG
4659 if (FLAG_enable_slow_asserts) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004660 for (int i = 0; i < result->length(); i++) {
4661 Object* current = result->get(i);
4662 ASSERT(current->IsNumber() || current->IsString());
Ben Murdochf87a2032010-10-22 12:50:53 +01004663 }
4664 }
4665#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004666 return result;
4667}
4668
4669
John Reck59135872010-11-02 12:39:01 -07004670MaybeObject* FixedArray::CopySize(int new_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01004671 Heap* heap = GetHeap();
4672 if (new_length == 0) return heap->empty_fixed_array();
John Reck59135872010-11-02 12:39:01 -07004673 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01004674 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
John Reck59135872010-11-02 12:39:01 -07004675 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4676 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004677 FixedArray* result = FixedArray::cast(obj);
4678 // Copy the content
Leon Clarke4515c472010-02-03 11:58:03 +00004679 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004680 int len = length();
4681 if (new_length < len) len = new_length;
Ben Murdoch85b71792012-04-11 18:30:58 +01004682 result->set_map(map());
Leon Clarke4515c472010-02-03 11:58:03 +00004683 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004684 for (int i = 0; i < len; i++) {
4685 result->set(i, get(i), mode);
4686 }
4687 return result;
4688}
4689
4690
4691void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Leon Clarke4515c472010-02-03 11:58:03 +00004692 AssertNoAllocation no_gc;
4693 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004694 for (int index = 0; index < len; index++) {
4695 dest->set(dest_pos+index, get(pos+index), mode);
4696 }
4697}
4698
4699
4700#ifdef DEBUG
4701bool FixedArray::IsEqualTo(FixedArray* other) {
4702 if (length() != other->length()) return false;
4703 for (int i = 0 ; i < length(); ++i) {
4704 if (get(i) != other->get(i)) return false;
4705 }
4706 return true;
4707}
4708#endif
4709
4710
John Reck59135872010-11-02 12:39:01 -07004711MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01004712 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004713 if (number_of_descriptors == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01004714 return heap->empty_descriptor_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00004715 }
4716 // Allocate the array of keys.
John Reck59135872010-11-02 12:39:01 -07004717 Object* array;
4718 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004719 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
John Reck59135872010-11-02 12:39:01 -07004720 if (!maybe_array->ToObject(&array)) return maybe_array;
4721 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004722 // Do not use DescriptorArray::cast on incomplete object.
4723 FixedArray* result = FixedArray::cast(array);
4724
4725 // Allocate the content array and set it in the descriptor array.
John Reck59135872010-11-02 12:39:01 -07004726 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004727 heap->AllocateFixedArray(number_of_descriptors << 1);
John Reck59135872010-11-02 12:39:01 -07004728 if (!maybe_array->ToObject(&array)) return maybe_array;
4729 }
Ben Murdoch257744e2011-11-30 15:57:28 +00004730 result->set(kBitField3StorageIndex, Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00004731 result->set(kContentArrayIndex, array);
4732 result->set(kEnumerationIndexIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00004733 Smi::FromInt(PropertyDetails::kInitialIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00004734 return result;
4735}
4736
4737
4738void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
Ben Murdoch85b71792012-04-11 18:30:58 +01004739 FixedArray* new_cache) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004740 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4741 if (HasEnumCache()) {
4742 FixedArray::cast(get(kEnumerationIndexIndex))->
4743 set(kEnumCacheBridgeCacheIndex, new_cache);
4744 } else {
4745 if (IsEmpty()) return; // Do nothing for empty descriptor array.
4746 FixedArray::cast(bridge_storage)->
4747 set(kEnumCacheBridgeCacheIndex, new_cache);
Ben Murdoch85b71792012-04-11 18:30:58 +01004748 fast_set(FixedArray::cast(bridge_storage),
4749 kEnumCacheBridgeEnumIndex,
4750 get(kEnumerationIndexIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00004751 set(kEnumerationIndexIndex, bridge_storage);
4752 }
4753}
4754
4755
John Reck59135872010-11-02 12:39:01 -07004756MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4757 TransitionFlag transition_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004758 // Transitions are only kept when inserting another transition.
4759 // This precondition is not required by this function's implementation, but
4760 // is currently required by the semantics of maps, so we check it.
4761 // Conversely, we filter after replacing, so replacing a transition and
4762 // removing all other transitions is not supported.
4763 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
Ben Murdoch85b71792012-04-11 18:30:58 +01004764 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
Steve Blocka7e24c12009-10-30 11:49:00 +00004765 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
4766
4767 // Ensure the key is a symbol.
Ben Murdoch85b71792012-04-11 18:30:58 +01004768 Object* result;
John Reck59135872010-11-02 12:39:01 -07004769 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
Ben Murdoch85b71792012-04-11 18:30:58 +01004770 if (!maybe_result->ToObject(&result)) return maybe_result;
John Reck59135872010-11-02 12:39:01 -07004771 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004772
Ben Murdoch85b71792012-04-11 18:30:58 +01004773 int transitions = 0;
4774 int null_descriptors = 0;
4775 if (remove_transitions) {
4776 for (int i = 0; i < number_of_descriptors(); i++) {
4777 if (IsTransition(i)) transitions++;
4778 if (IsNullDescriptor(i)) null_descriptors++;
4779 }
4780 } else {
4781 for (int i = 0; i < number_of_descriptors(); i++) {
4782 if (IsNullDescriptor(i)) null_descriptors++;
4783 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004784 }
Ben Murdoch85b71792012-04-11 18:30:58 +01004785 int new_size = number_of_descriptors() - transitions - null_descriptors;
Steve Blocka7e24c12009-10-30 11:49:00 +00004786
4787 // If key is in descriptor, we replace it in-place when filtering.
4788 // Count a null descriptor for key as inserted, not replaced.
4789 int index = Search(descriptor->GetKey());
Ben Murdoch85b71792012-04-11 18:30:58 +01004790 const bool inserting = (index == kNotFound);
4791 const bool replacing = !inserting;
Steve Blocka7e24c12009-10-30 11:49:00 +00004792 bool keep_enumeration_index = false;
Ben Murdoch85b71792012-04-11 18:30:58 +01004793 if (inserting) {
4794 ++new_size;
4795 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004796 if (replacing) {
4797 // We are replacing an existing descriptor. We keep the enumeration
4798 // index of a visible property.
4799 PropertyType t = PropertyDetails(GetDetails(index)).type();
4800 if (t == CONSTANT_FUNCTION ||
4801 t == FIELD ||
4802 t == CALLBACKS ||
4803 t == INTERCEPTOR) {
4804 keep_enumeration_index = true;
4805 } else if (remove_transitions) {
4806 // Replaced descriptor has been counted as removed if it is
4807 // a transition that will be replaced. Adjust count in this case.
4808 ++new_size;
4809 }
4810 }
John Reck59135872010-11-02 12:39:01 -07004811 { MaybeObject* maybe_result = Allocate(new_size);
Ben Murdoch85b71792012-04-11 18:30:58 +01004812 if (!maybe_result->ToObject(&result)) return maybe_result;
John Reck59135872010-11-02 12:39:01 -07004813 }
Ben Murdoch85b71792012-04-11 18:30:58 +01004814 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004815 // Set the enumeration index in the descriptors and set the enumeration index
4816 // in the result.
4817 int enumeration_index = NextEnumerationIndex();
Ben Murdoch85b71792012-04-11 18:30:58 +01004818 if (!descriptor->GetDetails().IsTransition()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004819 if (keep_enumeration_index) {
4820 descriptor->SetEnumerationIndex(
4821 PropertyDetails(GetDetails(index)).index());
4822 } else {
4823 descriptor->SetEnumerationIndex(enumeration_index);
4824 ++enumeration_index;
4825 }
4826 }
4827 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4828
4829 // Copy the descriptors, filtering out transitions and null descriptors,
4830 // and inserting or replacing a descriptor.
Ben Murdoch85b71792012-04-11 18:30:58 +01004831 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01004832 int from_index = 0;
Ben Murdoch85b71792012-04-11 18:30:58 +01004833 int to_index = 0;
4834
4835 for (; from_index < number_of_descriptors(); from_index++) {
4836 String* key = GetKey(from_index);
4837 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4838 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00004839 }
Ben Murdoch85b71792012-04-11 18:30:58 +01004840 if (IsNullDescriptor(from_index)) continue;
4841 if (remove_transitions && IsTransition(from_index)) continue;
4842 new_descriptors->CopyFrom(to_index++, this, from_index);
Steve Blocka7e24c12009-10-30 11:49:00 +00004843 }
Ben Murdoch85b71792012-04-11 18:30:58 +01004844
4845 new_descriptors->Set(to_index++, descriptor);
4846 if (replacing) from_index++;
4847
4848 for (; from_index < number_of_descriptors(); from_index++) {
4849 if (IsNullDescriptor(from_index)) continue;
4850 if (remove_transitions && IsTransition(from_index)) continue;
4851 new_descriptors->CopyFrom(to_index++, this, from_index);
4852 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004853
4854 ASSERT(to_index == new_descriptors->number_of_descriptors());
4855 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
4856
4857 return new_descriptors;
4858}
4859
4860
John Reck59135872010-11-02 12:39:01 -07004861MaybeObject* DescriptorArray::RemoveTransitions() {
Ben Murdoch85b71792012-04-11 18:30:58 +01004862 // Remove all transitions and null descriptors. Return a copy of the array
4863 // with all transitions removed, or a Failure object if the new array could
4864 // not be allocated.
4865
4866 // Compute the size of the map transition entries to be removed.
4867 int num_removed = 0;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01004868 for (int i = 0; i < number_of_descriptors(); i++) {
Ben Murdoch85b71792012-04-11 18:30:58 +01004869 if (!IsProperty(i)) num_removed++;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01004870 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004871
Ben Murdoch85b71792012-04-11 18:30:58 +01004872 // Allocate the new descriptor array.
4873 Object* result;
4874 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
4875 if (!maybe_result->ToObject(&result)) return maybe_result;
4876 }
4877 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4878
Steve Blocka7e24c12009-10-30 11:49:00 +00004879 // Copy the content.
4880 int next_descriptor = 0;
4881 for (int i = 0; i < number_of_descriptors(); i++) {
Ben Murdoch85b71792012-04-11 18:30:58 +01004882 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00004883 }
4884 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
4885
4886 return new_descriptors;
4887}
4888
4889
Ben Murdoch85b71792012-04-11 18:30:58 +01004890void DescriptorArray::SortUnchecked() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004891 // In-place heap sort.
4892 int len = number_of_descriptors();
4893
4894 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01004895 // Index of the last node with children
4896 const int max_parent_index = (len / 2) - 1;
4897 for (int i = max_parent_index; i >= 0; --i) {
4898 int parent_index = i;
4899 const uint32_t parent_hash = GetKey(i)->Hash();
4900 while (parent_index <= max_parent_index) {
4901 int child_index = 2 * parent_index + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00004902 uint32_t child_hash = GetKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01004903 if (child_index + 1 < len) {
4904 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4905 if (right_child_hash > child_hash) {
4906 child_index++;
4907 child_hash = right_child_hash;
4908 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004909 }
Steve Block6ded16b2010-05-10 14:33:55 +01004910 if (child_hash <= parent_hash) break;
Ben Murdoch85b71792012-04-11 18:30:58 +01004911 Swap(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01004912 // Now element at child_index could be < its children.
4913 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00004914 }
4915 }
4916
4917 // Extract elements and create sorted array.
4918 for (int i = len - 1; i > 0; --i) {
4919 // Put max element at the back of the array.
Ben Murdoch85b71792012-04-11 18:30:58 +01004920 Swap(0, i);
4921 // Sift down the new top element.
Steve Blocka7e24c12009-10-30 11:49:00 +00004922 int parent_index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01004923 const uint32_t parent_hash = GetKey(parent_index)->Hash();
4924 const int max_parent_index = (i / 2) - 1;
4925 while (parent_index <= max_parent_index) {
4926 int child_index = parent_index * 2 + 1;
4927 uint32_t child_hash = GetKey(child_index)->Hash();
4928 if (child_index + 1 < i) {
4929 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4930 if (right_child_hash > child_hash) {
4931 child_index++;
4932 child_hash = right_child_hash;
4933 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004934 }
Steve Block6ded16b2010-05-10 14:33:55 +01004935 if (child_hash <= parent_hash) break;
Ben Murdoch85b71792012-04-11 18:30:58 +01004936 Swap(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01004937 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00004938 }
4939 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004940}
Steve Blocka7e24c12009-10-30 11:49:00 +00004941
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004942
Ben Murdoch85b71792012-04-11 18:30:58 +01004943void DescriptorArray::Sort() {
4944 SortUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004945 SLOW_ASSERT(IsSortedNoDuplicates());
4946}
4947
4948
4949int DescriptorArray::BinarySearch(String* name, int low, int high) {
4950 uint32_t hash = name->Hash();
4951
4952 while (low <= high) {
4953 int mid = (low + high) / 2;
4954 String* mid_name = GetKey(mid);
4955 uint32_t mid_hash = mid_name->Hash();
4956
4957 if (mid_hash > hash) {
4958 high = mid - 1;
4959 continue;
4960 }
4961 if (mid_hash < hash) {
4962 low = mid + 1;
4963 continue;
4964 }
4965 // Found an element with the same hash-code.
4966 ASSERT(hash == mid_hash);
4967 // There might be more, so we find the first one and
4968 // check them all to see if we have a match.
4969 if (name == mid_name && !is_null_descriptor(mid)) return mid;
4970 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
4971 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
4972 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
4973 }
4974 break;
4975 }
4976 return kNotFound;
4977}
4978
4979
4980int DescriptorArray::LinearSearch(String* name, int len) {
4981 uint32_t hash = name->Hash();
4982 for (int number = 0; number < len; number++) {
4983 String* entry = GetKey(number);
4984 if ((entry->Hash() == hash) &&
4985 name->Equals(entry) &&
4986 !is_null_descriptor(number)) {
4987 return number;
4988 }
4989 }
4990 return kNotFound;
4991}
4992
4993
Ben Murdochb0fe1622011-05-05 13:52:32 +01004994MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
4995 PretenureFlag pretenure) {
4996 ASSERT(deopt_entry_count > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004997 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01004998 pretenure);
4999}
5000
5001
5002MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5003 PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01005004 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5005 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005006 pretenure);
5007}
5008
5009
Steve Blocka7e24c12009-10-30 11:49:00 +00005010#ifdef DEBUG
5011bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5012 if (IsEmpty()) return other->IsEmpty();
5013 if (other->IsEmpty()) return false;
5014 if (length() != other->length()) return false;
5015 for (int i = 0; i < length(); ++i) {
5016 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5017 }
5018 return GetContentArray()->IsEqualTo(other->GetContentArray());
5019}
5020#endif
5021
5022
Steve Blocka7e24c12009-10-30 11:49:00 +00005023bool String::LooksValid() {
Steve Block44f0eee2011-05-26 01:26:41 +01005024 if (!Isolate::Current()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00005025 return true;
5026}
5027
5028
Ben Murdoch85b71792012-04-11 18:30:58 +01005029int String::Utf8Length() {
5030 if (IsAsciiRepresentation()) return length();
5031 // Attempt to flatten before accessing the string. It probably
5032 // doesn't make Utf8Length faster, but it is very likely that
5033 // the string will be accessed later (for example by WriteUtf8)
5034 // so it's still a good idea.
5035 Heap* heap = GetHeap();
5036 TryFlatten();
5037 Access<StringInputBuffer> buffer(
5038 heap->isolate()->objects_string_input_buffer());
5039 buffer->Reset(0, this);
5040 int result = 0;
5041 while (buffer->has_more())
5042 result += unibrow::Utf8::Length(buffer->GetNext());
5043 return result;
5044}
5045
5046
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005047String::FlatContent String::GetFlatContent() {
Steve Blocka7e24c12009-10-30 11:49:00 +00005048 int length = this->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005049 StringShape shape(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00005050 String* string = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00005051 int offset = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005052 if (shape.representation_tag() == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005053 ConsString* cons = ConsString::cast(string);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005054 if (cons->second()->length() != 0) {
5055 return FlatContent();
5056 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005057 string = cons->first();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005058 shape = StringShape(string);
Steve Blocka7e24c12009-10-30 11:49:00 +00005059 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005060 if (shape.representation_tag() == kSlicedStringTag) {
5061 SlicedString* slice = SlicedString::cast(string);
5062 offset = slice->offset();
5063 string = slice->parent();
5064 shape = StringShape(string);
5065 ASSERT(shape.representation_tag() != kConsStringTag &&
5066 shape.representation_tag() != kSlicedStringTag);
Steve Blocka7e24c12009-10-30 11:49:00 +00005067 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005068 if (shape.encoding_tag() == kAsciiStringTag) {
5069 const char* start;
5070 if (shape.representation_tag() == kSeqStringTag) {
5071 start = SeqAsciiString::cast(string)->GetChars();
5072 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +01005073 start = ExternalAsciiString::cast(string)->resource()->data();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005074 }
5075 return FlatContent(Vector<const char>(start + offset, length));
5076 } else {
5077 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
5078 const uc16* start;
5079 if (shape.representation_tag() == kSeqStringTag) {
5080 start = SeqTwoByteString::cast(string)->GetChars();
5081 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +01005082 start = ExternalTwoByteString::cast(string)->resource()->data();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005083 }
5084 return FlatContent(Vector<const uc16>(start + offset, length));
5085 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005086}
5087
5088
Ben Murdoch589d6972011-11-30 16:04:58 +00005089SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5090 RobustnessFlag robust_flag,
5091 int offset,
5092 int length,
5093 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005094 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00005095 return SmartArrayPointer<char>(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00005096 }
Steve Block44f0eee2011-05-26 01:26:41 +01005097 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005098
5099 // Negative length means the to the end of the string.
5100 if (length < 0) length = kMaxInt - offset;
5101
5102 // Compute the size of the UTF-8 string. Start at the specified offset.
Steve Block44f0eee2011-05-26 01:26:41 +01005103 Access<StringInputBuffer> buffer(
5104 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005105 buffer->Reset(offset, this);
5106 int character_position = offset;
5107 int utf8_bytes = 0;
Ben Murdoch85b71792012-04-11 18:30:58 +01005108 while (buffer->has_more()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005109 uint16_t character = buffer->GetNext();
Ben Murdoch85b71792012-04-11 18:30:58 +01005110 if (character_position < offset + length) {
5111 utf8_bytes += unibrow::Utf8::Length(character);
5112 }
5113 character_position++;
Steve Blocka7e24c12009-10-30 11:49:00 +00005114 }
5115
5116 if (length_return) {
5117 *length_return = utf8_bytes;
5118 }
5119
5120 char* result = NewArray<char>(utf8_bytes + 1);
5121
5122 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
5123 buffer->Rewind();
5124 buffer->Seek(offset);
5125 character_position = offset;
5126 int utf8_byte_position = 0;
Ben Murdoch85b71792012-04-11 18:30:58 +01005127 while (buffer->has_more()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005128 uint16_t character = buffer->GetNext();
Ben Murdoch85b71792012-04-11 18:30:58 +01005129 if (character_position < offset + length) {
5130 if (allow_nulls == DISALLOW_NULLS && character == 0) {
5131 character = ' ';
5132 }
5133 utf8_byte_position +=
5134 unibrow::Utf8::Encode(result + utf8_byte_position, character);
Steve Blocka7e24c12009-10-30 11:49:00 +00005135 }
Ben Murdoch85b71792012-04-11 18:30:58 +01005136 character_position++;
Steve Blocka7e24c12009-10-30 11:49:00 +00005137 }
5138 result[utf8_byte_position] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00005139 return SmartArrayPointer<char>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005140}
5141
5142
Ben Murdoch589d6972011-11-30 16:04:58 +00005143SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5144 RobustnessFlag robust_flag,
5145 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005146 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
5147}
5148
5149
5150const uc16* String::GetTwoByteData() {
5151 return GetTwoByteData(0);
5152}
5153
5154
5155const uc16* String::GetTwoByteData(unsigned start) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005156 ASSERT(!IsAsciiRepresentationUnderneath());
Steve Blocka7e24c12009-10-30 11:49:00 +00005157 switch (StringShape(this).representation_tag()) {
5158 case kSeqStringTag:
5159 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
5160 case kExternalStringTag:
5161 return ExternalTwoByteString::cast(this)->
5162 ExternalTwoByteStringGetData(start);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005163 case kSlicedStringTag: {
5164 SlicedString* slice = SlicedString::cast(this);
5165 return slice->parent()->GetTwoByteData(start + slice->offset());
5166 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005167 case kConsStringTag:
5168 UNREACHABLE();
5169 return NULL;
5170 }
5171 UNREACHABLE();
5172 return NULL;
5173}
5174
5175
Ben Murdoch589d6972011-11-30 16:04:58 +00005176SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005177 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00005178 return SmartArrayPointer<uc16>();
Steve Blocka7e24c12009-10-30 11:49:00 +00005179 }
Steve Block44f0eee2011-05-26 01:26:41 +01005180 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005181
Steve Block44f0eee2011-05-26 01:26:41 +01005182 Access<StringInputBuffer> buffer(
5183 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005184 buffer->Reset(this);
5185
5186 uc16* result = NewArray<uc16>(length() + 1);
5187
5188 int i = 0;
5189 while (buffer->has_more()) {
5190 uint16_t character = buffer->GetNext();
5191 result[i++] = character;
5192 }
5193 result[i] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00005194 return SmartArrayPointer<uc16>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005195}
5196
5197
5198const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
5199 return reinterpret_cast<uc16*>(
5200 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
5201}
5202
5203
5204void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5205 unsigned* offset_ptr,
5206 unsigned max_chars) {
5207 unsigned chars_read = 0;
5208 unsigned offset = *offset_ptr;
5209 while (chars_read < max_chars) {
5210 uint16_t c = *reinterpret_cast<uint16_t*>(
5211 reinterpret_cast<char*>(this) -
5212 kHeapObjectTag + kHeaderSize + offset * kShortSize);
5213 if (c <= kMaxAsciiCharCode) {
5214 // Fast case for ASCII characters. Cursor is an input output argument.
5215 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5216 rbb->util_buffer,
5217 rbb->capacity,
5218 rbb->cursor)) {
5219 break;
5220 }
5221 } else {
5222 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5223 rbb->util_buffer,
5224 rbb->capacity,
5225 rbb->cursor)) {
5226 break;
5227 }
5228 }
5229 offset++;
5230 chars_read++;
5231 }
5232 *offset_ptr = offset;
5233 rbb->remaining += chars_read;
5234}
5235
5236
5237const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
5238 unsigned* remaining,
5239 unsigned* offset_ptr,
5240 unsigned max_chars) {
5241 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
5242 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
5243 *remaining = max_chars;
5244 *offset_ptr += max_chars;
5245 return b;
5246}
5247
5248
5249// This will iterate unless the block of string data spans two 'halves' of
5250// a ConsString, in which case it will recurse. Since the block of string
5251// data to be read has a maximum size this limits the maximum recursion
5252// depth to something sane. Since C++ does not have tail call recursion
5253// elimination, the iteration must be explicit. Since this is not an
5254// -IntoBuffer method it can delegate to one of the efficient
5255// *AsciiStringReadBlock routines.
5256const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
5257 unsigned* offset_ptr,
5258 unsigned max_chars) {
5259 ConsString* current = this;
5260 unsigned offset = *offset_ptr;
5261 int offset_correction = 0;
5262
5263 while (true) {
5264 String* left = current->first();
5265 unsigned left_length = (unsigned)left->length();
5266 if (left_length > offset &&
5267 (max_chars <= left_length - offset ||
5268 (rbb->capacity <= left_length - offset &&
5269 (max_chars = left_length - offset, true)))) { // comma operator!
5270 // Left hand side only - iterate unless we have reached the bottom of
5271 // the cons tree. The assignment on the left of the comma operator is
5272 // in order to make use of the fact that the -IntoBuffer routines can
5273 // produce at most 'capacity' characters. This enables us to postpone
5274 // the point where we switch to the -IntoBuffer routines (below) in order
5275 // to maximize the chances of delegating a big chunk of work to the
5276 // efficient *AsciiStringReadBlock routines.
5277 if (StringShape(left).IsCons()) {
5278 current = ConsString::cast(left);
5279 continue;
5280 } else {
5281 const unibrow::byte* answer =
5282 String::ReadBlock(left, rbb, &offset, max_chars);
5283 *offset_ptr = offset + offset_correction;
5284 return answer;
5285 }
5286 } else if (left_length <= offset) {
5287 // Right hand side only - iterate unless we have reached the bottom of
5288 // the cons tree.
5289 String* right = current->second();
5290 offset -= left_length;
5291 offset_correction += left_length;
5292 if (StringShape(right).IsCons()) {
5293 current = ConsString::cast(right);
5294 continue;
5295 } else {
5296 const unibrow::byte* answer =
5297 String::ReadBlock(right, rbb, &offset, max_chars);
5298 *offset_ptr = offset + offset_correction;
5299 return answer;
5300 }
5301 } else {
5302 // The block to be read spans two sides of the ConsString, so we call the
5303 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
5304 // are able to assemble data from several part strings because they use
5305 // the util_buffer to store their data and never return direct pointers
5306 // to their storage. We don't try to read more than the buffer capacity
5307 // here or we can get too much recursion.
5308 ASSERT(rbb->remaining == 0);
5309 ASSERT(rbb->cursor == 0);
5310 current->ConsStringReadBlockIntoBuffer(
5311 rbb,
5312 &offset,
5313 max_chars > rbb->capacity ? rbb->capacity : max_chars);
5314 *offset_ptr = offset + offset_correction;
5315 return rbb->util_buffer;
5316 }
5317 }
5318}
5319
5320
Ben Murdoch85b71792012-04-11 18:30:58 +01005321uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
5322 ASSERT(index >= 0 && index < length());
5323 return resource()->data()[index];
5324}
5325
5326
Steve Blocka7e24c12009-10-30 11:49:00 +00005327const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
5328 unsigned* remaining,
5329 unsigned* offset_ptr,
5330 unsigned max_chars) {
5331 // Cast const char* to unibrow::byte* (signedness difference).
5332 const unibrow::byte* b =
Ben Murdoch85b71792012-04-11 18:30:58 +01005333 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
Steve Blocka7e24c12009-10-30 11:49:00 +00005334 *remaining = max_chars;
5335 *offset_ptr += max_chars;
5336 return b;
5337}
5338
5339
Ben Murdoch85b71792012-04-11 18:30:58 +01005340const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
5341 unsigned start) {
5342 return resource()->data() + start;
5343}
5344
5345
5346uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
5347 ASSERT(index >= 0 && index < length());
5348 return resource()->data()[index];
5349}
5350
5351
Steve Blocka7e24c12009-10-30 11:49:00 +00005352void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
5353 ReadBlockBuffer* rbb,
5354 unsigned* offset_ptr,
5355 unsigned max_chars) {
5356 unsigned chars_read = 0;
5357 unsigned offset = *offset_ptr;
Ben Murdoch85b71792012-04-11 18:30:58 +01005358 const uint16_t* data = resource()->data();
Steve Blocka7e24c12009-10-30 11:49:00 +00005359 while (chars_read < max_chars) {
5360 uint16_t c = data[offset];
5361 if (c <= kMaxAsciiCharCode) {
5362 // Fast case for ASCII characters. Cursor is an input output argument.
5363 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5364 rbb->util_buffer,
5365 rbb->capacity,
5366 rbb->cursor))
5367 break;
5368 } else {
5369 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5370 rbb->util_buffer,
5371 rbb->capacity,
5372 rbb->cursor))
5373 break;
5374 }
5375 offset++;
5376 chars_read++;
5377 }
5378 *offset_ptr = offset;
5379 rbb->remaining += chars_read;
5380}
5381
5382
5383void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5384 unsigned* offset_ptr,
5385 unsigned max_chars) {
5386 unsigned capacity = rbb->capacity - rbb->cursor;
5387 if (max_chars > capacity) max_chars = capacity;
5388 memcpy(rbb->util_buffer + rbb->cursor,
5389 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
5390 *offset_ptr * kCharSize,
5391 max_chars);
5392 rbb->remaining += max_chars;
5393 *offset_ptr += max_chars;
5394 rbb->cursor += max_chars;
5395}
5396
5397
5398void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
5399 ReadBlockBuffer* rbb,
5400 unsigned* offset_ptr,
5401 unsigned max_chars) {
5402 unsigned capacity = rbb->capacity - rbb->cursor;
5403 if (max_chars > capacity) max_chars = capacity;
Ben Murdoch85b71792012-04-11 18:30:58 +01005404 memcpy(rbb->util_buffer + rbb->cursor,
5405 resource()->data() + *offset_ptr,
5406 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005407 rbb->remaining += max_chars;
5408 *offset_ptr += max_chars;
5409 rbb->cursor += max_chars;
5410}
5411
5412
5413// This method determines the type of string involved and then copies
5414// a whole chunk of characters into a buffer, or returns a pointer to a buffer
5415// where they can be found. The pointer is not necessarily valid across a GC
5416// (see AsciiStringReadBlock).
5417const unibrow::byte* String::ReadBlock(String* input,
5418 ReadBlockBuffer* rbb,
5419 unsigned* offset_ptr,
5420 unsigned max_chars) {
5421 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
5422 if (max_chars == 0) {
5423 rbb->remaining = 0;
5424 return NULL;
5425 }
5426 switch (StringShape(input).representation_tag()) {
5427 case kSeqStringTag:
5428 if (input->IsAsciiRepresentation()) {
5429 SeqAsciiString* str = SeqAsciiString::cast(input);
5430 return str->SeqAsciiStringReadBlock(&rbb->remaining,
5431 offset_ptr,
5432 max_chars);
5433 } else {
5434 SeqTwoByteString* str = SeqTwoByteString::cast(input);
5435 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5436 offset_ptr,
5437 max_chars);
5438 return rbb->util_buffer;
5439 }
5440 case kConsStringTag:
5441 return ConsString::cast(input)->ConsStringReadBlock(rbb,
5442 offset_ptr,
5443 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005444 case kExternalStringTag:
5445 if (input->IsAsciiRepresentation()) {
5446 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
5447 &rbb->remaining,
5448 offset_ptr,
5449 max_chars);
5450 } else {
5451 ExternalTwoByteString::cast(input)->
5452 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5453 offset_ptr,
5454 max_chars);
5455 return rbb->util_buffer;
5456 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005457 case kSlicedStringTag:
5458 return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
5459 offset_ptr,
5460 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005461 default:
5462 break;
5463 }
5464
5465 UNREACHABLE();
5466 return 0;
5467}
5468
5469
Steve Blocka7e24c12009-10-30 11:49:00 +00005470void Relocatable::PostGarbageCollectionProcessing() {
Steve Block44f0eee2011-05-26 01:26:41 +01005471 Isolate* isolate = Isolate::Current();
5472 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00005473 while (current != NULL) {
5474 current->PostGarbageCollection();
5475 current = current->prev_;
5476 }
5477}
5478
5479
5480// Reserve space for statics needing saving and restoring.
5481int Relocatable::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +01005482 return sizeof(Isolate::Current()->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00005483}
5484
5485
5486// Archive statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00005487char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01005488 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
5489 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00005490 return to + ArchiveSpacePerThread();
5491}
5492
5493
5494// Restore statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00005495char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01005496 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00005497 return from + ArchiveSpacePerThread();
5498}
5499
5500
5501char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
5502 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
5503 Iterate(v, top);
5504 return thread_storage + ArchiveSpacePerThread();
5505}
5506
5507
5508void Relocatable::Iterate(ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01005509 Isolate* isolate = Isolate::Current();
5510 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00005511}
5512
5513
5514void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
5515 Relocatable* current = top;
5516 while (current != NULL) {
5517 current->IterateInstance(v);
5518 current = current->prev_;
5519 }
5520}
5521
5522
Steve Block44f0eee2011-05-26 01:26:41 +01005523FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
5524 : Relocatable(isolate),
5525 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00005526 length_(str->length()) {
5527 PostGarbageCollection();
5528}
5529
5530
Steve Block44f0eee2011-05-26 01:26:41 +01005531FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
5532 : Relocatable(isolate),
5533 str_(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00005534 is_ascii_(true),
5535 length_(input.length()),
5536 start_(input.start()) { }
5537
5538
5539void FlatStringReader::PostGarbageCollection() {
5540 if (str_ == NULL) return;
5541 Handle<String> str(str_);
5542 ASSERT(str->IsFlat());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005543 String::FlatContent content = str->GetFlatContent();
5544 ASSERT(content.IsFlat());
5545 is_ascii_ = content.IsAscii();
Steve Blocka7e24c12009-10-30 11:49:00 +00005546 if (is_ascii_) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005547 start_ = content.ToAsciiVector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00005548 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005549 start_ = content.ToUC16Vector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00005550 }
5551}
5552
5553
5554void StringInputBuffer::Seek(unsigned pos) {
5555 Reset(pos, input_);
5556}
5557
5558
5559void SafeStringInputBuffer::Seek(unsigned pos) {
5560 Reset(pos, input_);
5561}
5562
5563
5564// This method determines the type of string involved and then copies
5565// a whole chunk of characters into a buffer. It can be used with strings
5566// that have been glued together to form a ConsString and which must cooperate
5567// to fill up a buffer.
5568void String::ReadBlockIntoBuffer(String* input,
5569 ReadBlockBuffer* rbb,
5570 unsigned* offset_ptr,
5571 unsigned max_chars) {
5572 ASSERT(*offset_ptr <= (unsigned)input->length());
5573 if (max_chars == 0) return;
5574
5575 switch (StringShape(input).representation_tag()) {
5576 case kSeqStringTag:
5577 if (input->IsAsciiRepresentation()) {
5578 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
5579 offset_ptr,
5580 max_chars);
5581 return;
5582 } else {
5583 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5584 offset_ptr,
5585 max_chars);
5586 return;
5587 }
5588 case kConsStringTag:
5589 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5590 offset_ptr,
5591 max_chars);
5592 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005593 case kExternalStringTag:
5594 if (input->IsAsciiRepresentation()) {
Steve Blockd0582a62009-12-15 09:54:21 +00005595 ExternalAsciiString::cast(input)->
5596 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5597 } else {
5598 ExternalTwoByteString::cast(input)->
5599 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5600 offset_ptr,
5601 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005602 }
5603 return;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005604 case kSlicedStringTag:
5605 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
5606 offset_ptr,
5607 max_chars);
5608 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005609 default:
5610 break;
5611 }
5612
5613 UNREACHABLE();
5614 return;
5615}
5616
5617
5618const unibrow::byte* String::ReadBlock(String* input,
5619 unibrow::byte* util_buffer,
5620 unsigned capacity,
5621 unsigned* remaining,
5622 unsigned* offset_ptr) {
5623 ASSERT(*offset_ptr <= (unsigned)input->length());
5624 unsigned chars = input->length() - *offset_ptr;
5625 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5626 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
5627 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5628 *remaining = rbb.remaining;
5629 return answer;
5630}
5631
5632
5633const unibrow::byte* String::ReadBlock(String** raw_input,
5634 unibrow::byte* util_buffer,
5635 unsigned capacity,
5636 unsigned* remaining,
5637 unsigned* offset_ptr) {
5638 Handle<String> input(raw_input);
5639 ASSERT(*offset_ptr <= (unsigned)input->length());
5640 unsigned chars = input->length() - *offset_ptr;
5641 if (chars > capacity) chars = capacity;
5642 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5643 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
5644 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5645 *remaining = rbb.remaining;
5646 return rbb.util_buffer;
5647}
5648
5649
5650// This will iterate unless the block of string data spans two 'halves' of
5651// a ConsString, in which case it will recurse. Since the block of string
5652// data to be read has a maximum size this limits the maximum recursion
5653// depth to something sane. Since C++ does not have tail call recursion
5654// elimination, the iteration must be explicit.
5655void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5656 unsigned* offset_ptr,
5657 unsigned max_chars) {
5658 ConsString* current = this;
5659 unsigned offset = *offset_ptr;
5660 int offset_correction = 0;
5661
5662 while (true) {
5663 String* left = current->first();
5664 unsigned left_length = (unsigned)left->length();
5665 if (left_length > offset &&
5666 max_chars <= left_length - offset) {
5667 // Left hand side only - iterate unless we have reached the bottom of
5668 // the cons tree.
5669 if (StringShape(left).IsCons()) {
5670 current = ConsString::cast(left);
5671 continue;
5672 } else {
5673 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5674 *offset_ptr = offset + offset_correction;
5675 return;
5676 }
5677 } else if (left_length <= offset) {
5678 // Right hand side only - iterate unless we have reached the bottom of
5679 // the cons tree.
5680 offset -= left_length;
5681 offset_correction += left_length;
5682 String* right = current->second();
5683 if (StringShape(right).IsCons()) {
5684 current = ConsString::cast(right);
5685 continue;
5686 } else {
5687 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5688 *offset_ptr = offset + offset_correction;
5689 return;
5690 }
5691 } else {
5692 // The block to be read spans two sides of the ConsString, so we recurse.
5693 // First recurse on the left.
5694 max_chars -= left_length - offset;
5695 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5696 // We may have reached the max or there may not have been enough space
5697 // in the buffer for the characters in the left hand side.
5698 if (offset == left_length) {
5699 // Recurse on the right.
5700 String* right = String::cast(current->second());
5701 offset -= left_length;
5702 offset_correction += left_length;
5703 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5704 }
5705 *offset_ptr = offset + offset_correction;
5706 return;
5707 }
5708 }
5709}
5710
5711
Steve Blocka7e24c12009-10-30 11:49:00 +00005712uint16_t ConsString::ConsStringGet(int index) {
5713 ASSERT(index >= 0 && index < this->length());
5714
5715 // Check for a flattened cons string
5716 if (second()->length() == 0) {
5717 String* left = first();
5718 return left->Get(index);
5719 }
5720
5721 String* string = String::cast(this);
5722
5723 while (true) {
5724 if (StringShape(string).IsCons()) {
5725 ConsString* cons_string = ConsString::cast(string);
5726 String* left = cons_string->first();
5727 if (left->length() > index) {
5728 string = left;
5729 } else {
5730 index -= left->length();
5731 string = cons_string->second();
5732 }
5733 } else {
5734 return string->Get(index);
5735 }
5736 }
5737
5738 UNREACHABLE();
5739 return 0;
5740}
5741
5742
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005743uint16_t SlicedString::SlicedStringGet(int index) {
5744 return parent()->Get(offset() + index);
5745}
5746
5747
5748const unibrow::byte* SlicedString::SlicedStringReadBlock(
5749 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
5750 unsigned offset = this->offset();
5751 *offset_ptr += offset;
5752 const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
5753 buffer, offset_ptr, chars);
5754 *offset_ptr -= offset;
5755 return answer;
5756}
5757
5758
5759void SlicedString::SlicedStringReadBlockIntoBuffer(
5760 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
5761 unsigned offset = this->offset();
5762 *offset_ptr += offset;
5763 String::ReadBlockIntoBuffer(String::cast(parent()),
5764 buffer, offset_ptr, chars);
5765 *offset_ptr -= offset;
5766}
5767
Steve Blocka7e24c12009-10-30 11:49:00 +00005768template <typename sinkchar>
5769void String::WriteToFlat(String* src,
5770 sinkchar* sink,
5771 int f,
5772 int t) {
5773 String* source = src;
5774 int from = f;
5775 int to = t;
5776 while (true) {
5777 ASSERT(0 <= from && from <= to && to <= source->length());
5778 switch (StringShape(source).full_representation_tag()) {
5779 case kAsciiStringTag | kExternalStringTag: {
5780 CopyChars(sink,
Ben Murdoch85b71792012-04-11 18:30:58 +01005781 ExternalAsciiString::cast(source)->resource()->data() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +00005782 to - from);
5783 return;
5784 }
5785 case kTwoByteStringTag | kExternalStringTag: {
5786 const uc16* data =
Ben Murdoch85b71792012-04-11 18:30:58 +01005787 ExternalTwoByteString::cast(source)->resource()->data();
Steve Blocka7e24c12009-10-30 11:49:00 +00005788 CopyChars(sink,
5789 data + from,
5790 to - from);
5791 return;
5792 }
5793 case kAsciiStringTag | kSeqStringTag: {
5794 CopyChars(sink,
5795 SeqAsciiString::cast(source)->GetChars() + from,
5796 to - from);
5797 return;
5798 }
5799 case kTwoByteStringTag | kSeqStringTag: {
5800 CopyChars(sink,
5801 SeqTwoByteString::cast(source)->GetChars() + from,
5802 to - from);
5803 return;
5804 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005805 case kAsciiStringTag | kConsStringTag:
5806 case kTwoByteStringTag | kConsStringTag: {
5807 ConsString* cons_string = ConsString::cast(source);
5808 String* first = cons_string->first();
5809 int boundary = first->length();
5810 if (to - boundary >= boundary - from) {
5811 // Right hand side is longer. Recurse over left.
5812 if (from < boundary) {
5813 WriteToFlat(first, sink, from, boundary);
5814 sink += boundary - from;
5815 from = 0;
5816 } else {
5817 from -= boundary;
5818 }
5819 to -= boundary;
5820 source = cons_string->second();
5821 } else {
5822 // Left hand side is longer. Recurse over right.
5823 if (to > boundary) {
5824 String* second = cons_string->second();
Ben Murdoch85b71792012-04-11 18:30:58 +01005825 WriteToFlat(second,
5826 sink + boundary - from,
5827 0,
Steve Blocka7e24c12009-10-30 11:49:00 +00005828 to - boundary);
5829 to = boundary;
5830 }
5831 source = first;
5832 }
5833 break;
5834 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005835 case kAsciiStringTag | kSlicedStringTag:
5836 case kTwoByteStringTag | kSlicedStringTag: {
5837 SlicedString* slice = SlicedString::cast(source);
5838 unsigned offset = slice->offset();
5839 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
5840 return;
5841 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005842 }
5843 }
5844}
5845
5846
Steve Blocka7e24c12009-10-30 11:49:00 +00005847template <typename IteratorA, typename IteratorB>
5848static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5849 // General slow case check. We know that the ia and ib iterators
5850 // have the same length.
5851 while (ia->has_more()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01005852 uc32 ca = ia->GetNext();
5853 uc32 cb = ib->GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00005854 if (ca != cb)
5855 return false;
5856 }
5857 return true;
5858}
5859
5860
5861// Compares the contents of two strings by reading and comparing
5862// int-sized blocks of characters.
5863template <typename Char>
5864static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5865 int length = a.length();
5866 ASSERT_EQ(length, b.length());
5867 const Char* pa = a.start();
5868 const Char* pb = b.start();
5869 int i = 0;
5870#ifndef V8_HOST_CAN_READ_UNALIGNED
5871 // If this architecture isn't comfortable reading unaligned ints
5872 // then we have to check that the strings are aligned before
5873 // comparing them blockwise.
5874 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5875 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5876 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
5877 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
5878#endif
5879 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5880 int endpoint = length - kStepSize;
5881 // Compare blocks until we reach near the end of the string.
5882 for (; i <= endpoint; i += kStepSize) {
5883 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5884 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5885 if (wa != wb) {
5886 return false;
5887 }
5888 }
5889#ifndef V8_HOST_CAN_READ_UNALIGNED
5890 }
5891#endif
5892 // Compare the remaining characters that didn't fit into a block.
5893 for (; i < length; i++) {
5894 if (a[i] != b[i]) {
5895 return false;
5896 }
5897 }
5898 return true;
5899}
5900
5901
Steve Blocka7e24c12009-10-30 11:49:00 +00005902template <typename IteratorA>
Steve Block44f0eee2011-05-26 01:26:41 +01005903static inline bool CompareStringContentsPartial(Isolate* isolate,
5904 IteratorA* ia,
5905 String* b) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005906 String::FlatContent content = b->GetFlatContent();
5907 if (content.IsFlat()) {
5908 if (content.IsAscii()) {
5909 VectorIterator<char> ib(content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005910 return CompareStringContents(ia, &ib);
5911 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005912 VectorIterator<uc16> ib(content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005913 return CompareStringContents(ia, &ib);
5914 }
5915 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005916 isolate->objects_string_compare_buffer_b()->Reset(0, b);
5917 return CompareStringContents(ia,
5918 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005919 }
5920}
5921
5922
Steve Blocka7e24c12009-10-30 11:49:00 +00005923bool String::SlowEquals(String* other) {
5924 // Fast check: negative check with lengths.
5925 int len = length();
5926 if (len != other->length()) return false;
5927 if (len == 0) return true;
5928
5929 // Fast check: if hash code is computed for both strings
5930 // a fast negative check can be performed.
5931 if (HasHashCode() && other->HasHashCode()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00005932#ifdef DEBUG
5933 if (FLAG_enable_slow_asserts) {
5934 if (Hash() != other->Hash()) {
5935 bool found_difference = false;
5936 for (int i = 0; i < len; i++) {
5937 if (Get(i) != other->Get(i)) {
5938 found_difference = true;
5939 break;
5940 }
5941 }
5942 ASSERT(found_difference);
5943 }
5944 }
5945#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00005946 if (Hash() != other->Hash()) return false;
5947 }
5948
Leon Clarkef7060e22010-06-03 12:02:55 +01005949 // We know the strings are both non-empty. Compare the first chars
5950 // before we try to flatten the strings.
5951 if (this->Get(0) != other->Get(0)) return false;
5952
5953 String* lhs = this->TryFlattenGetString();
5954 String* rhs = other->TryFlattenGetString();
5955
5956 if (StringShape(lhs).IsSequentialAscii() &&
5957 StringShape(rhs).IsSequentialAscii()) {
5958 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
5959 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00005960 return CompareRawStringContents(Vector<const char>(str1, len),
5961 Vector<const char>(str2, len));
5962 }
5963
Steve Block44f0eee2011-05-26 01:26:41 +01005964 Isolate* isolate = GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005965 String::FlatContent lhs_content = lhs->GetFlatContent();
5966 String::FlatContent rhs_content = rhs->GetFlatContent();
5967 if (lhs_content.IsFlat()) {
5968 if (lhs_content.IsAscii()) {
5969 Vector<const char> vec1 = lhs_content.ToAsciiVector();
5970 if (rhs_content.IsFlat()) {
5971 if (rhs_content.IsAscii()) {
5972 Vector<const char> vec2 = rhs_content.ToAsciiVector();
Steve Blocka7e24c12009-10-30 11:49:00 +00005973 return CompareRawStringContents(vec1, vec2);
5974 } else {
5975 VectorIterator<char> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005976 VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005977 return CompareStringContents(&buf1, &ib);
5978 }
5979 } else {
5980 VectorIterator<char> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005981 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5982 return CompareStringContents(&buf1,
5983 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005984 }
5985 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005986 Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
5987 if (rhs_content.IsFlat()) {
5988 if (rhs_content.IsAscii()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005989 VectorIterator<uc16> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005990 VectorIterator<char> ib(rhs_content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005991 return CompareStringContents(&buf1, &ib);
5992 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005993 Vector<const uc16> vec2(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005994 return CompareRawStringContents(vec1, vec2);
5995 }
5996 } else {
5997 VectorIterator<uc16> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005998 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5999 return CompareStringContents(&buf1,
6000 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006001 }
6002 }
6003 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006004 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
6005 return CompareStringContentsPartial(isolate,
6006 isolate->objects_string_compare_buffer_a(), rhs);
Steve Blocka7e24c12009-10-30 11:49:00 +00006007 }
6008}
6009
6010
6011bool String::MarkAsUndetectable() {
6012 if (StringShape(this).IsSymbol()) return false;
6013
6014 Map* map = this->map();
Ben Murdoch85b71792012-04-11 18:30:58 +01006015 Heap* heap = map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01006016 if (map == heap->string_map()) {
6017 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006018 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01006019 } else if (map == heap->ascii_string_map()) {
6020 this->set_map(heap->undetectable_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006021 return true;
6022 }
6023 // Rest cannot be marked as undetectable
6024 return false;
6025}
6026
6027
6028bool String::IsEqualTo(Vector<const char> str) {
Steve Block44f0eee2011-05-26 01:26:41 +01006029 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006030 int slen = length();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006031 Access<UnicodeCache::Utf8Decoder>
6032 decoder(isolate->unicode_cache()->utf8_decoder());
Steve Blocka7e24c12009-10-30 11:49:00 +00006033 decoder->Reset(str.start(), str.length());
6034 int i;
6035 for (i = 0; i < slen && decoder->has_more(); i++) {
Ben Murdoch85b71792012-04-11 18:30:58 +01006036 uc32 r = decoder->GetNext();
6037 if (Get(i) != r) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00006038 }
6039 return i == slen && !decoder->has_more();
6040}
6041
6042
Steve Block9fac8402011-05-12 15:51:54 +01006043bool String::IsAsciiEqualTo(Vector<const char> str) {
6044 int slen = length();
6045 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006046 FlatContent content = GetFlatContent();
6047 if (content.IsAscii()) {
6048 return CompareChars(content.ToAsciiVector().start(),
6049 str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006050 }
6051 for (int i = 0; i < slen; i++) {
6052 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +01006053 }
6054 return true;
6055}
6056
6057
6058bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
6059 int slen = length();
6060 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006061 FlatContent content = GetFlatContent();
6062 if (content.IsTwoByte()) {
6063 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006064 }
Steve Block9fac8402011-05-12 15:51:54 +01006065 for (int i = 0; i < slen; i++) {
6066 if (Get(i) != str[i]) return false;
6067 }
6068 return true;
6069}
6070
6071
Steve Blocka7e24c12009-10-30 11:49:00 +00006072uint32_t String::ComputeAndSetHash() {
6073 // Should only be called if hash code has not yet been computed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006074 ASSERT(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00006075
Steve Block6ded16b2010-05-10 14:33:55 +01006076 const int len = length();
6077
Steve Blocka7e24c12009-10-30 11:49:00 +00006078 // Compute the hash code.
Steve Block6ded16b2010-05-10 14:33:55 +01006079 uint32_t field = 0;
6080 if (StringShape(this).IsSequentialAscii()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00006081 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(),
6082 len,
6083 GetHeap()->HashSeed());
Steve Block6ded16b2010-05-10 14:33:55 +01006084 } else if (StringShape(this).IsSequentialTwoByte()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00006085 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(),
6086 len,
6087 GetHeap()->HashSeed());
Steve Block6ded16b2010-05-10 14:33:55 +01006088 } else {
6089 StringInputBuffer buffer(this);
Ben Murdochc7cc0282012-03-05 14:35:55 +00006090 field = ComputeHashField(&buffer, len, GetHeap()->HashSeed());
Steve Block6ded16b2010-05-10 14:33:55 +01006091 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006092
6093 // Store the hash code in the object.
Steve Blockd0582a62009-12-15 09:54:21 +00006094 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00006095
6096 // Check the hash code is there.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006097 ASSERT(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00006098 uint32_t result = field >> kHashShift;
6099 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
6100 return result;
6101}
6102
6103
6104bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
6105 uint32_t* index,
6106 int length) {
6107 if (length == 0 || length > kMaxArrayIndexSize) return false;
6108 uc32 ch = buffer->GetNext();
6109
6110 // If the string begins with a '0' character, it must only consist
6111 // of it to be a legal array index.
6112 if (ch == '0') {
6113 *index = 0;
6114 return length == 1;
6115 }
6116
6117 // Convert string to uint32 array index; character by character.
6118 int d = ch - '0';
6119 if (d < 0 || d > 9) return false;
6120 uint32_t result = d;
6121 while (buffer->has_more()) {
6122 d = buffer->GetNext() - '0';
6123 if (d < 0 || d > 9) return false;
6124 // Check that the new result is below the 32 bit limit.
6125 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
6126 result = (result * 10) + d;
6127 }
6128
6129 *index = result;
6130 return true;
6131}
6132
6133
6134bool String::SlowAsArrayIndex(uint32_t* index) {
6135 if (length() <= kMaxCachedArrayIndexLength) {
6136 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00006137 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006138 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00006139 // Isolate the array index form the full hash field.
6140 *index = (kArrayIndexHashMask & field) >> kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00006141 return true;
6142 } else {
6143 StringInputBuffer buffer(this);
6144 return ComputeArrayIndex(&buffer, index, length());
6145 }
6146}
6147
6148
Iain Merrick9ac36c92010-09-13 15:29:50 +01006149uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006150 // For array indexes mix the length into the hash as an array index could
6151 // be zero.
6152 ASSERT(length > 0);
6153 ASSERT(length <= String::kMaxArrayIndexSize);
6154 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
6155 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01006156
6157 value <<= String::kHashShift;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006158 value |= length << String::kArrayIndexHashLengthShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01006159
6160 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
6161 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
6162 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006163 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00006164}
6165
6166
6167uint32_t StringHasher::GetHashField() {
6168 ASSERT(is_valid());
Steve Blockd0582a62009-12-15 09:54:21 +00006169 if (length_ <= String::kMaxHashCalcLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006170 if (is_array_index()) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01006171 return MakeArrayIndexHash(array_index(), length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00006172 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006173 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00006174 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006175 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00006176 }
6177}
6178
6179
Steve Blockd0582a62009-12-15 09:54:21 +00006180uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
Ben Murdochc7cc0282012-03-05 14:35:55 +00006181 int length,
6182 uint32_t seed) {
6183 StringHasher hasher(length, seed);
Steve Blocka7e24c12009-10-30 11:49:00 +00006184
6185 // Very long strings have a trivial hash that doesn't inspect the
6186 // string contents.
6187 if (hasher.has_trivial_hash()) {
6188 return hasher.GetHashField();
6189 }
6190
6191 // Do the iterative array index computation as long as there is a
6192 // chance this is an array index.
6193 while (buffer->has_more() && hasher.is_array_index()) {
6194 hasher.AddCharacter(buffer->GetNext());
6195 }
6196
6197 // Process the remaining characters without updating the array
6198 // index.
6199 while (buffer->has_more()) {
6200 hasher.AddCharacterNoIndex(buffer->GetNext());
6201 }
6202
6203 return hasher.GetHashField();
6204}
6205
6206
John Reck59135872010-11-02 12:39:01 -07006207MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01006208 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006209 if (start == 0 && end == length()) return this;
Steve Block44f0eee2011-05-26 01:26:41 +01006210 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
Steve Blockd0582a62009-12-15 09:54:21 +00006211 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00006212}
6213
6214
6215void String::PrintOn(FILE* file) {
6216 int length = this->length();
6217 for (int i = 0; i < length; i++) {
6218 fprintf(file, "%c", Get(i));
6219 }
6220}
6221
6222
6223void Map::CreateBackPointers() {
6224 DescriptorArray* descriptors = instance_descriptors();
6225 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
Ben Murdoch85b71792012-04-11 18:30:58 +01006226 if (descriptors->GetType(i) == MAP_TRANSITION ||
6227 descriptors->GetType(i) == ELEMENTS_TRANSITION ||
6228 descriptors->GetType(i) == CONSTANT_TRANSITION) {
6229 // Get target.
6230 Map* target = Map::cast(descriptors->GetValue(i));
6231#ifdef DEBUG
6232 // Verify target.
6233 Object* source_prototype = prototype();
6234 Object* target_prototype = target->prototype();
6235 ASSERT(source_prototype->IsJSObject() ||
6236 source_prototype->IsMap() ||
6237 source_prototype->IsNull());
6238 ASSERT(target_prototype->IsJSObject() ||
6239 target_prototype->IsNull());
6240 ASSERT(source_prototype->IsMap() ||
6241 source_prototype == target_prototype);
6242#endif
6243 // Point target back to source. set_prototype() will not let us set
6244 // the prototype to a map, as we do here.
6245 *RawField(target, kPrototypeOffset) = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00006246 }
6247 }
6248}
6249
6250
Steve Block44f0eee2011-05-26 01:26:41 +01006251void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Ben Murdoch85b71792012-04-11 18:30:58 +01006252 // Live DescriptorArray objects will be marked, so we must use
6253 // low-level accessors to get and modify their data.
6254 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00006255 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
6256 if (d->IsEmpty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00006257 Smi* NullDescriptorDetails =
6258 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
Ben Murdoch85b71792012-04-11 18:30:58 +01006259 FixedArray* contents = reinterpret_cast<FixedArray*>(
Steve Blocka7e24c12009-10-30 11:49:00 +00006260 d->get(DescriptorArray::kContentArrayIndex));
6261 ASSERT(contents->length() >= 2);
6262 for (int i = 0; i < contents->length(); i += 2) {
Ben Murdoch85b71792012-04-11 18:30:58 +01006263 // If the pair (value, details) is a map transition,
6264 // check if the target is live. If not, null the descriptor.
6265 // Also drop the back pointer for that map transition, so that this
6266 // map is not reached again by following a back pointer from a
6267 // non-live object.
Steve Blocka7e24c12009-10-30 11:49:00 +00006268 PropertyDetails details(Smi::cast(contents->get(i + 1)));
Ben Murdoch85b71792012-04-11 18:30:58 +01006269 if (details.type() == MAP_TRANSITION ||
6270 details.type() == ELEMENTS_TRANSITION ||
6271 details.type() == CONSTANT_TRANSITION) {
6272 Map* target = reinterpret_cast<Map*>(contents->get(i));
6273 ASSERT(target->IsHeapObject());
6274 if (!target->IsMarked()) {
6275 ASSERT(target->IsMap());
6276 contents->set_unchecked(i + 1, NullDescriptorDetails);
6277 contents->set_null_unchecked(heap, i);
6278 ASSERT(target->prototype() == this ||
6279 target->prototype() == real_prototype);
6280 // Getter prototype() is read-only, set_prototype() has side effects.
6281 *RawField(target, Map::kPrototypeOffset) = real_prototype;
Steve Blocka7e24c12009-10-30 11:49:00 +00006282 }
6283 }
6284 }
6285}
6286
6287
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006288int Map::Hash() {
6289 // For performance reasons we only hash the 3 most variable fields of a map:
6290 // constructor, prototype and bit_field2.
6291
6292 // Shift away the tag.
6293 int hash = (static_cast<uint32_t>(
6294 reinterpret_cast<uintptr_t>(constructor())) >> 2);
6295
6296 // XOR-ing the prototype and constructor directly yields too many zero bits
6297 // when the two pointers are close (which is fairly common).
6298 // To avoid this we shift the prototype 4 bits relatively to the constructor.
6299 hash ^= (static_cast<uint32_t>(
6300 reinterpret_cast<uintptr_t>(prototype())) << 2);
6301
6302 return hash ^ (hash >> 16) ^ bit_field2();
6303}
6304
6305
6306bool Map::EquivalentToForNormalization(Map* other,
6307 PropertyNormalizationMode mode) {
6308 return
6309 constructor() == other->constructor() &&
6310 prototype() == other->prototype() &&
6311 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
6312 0 :
6313 other->inobject_properties()) &&
6314 instance_type() == other->instance_type() &&
6315 bit_field() == other->bit_field() &&
6316 bit_field2() == other->bit_field2() &&
6317 (bit_field3() & ~(1<<Map::kIsShared)) ==
6318 (other->bit_field3() & ~(1<<Map::kIsShared));
6319}
6320
6321
Steve Block791712a2010-08-27 10:21:07 +01006322void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
6323 // Iterate over all fields in the body but take care in dealing with
6324 // the code entry.
6325 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
6326 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
6327 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
6328}
6329
6330
Ben Murdochb0fe1622011-05-05 13:52:32 +01006331void JSFunction::MarkForLazyRecompilation() {
6332 ASSERT(is_compiled() && !IsOptimized());
Ben Murdochb8e0da22011-05-16 14:20:40 +01006333 ASSERT(shared()->allows_lazy_compilation() ||
6334 code()->optimizable());
Steve Block44f0eee2011-05-26 01:26:41 +01006335 Builtins* builtins = GetIsolate()->builtins();
6336 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006337}
6338
6339
Ben Murdochb0fe1622011-05-05 13:52:32 +01006340bool JSFunction::IsInlineable() {
6341 if (IsBuiltin()) return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006342 SharedFunctionInfo* shared_info = shared();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006343 // Check that the function has a script associated with it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006344 if (!shared_info->script()->IsScript()) return false;
6345 if (shared_info->optimization_disabled()) return false;
6346 Code* code = shared_info->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006347 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
6348 // If we never ran this (unlikely) then lets try to optimize it.
6349 if (code->kind() != Code::FUNCTION) return true;
6350 return code->optimizable();
6351}
6352
6353
Ben Murdoch85b71792012-04-11 18:30:58 +01006354Object* JSFunction::SetInstancePrototype(Object* value) {
6355 ASSERT(value->IsJSObject());
Steve Block44f0eee2011-05-26 01:26:41 +01006356 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006357 if (has_initial_map()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01006358 initial_map()->set_prototype(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00006359 } else {
6360 // Put the value in the initial map field until an initial map is
6361 // needed. At that point, a new initial map is created and the
6362 // prototype is put into the initial map where it belongs.
6363 set_prototype_or_initial_map(value);
6364 }
Steve Block44f0eee2011-05-26 01:26:41 +01006365 heap->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00006366 return value;
6367}
6368
6369
John Reck59135872010-11-02 12:39:01 -07006370MaybeObject* JSFunction::SetPrototype(Object* value) {
Steve Block6ded16b2010-05-10 14:33:55 +01006371 ASSERT(should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +00006372 Object* construct_prototype = value;
6373
Ben Murdoch85b71792012-04-11 18:30:58 +01006374 // If the value is not a JSObject, store the value in the map's
Steve Blocka7e24c12009-10-30 11:49:00 +00006375 // constructor field so it can be accessed. Also, set the prototype
6376 // used for constructing objects to the original object prototype.
6377 // See ECMA-262 13.2.2.
Ben Murdoch85b71792012-04-11 18:30:58 +01006378 if (!value->IsJSObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006379 // Copy the map so this does not affect unrelated functions.
6380 // Remove map transitions because they point to maps with a
6381 // different prototype.
Ben Murdoch85b71792012-04-11 18:30:58 +01006382 Object* new_object;
John Reck59135872010-11-02 12:39:01 -07006383 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
Ben Murdoch85b71792012-04-11 18:30:58 +01006384 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07006385 }
Ben Murdoch85b71792012-04-11 18:30:58 +01006386 Map* new_map = Map::cast(new_object);
6387 Heap* heap = new_map->heap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006388 set_map(new_map);
6389 new_map->set_constructor(value);
6390 new_map->set_non_instance_prototype(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00006391 construct_prototype =
Steve Block44f0eee2011-05-26 01:26:41 +01006392 heap->isolate()->context()->global_context()->
6393 initial_object_prototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00006394 } else {
6395 map()->set_non_instance_prototype(false);
6396 }
6397
6398 return SetInstancePrototype(construct_prototype);
6399}
6400
6401
Steve Block6ded16b2010-05-10 14:33:55 +01006402Object* JSFunction::RemovePrototype() {
Steve Block44f0eee2011-05-26 01:26:41 +01006403 Context* global_context = context()->global_context();
Ben Murdoch85b71792012-04-11 18:30:58 +01006404 Map* no_prototype_map = shared()->strict_mode()
6405 ? global_context->strict_mode_function_without_prototype_map()
6406 : global_context->function_without_prototype_map();
Steve Block44f0eee2011-05-26 01:26:41 +01006407
6408 if (map() == no_prototype_map) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006409 // Be idempotent.
6410 return this;
6411 }
Steve Block44f0eee2011-05-26 01:26:41 +01006412
Ben Murdoch85b71792012-04-11 18:30:58 +01006413 ASSERT(!shared()->strict_mode() ||
6414 map() == global_context->strict_mode_function_map());
6415 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
Steve Block44f0eee2011-05-26 01:26:41 +01006416
6417 set_map(no_prototype_map);
Ben Murdoch85b71792012-04-11 18:30:58 +01006418 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01006419 return this;
6420}
6421
6422
Steve Blocka7e24c12009-10-30 11:49:00 +00006423Object* JSFunction::SetInstanceClassName(String* name) {
6424 shared()->set_instance_class_name(name);
6425 return this;
6426}
6427
6428
Ben Murdochb0fe1622011-05-05 13:52:32 +01006429void JSFunction::PrintName(FILE* out) {
Ben Murdoch589d6972011-11-30 16:04:58 +00006430 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006431 PrintF(out, "%s", *name);
6432}
6433
6434
Steve Blocka7e24c12009-10-30 11:49:00 +00006435Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
6436 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
6437}
6438
6439
Steve Block44f0eee2011-05-26 01:26:41 +01006440MaybeObject* Oddball::Initialize(const char* to_string,
6441 Object* to_number,
6442 byte kind) {
Ben Murdoch85b71792012-04-11 18:30:58 +01006443 Object* symbol;
Steve Block44f0eee2011-05-26 01:26:41 +01006444 { MaybeObject* maybe_symbol =
6445 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
Ben Murdoch85b71792012-04-11 18:30:58 +01006446 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
John Reck59135872010-11-02 12:39:01 -07006447 }
Ben Murdoch85b71792012-04-11 18:30:58 +01006448 set_to_string(String::cast(symbol));
Steve Blocka7e24c12009-10-30 11:49:00 +00006449 set_to_number(to_number);
Steve Block44f0eee2011-05-26 01:26:41 +01006450 set_kind(kind);
Steve Blocka7e24c12009-10-30 11:49:00 +00006451 return this;
6452}
6453
6454
Ben Murdochf87a2032010-10-22 12:50:53 +01006455String* SharedFunctionInfo::DebugName() {
6456 Object* n = name();
6457 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
6458 return String::cast(n);
6459}
6460
6461
Steve Blocka7e24c12009-10-30 11:49:00 +00006462bool SharedFunctionInfo::HasSourceCode() {
6463 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01006464 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00006465}
6466
6467
Ben Murdoch85b71792012-04-11 18:30:58 +01006468Object* SharedFunctionInfo::GetSourceCode() {
6469 Isolate* isolate = GetIsolate();
6470 if (!HasSourceCode()) return isolate->heap()->undefined_value();
6471 HandleScope scope(isolate);
6472 Object* source = Script::cast(script())->source();
6473 return *SubString(Handle<String>(String::cast(source), isolate),
6474 start_position(), end_position());
Steve Blocka7e24c12009-10-30 11:49:00 +00006475}
6476
6477
Ben Murdochb0fe1622011-05-05 13:52:32 +01006478int SharedFunctionInfo::SourceSize() {
6479 return end_position() - start_position();
6480}
6481
6482
Steve Blocka7e24c12009-10-30 11:49:00 +00006483int SharedFunctionInfo::CalculateInstanceSize() {
6484 int instance_size =
6485 JSObject::kHeaderSize +
6486 expected_nof_properties() * kPointerSize;
6487 if (instance_size > JSObject::kMaxInstanceSize) {
6488 instance_size = JSObject::kMaxInstanceSize;
6489 }
6490 return instance_size;
6491}
6492
6493
6494int SharedFunctionInfo::CalculateInObjectProperties() {
6495 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
6496}
6497
6498
Andrei Popescu402d9372010-02-26 13:31:12 +00006499bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
6500 // Check the basic conditions for generating inline constructor code.
6501 if (!FLAG_inline_new
6502 || !has_only_simple_this_property_assignments()
6503 || this_property_assignments_count() == 0) {
6504 return false;
6505 }
6506
6507 // If the prototype is null inline constructors cause no problems.
6508 if (!prototype->IsJSObject()) {
6509 ASSERT(prototype->IsNull());
6510 return true;
6511 }
6512
Ben Murdoch8b112d22011-06-08 16:22:53 +01006513 Heap* heap = GetHeap();
6514
Andrei Popescu402d9372010-02-26 13:31:12 +00006515 // Traverse the proposed prototype chain looking for setters for properties of
6516 // the same names as are set by the inline constructor.
6517 for (Object* obj = prototype;
Steve Block44f0eee2011-05-26 01:26:41 +01006518 obj != heap->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00006519 obj = obj->GetPrototype()) {
6520 JSObject* js_object = JSObject::cast(obj);
6521 for (int i = 0; i < this_property_assignments_count(); i++) {
Ben Murdoch85b71792012-04-11 18:30:58 +01006522 LookupResult result;
Andrei Popescu402d9372010-02-26 13:31:12 +00006523 String* name = GetThisPropertyAssignmentName(i);
6524 js_object->LocalLookupRealNamedProperty(name, &result);
Ben Murdoch85b71792012-04-11 18:30:58 +01006525 if (result.IsProperty() && result.type() == CALLBACKS) {
Andrei Popescu402d9372010-02-26 13:31:12 +00006526 return false;
6527 }
6528 }
6529 }
6530
6531 return true;
6532}
6533
6534
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006535void SharedFunctionInfo::ForbidInlineConstructor() {
6536 set_compiler_hints(BooleanBit::set(compiler_hints(),
6537 kHasOnlySimpleThisPropertyAssignments,
6538 false));
6539}
6540
6541
Steve Blocka7e24c12009-10-30 11:49:00 +00006542void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +00006543 bool only_simple_this_property_assignments,
6544 FixedArray* assignments) {
6545 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00006546 kHasOnlySimpleThisPropertyAssignments,
6547 only_simple_this_property_assignments));
6548 set_this_property_assignments(assignments);
6549 set_this_property_assignments_count(assignments->length() / 3);
6550}
6551
6552
6553void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
Steve Block44f0eee2011-05-26 01:26:41 +01006554 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006555 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00006556 kHasOnlySimpleThisPropertyAssignments,
6557 false));
Steve Block44f0eee2011-05-26 01:26:41 +01006558 set_this_property_assignments(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00006559 set_this_property_assignments_count(0);
6560}
6561
6562
6563String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
6564 Object* obj = this_property_assignments();
6565 ASSERT(obj->IsFixedArray());
6566 ASSERT(index < this_property_assignments_count());
6567 obj = FixedArray::cast(obj)->get(index * 3);
6568 ASSERT(obj->IsString());
6569 return String::cast(obj);
6570}
6571
6572
6573bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
6574 Object* obj = this_property_assignments();
6575 ASSERT(obj->IsFixedArray());
6576 ASSERT(index < this_property_assignments_count());
6577 obj = FixedArray::cast(obj)->get(index * 3 + 1);
6578 return Smi::cast(obj)->value() != -1;
6579}
6580
6581
6582int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
6583 ASSERT(IsThisPropertyAssignmentArgument(index));
6584 Object* obj =
6585 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
6586 return Smi::cast(obj)->value();
6587}
6588
6589
6590Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
6591 ASSERT(!IsThisPropertyAssignmentArgument(index));
6592 Object* obj =
6593 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
6594 return obj;
6595}
6596
6597
Steve Blocka7e24c12009-10-30 11:49:00 +00006598// Support function for printing the source code to a StringStream
6599// without any allocation in the heap.
6600void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
6601 int max_length) {
6602 // For some native functions there is no source.
Ben Murdochb0fe1622011-05-05 13:52:32 +01006603 if (!HasSourceCode()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006604 accumulator->Add("<No Source>");
6605 return;
6606 }
6607
Steve Blockd0582a62009-12-15 09:54:21 +00006608 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00006609 // Don't use String::cast because we don't want more assertion errors while
6610 // we are already creating a stack dump.
6611 String* script_source =
6612 reinterpret_cast<String*>(Script::cast(script())->source());
6613
6614 if (!script_source->LooksValid()) {
6615 accumulator->Add("<Invalid Source>");
6616 return;
6617 }
6618
6619 if (!is_toplevel()) {
6620 accumulator->Add("function ");
6621 Object* name = this->name();
6622 if (name->IsString() && String::cast(name)->length() > 0) {
6623 accumulator->PrintName(name);
6624 }
6625 }
6626
6627 int len = end_position() - start_position();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006628 if (len <= max_length || max_length < 0) {
6629 accumulator->Put(script_source, start_position(), end_position());
6630 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00006631 accumulator->Put(script_source,
6632 start_position(),
6633 start_position() + max_length);
6634 accumulator->Add("...\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006635 }
6636}
6637
6638
Ben Murdochb0fe1622011-05-05 13:52:32 +01006639static bool IsCodeEquivalent(Code* code, Code* recompiled) {
6640 if (code->instruction_size() != recompiled->instruction_size()) return false;
6641 ByteArray* code_relocation = code->relocation_info();
6642 ByteArray* recompiled_relocation = recompiled->relocation_info();
6643 int length = code_relocation->length();
6644 if (length != recompiled_relocation->length()) return false;
6645 int compare = memcmp(code_relocation->GetDataStartAddress(),
6646 recompiled_relocation->GetDataStartAddress(),
6647 length);
6648 return compare == 0;
6649}
6650
6651
6652void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
6653 ASSERT(!has_deoptimization_support());
6654 AssertNoAllocation no_allocation;
6655 Code* code = this->code();
6656 if (IsCodeEquivalent(code, recompiled)) {
6657 // Copy the deoptimization data from the recompiled code.
6658 code->set_deoptimization_data(recompiled->deoptimization_data());
6659 code->set_has_deoptimization_support(true);
6660 } else {
6661 // TODO(3025757): In case the recompiled isn't equivalent to the
6662 // old code, we have to replace it. We should try to avoid this
6663 // altogether because it flushes valuable type feedback by
6664 // effectively resetting all IC state.
6665 set_code(recompiled);
6666 }
6667 ASSERT(has_deoptimization_support());
6668}
6669
6670
Ben Murdoch85b71792012-04-11 18:30:58 +01006671void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
Ben Murdoch257744e2011-11-30 15:57:28 +00006672 // Disable optimization for the shared function info and mark the
6673 // code as non-optimizable. The marker on the shared function info
6674 // is there because we flush non-optimized code thereby loosing the
6675 // non-optimizable information for the code. When the code is
6676 // regenerated and set on the shared function info it is marked as
6677 // non-optimizable if optimization is disabled for the shared
6678 // function info.
6679 set_optimization_disabled(true);
6680 // Code should be the lazy compilation stub or else unoptimized. If the
6681 // latter, disable optimization for the code too.
6682 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
6683 if (code()->kind() == Code::FUNCTION) {
6684 code()->set_optimizable(false);
6685 }
6686 if (FLAG_trace_opt) {
Ben Murdoch85b71792012-04-11 18:30:58 +01006687 PrintF("[disabled optimization for: ");
6688 function->PrintName();
6689 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
Ben Murdoch257744e2011-11-30 15:57:28 +00006690 }
6691}
6692
6693
Ben Murdochb0fe1622011-05-05 13:52:32 +01006694bool SharedFunctionInfo::VerifyBailoutId(int id) {
Ben Murdoch85b71792012-04-11 18:30:58 +01006695 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
6696 // we are always bailing out on ARM.
6697
Ben Murdochb0fe1622011-05-05 13:52:32 +01006698 ASSERT(id != AstNode::kNoNumber);
6699 Code* unoptimized = code();
6700 DeoptimizationOutputData* data =
6701 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6702 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6703 USE(ignore);
6704 return true; // Return true if there was no ASSERT.
6705}
6706
6707
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006708void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6709 ASSERT(!IsInobjectSlackTrackingInProgress());
6710
6711 // Only initiate the tracking the first time.
6712 if (live_objects_may_exist()) return;
6713 set_live_objects_may_exist(true);
6714
6715 // No tracking during the snapshot construction phase.
6716 if (Serializer::enabled()) return;
6717
6718 if (map->unused_property_fields() == 0) return;
6719
6720 // Nonzero counter is a leftover from the previous attempt interrupted
6721 // by GC, keep it.
6722 if (construction_count() == 0) {
6723 set_construction_count(kGenerousAllocationCount);
6724 }
6725 set_initial_map(map);
Ben Murdoch85b71792012-04-11 18:30:58 +01006726 Builtins* builtins = map->heap()->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01006727 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006728 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006729 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006730}
6731
6732
6733// Called from GC, hence reinterpret_cast and unchecked accessors.
6734void SharedFunctionInfo::DetachInitialMap() {
6735 Map* map = reinterpret_cast<Map*>(initial_map());
6736
6737 // Make the map remember to restore the link if it survives the GC.
6738 map->set_bit_field2(
6739 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6740
6741 // Undo state changes made by StartInobjectTracking (except the
6742 // construction_count). This way if the initial map does not survive the GC
6743 // then StartInobjectTracking will be called again the next time the
6744 // constructor is called. The countdown will continue and (possibly after
6745 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
Ben Murdoch85b71792012-04-11 18:30:58 +01006746 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6747 Builtins* builtins = map->heap()->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01006748 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006749 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006750 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006751 // It is safe to clear the flag: it will be set again if the map is live.
6752 set_live_objects_may_exist(false);
6753}
6754
6755
6756// Called from GC, hence reinterpret_cast and unchecked accessors.
6757void SharedFunctionInfo::AttachInitialMap(Map* map) {
6758 map->set_bit_field2(
6759 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6760
6761 // Resume inobject slack tracking.
6762 set_initial_map(map);
Ben Murdoch85b71792012-04-11 18:30:58 +01006763 Builtins* builtins = map->heap()->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01006764 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006765 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006766 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006767 // The map survived the gc, so there may be objects referencing it.
6768 set_live_objects_may_exist(true);
6769}
6770
6771
6772static void GetMinInobjectSlack(Map* map, void* data) {
6773 int slack = map->unused_property_fields();
6774 if (*reinterpret_cast<int*>(data) > slack) {
6775 *reinterpret_cast<int*>(data) = slack;
6776 }
6777}
6778
6779
6780static void ShrinkInstanceSize(Map* map, void* data) {
6781 int slack = *reinterpret_cast<int*>(data);
6782 map->set_inobject_properties(map->inobject_properties() - slack);
6783 map->set_unused_property_fields(map->unused_property_fields() - slack);
6784 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6785
6786 // Visitor id might depend on the instance size, recalculate it.
6787 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6788}
6789
6790
6791void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6792 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6793 Map* map = Map::cast(initial_map());
6794
Ben Murdoch85b71792012-04-11 18:30:58 +01006795 Heap* heap = map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01006796 set_initial_map(heap->undefined_value());
6797 Builtins* builtins = heap->isolate()->builtins();
6798 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006799 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006800 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006801
6802 int slack = map->unused_property_fields();
6803 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6804 if (slack != 0) {
6805 // Resize the initial map and all maps in its transition tree.
6806 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006807
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006808 // Give the correct expected_nof_properties to initial maps created later.
6809 ASSERT(expected_nof_properties() >= slack);
6810 set_expected_nof_properties(expected_nof_properties() - slack);
6811 }
6812}
6813
6814
Steve Blocka7e24c12009-10-30 11:49:00 +00006815void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
6816 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
6817 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6818 Object* old_target = target;
6819 VisitPointer(&target);
6820 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6821}
6822
6823
Steve Block791712a2010-08-27 10:21:07 +01006824void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6825 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6826 Object* old_code = code;
6827 VisitPointer(&code);
6828 if (code != old_code) {
6829 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6830 }
6831}
6832
6833
Ben Murdochb0fe1622011-05-05 13:52:32 +01006834void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6835 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6836 Object* cell = rinfo->target_cell();
6837 Object* old_cell = cell;
6838 VisitPointer(&cell);
6839 if (cell != old_cell) {
6840 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6841 }
6842}
6843
6844
Steve Blocka7e24c12009-10-30 11:49:00 +00006845void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006846 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6847 rinfo->IsPatchedReturnSequence()) ||
6848 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6849 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006850 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6851 Object* old_target = target;
6852 VisitPointer(&target);
6853 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6854}
6855
6856
Ben Murdochb0fe1622011-05-05 13:52:32 +01006857void Code::InvalidateRelocation() {
Ben Murdoch85b71792012-04-11 18:30:58 +01006858 set_relocation_info(heap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006859}
6860
6861
Steve Blockd0582a62009-12-15 09:54:21 +00006862void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006863 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6864 it.rinfo()->apply(delta);
6865 }
6866 CPU::FlushICache(instruction_start(), instruction_size());
6867}
6868
6869
6870void Code::CopyFrom(const CodeDesc& desc) {
6871 // copy code
6872 memmove(instruction_start(), desc.buffer, desc.instr_size);
6873
Steve Blocka7e24c12009-10-30 11:49:00 +00006874 // copy reloc info
6875 memmove(relocation_start(),
6876 desc.buffer + desc.buffer_size - desc.reloc_size,
6877 desc.reloc_size);
6878
6879 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +00006880 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +00006881 int mode_mask = RelocInfo::kCodeTargetMask |
6882 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb0fe1622011-05-05 13:52:32 +01006883 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
Steve Blocka7e24c12009-10-30 11:49:00 +00006884 RelocInfo::kApplyMask;
Steve Block3ce2e202009-11-05 08:53:23 +00006885 Assembler* origin = desc.origin; // Needed to find target_object on X64.
Steve Blocka7e24c12009-10-30 11:49:00 +00006886 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
6887 RelocInfo::Mode mode = it.rinfo()->rmode();
6888 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +00006889 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Ben Murdoch85b71792012-04-11 18:30:58 +01006890 it.rinfo()->set_target_object(*p);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006891 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Ben Murdoch85b71792012-04-11 18:30:58 +01006892 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
6893 it.rinfo()->set_target_cell(*cell);
Steve Blocka7e24c12009-10-30 11:49:00 +00006894 } else if (RelocInfo::IsCodeTarget(mode)) {
6895 // rewrite code handles in inline cache targets to direct
6896 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +00006897 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006898 Code* code = Code::cast(*p);
Ben Murdoch85b71792012-04-11 18:30:58 +01006899 it.rinfo()->set_target_address(code->instruction_start());
Steve Blocka7e24c12009-10-30 11:49:00 +00006900 } else {
6901 it.rinfo()->apply(delta);
6902 }
6903 }
6904 CPU::FlushICache(instruction_start(), instruction_size());
6905}
6906
6907
6908// Locate the source position which is closest to the address in the code. This
6909// is using the source position information embedded in the relocation info.
6910// The position returned is relative to the beginning of the script where the
6911// source for this function is found.
6912int Code::SourcePosition(Address pc) {
6913 int distance = kMaxInt;
6914 int position = RelocInfo::kNoPosition; // Initially no position found.
6915 // Run through all the relocation info to find the best matching source
6916 // position. All the code needs to be considered as the sequence of the
6917 // instructions in the code does not necessarily follow the same order as the
6918 // source.
6919 RelocIterator it(this, RelocInfo::kPositionMask);
6920 while (!it.done()) {
6921 // Only look at positions after the current pc.
6922 if (it.rinfo()->pc() < pc) {
6923 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +00006924
6925 int dist = static_cast<int>(pc - it.rinfo()->pc());
6926 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006927 // If this position is closer than the current candidate or if it has the
6928 // same distance as the current candidate and the position is higher then
6929 // this position is the new candidate.
6930 if ((dist < distance) ||
6931 (dist == distance && pos > position)) {
6932 position = pos;
6933 distance = dist;
6934 }
6935 }
6936 it.next();
6937 }
6938 return position;
6939}
6940
6941
6942// Same as Code::SourcePosition above except it only looks for statement
6943// positions.
6944int Code::SourceStatementPosition(Address pc) {
6945 // First find the position as close as possible using all position
6946 // information.
6947 int position = SourcePosition(pc);
6948 // Now find the closest statement position before the position.
6949 int statement_position = 0;
6950 RelocIterator it(this, RelocInfo::kPositionMask);
6951 while (!it.done()) {
6952 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +00006953 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006954 if (statement_position < p && p <= position) {
6955 statement_position = p;
6956 }
6957 }
6958 it.next();
6959 }
6960 return statement_position;
6961}
6962
6963
Ben Murdochb8e0da22011-05-16 14:20:40 +01006964SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006965 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01006966 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006967}
6968
6969
6970void Code::SetNoStackCheckTable() {
6971 // Indicate the absence of a stack-check table by a table start after the
6972 // end of the instructions. Table start must be aligned, so round up.
Steve Block1e0659c2011-05-24 12:43:12 +01006973 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006974}
6975
6976
6977Map* Code::FindFirstMap() {
6978 ASSERT(is_inline_cache_stub());
6979 AssertNoAllocation no_allocation;
6980 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
6981 for (RelocIterator it(this, mask); !it.done(); it.next()) {
6982 RelocInfo* info = it.rinfo();
6983 Object* object = info->target_object();
6984 if (object->IsMap()) return Map::cast(object);
6985 }
6986 return NULL;
6987}
6988
6989
Steve Blocka7e24c12009-10-30 11:49:00 +00006990#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +01006991
Ben Murdochb0fe1622011-05-05 13:52:32 +01006992void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
6993 disasm::NameConverter converter;
6994 int deopt_count = DeoptCount();
6995 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
6996 if (0 == deopt_count) return;
6997
Ben Murdoch2b4ba112012-01-20 14:57:15 +00006998 PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc",
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006999 FLAG_print_code_verbose ? "commands" : "");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007000 for (int i = 0; i < deopt_count; i++) {
Ben Murdoch2b4ba112012-01-20 14:57:15 +00007001 PrintF(out, "%6d %6d %6d %6d",
7002 i,
7003 AstId(i)->value(),
7004 ArgumentsStackHeight(i)->value(),
7005 Pc(i)->value());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007006
7007 if (!FLAG_print_code_verbose) {
7008 PrintF(out, "\n");
7009 continue;
7010 }
7011 // Print details of the frame translation.
Ben Murdochb0fe1622011-05-05 13:52:32 +01007012 int translation_index = TranslationIndex(i)->value();
7013 TranslationIterator iterator(TranslationByteArray(), translation_index);
7014 Translation::Opcode opcode =
7015 static_cast<Translation::Opcode>(iterator.Next());
7016 ASSERT(Translation::BEGIN == opcode);
7017 int frame_count = iterator.Next();
Ben Murdoch85b71792012-04-11 18:30:58 +01007018 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
7019 frame_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007020
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007021 while (iterator.HasNext() &&
7022 Translation::BEGIN !=
7023 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
7024 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
7025
7026 switch (opcode) {
7027 case Translation::BEGIN:
7028 UNREACHABLE();
7029 break;
7030
Ben Murdoch85b71792012-04-11 18:30:58 +01007031 case Translation::FRAME: {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007032 int ast_id = iterator.Next();
7033 int function_id = iterator.Next();
7034 JSFunction* function =
7035 JSFunction::cast(LiteralArray()->get(function_id));
7036 unsigned height = iterator.Next();
Ben Murdoch589d6972011-11-30 16:04:58 +00007037 PrintF(out, "{ast_id=%d, function=", ast_id);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007038 function->PrintName(out);
7039 PrintF(out, ", height=%u}", height);
7040 break;
7041 }
7042
7043 case Translation::DUPLICATE:
7044 break;
7045
7046 case Translation::REGISTER: {
7047 int reg_code = iterator.Next();
7048 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7049 break;
7050 }
7051
7052 case Translation::INT32_REGISTER: {
7053 int reg_code = iterator.Next();
7054 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7055 break;
7056 }
7057
7058 case Translation::DOUBLE_REGISTER: {
7059 int reg_code = iterator.Next();
7060 PrintF(out, "{input=%s}",
7061 DoubleRegister::AllocationIndexToString(reg_code));
7062 break;
7063 }
7064
7065 case Translation::STACK_SLOT: {
7066 int input_slot_index = iterator.Next();
7067 PrintF(out, "{input=%d}", input_slot_index);
7068 break;
7069 }
7070
7071 case Translation::INT32_STACK_SLOT: {
7072 int input_slot_index = iterator.Next();
7073 PrintF(out, "{input=%d}", input_slot_index);
7074 break;
7075 }
7076
7077 case Translation::DOUBLE_STACK_SLOT: {
7078 int input_slot_index = iterator.Next();
7079 PrintF(out, "{input=%d}", input_slot_index);
7080 break;
7081 }
7082
7083 case Translation::LITERAL: {
7084 unsigned literal_index = iterator.Next();
7085 PrintF(out, "{literal_id=%u}", literal_index);
7086 break;
7087 }
7088
7089 case Translation::ARGUMENTS_OBJECT:
7090 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01007091 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007092 PrintF(out, "\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007093 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007094 }
7095}
7096
7097
7098void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
7099 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
7100 this->DeoptPoints());
7101 if (this->DeoptPoints() == 0) return;
7102
7103 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
7104 for (int i = 0; i < this->DeoptPoints(); i++) {
7105 int pc_and_state = this->PcAndState(i)->value();
7106 PrintF("%6d %8d %s\n",
7107 this->AstId(i)->value(),
7108 FullCodeGenerator::PcField::decode(pc_and_state),
7109 FullCodeGenerator::State2String(
7110 FullCodeGenerator::StateField::decode(pc_and_state)));
7111 }
7112}
7113
Ben Murdochb0fe1622011-05-05 13:52:32 +01007114
Steve Blocka7e24c12009-10-30 11:49:00 +00007115// Identify kind of code.
7116const char* Code::Kind2String(Kind kind) {
7117 switch (kind) {
7118 case FUNCTION: return "FUNCTION";
Ben Murdochb0fe1622011-05-05 13:52:32 +01007119 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
Steve Blocka7e24c12009-10-30 11:49:00 +00007120 case STUB: return "STUB";
7121 case BUILTIN: return "BUILTIN";
7122 case LOAD_IC: return "LOAD_IC";
7123 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
7124 case STORE_IC: return "STORE_IC";
7125 case KEYED_STORE_IC: return "KEYED_STORE_IC";
7126 case CALL_IC: return "CALL_IC";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007127 case KEYED_CALL_IC: return "KEYED_CALL_IC";
Ben Murdoch257744e2011-11-30 15:57:28 +00007128 case UNARY_OP_IC: return "UNARY_OP_IC";
7129 case BINARY_OP_IC: return "BINARY_OP_IC";
Ben Murdochb0fe1622011-05-05 13:52:32 +01007130 case COMPARE_IC: return "COMPARE_IC";
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007131 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00007132 }
7133 UNREACHABLE();
7134 return NULL;
7135}
7136
7137
7138const char* Code::ICState2String(InlineCacheState state) {
7139 switch (state) {
7140 case UNINITIALIZED: return "UNINITIALIZED";
7141 case PREMONOMORPHIC: return "PREMONOMORPHIC";
7142 case MONOMORPHIC: return "MONOMORPHIC";
7143 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
7144 case MEGAMORPHIC: return "MEGAMORPHIC";
7145 case DEBUG_BREAK: return "DEBUG_BREAK";
7146 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
7147 }
7148 UNREACHABLE();
7149 return NULL;
7150}
7151
7152
7153const char* Code::PropertyType2String(PropertyType type) {
7154 switch (type) {
7155 case NORMAL: return "NORMAL";
7156 case FIELD: return "FIELD";
7157 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
7158 case CALLBACKS: return "CALLBACKS";
Ben Murdoch257744e2011-11-30 15:57:28 +00007159 case HANDLER: return "HANDLER";
Steve Blocka7e24c12009-10-30 11:49:00 +00007160 case INTERCEPTOR: return "INTERCEPTOR";
7161 case MAP_TRANSITION: return "MAP_TRANSITION";
Ben Murdoch589d6972011-11-30 16:04:58 +00007162 case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
Steve Blocka7e24c12009-10-30 11:49:00 +00007163 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
7164 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
7165 }
Ben Murdoch85b71792012-04-11 18:30:58 +01007166 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00007167 return NULL;
7168}
7169
Ben Murdochb0fe1622011-05-05 13:52:32 +01007170
Steve Block1e0659c2011-05-24 12:43:12 +01007171void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
7172 const char* name = NULL;
7173 switch (kind) {
7174 case CALL_IC:
7175 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
7176 name = "STRING_INDEX_OUT_OF_BOUNDS";
7177 }
7178 break;
7179 case STORE_IC:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007180 case KEYED_STORE_IC:
7181 if (extra == kStrictMode) {
Steve Block1e0659c2011-05-24 12:43:12 +01007182 name = "STRICT";
7183 }
7184 break;
7185 default:
7186 break;
7187 }
7188 if (name != NULL) {
7189 PrintF(out, "extra_ic_state = %s\n", name);
7190 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007191 PrintF(out, "extra_ic_state = %d\n", extra);
Steve Block1e0659c2011-05-24 12:43:12 +01007192 }
7193}
7194
7195
Ben Murdochb0fe1622011-05-05 13:52:32 +01007196void Code::Disassemble(const char* name, FILE* out) {
7197 PrintF(out, "kind = %s\n", Kind2String(kind()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007198 if (is_inline_cache_stub()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007199 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
Steve Block1e0659c2011-05-24 12:43:12 +01007200 PrintExtraICState(out, kind(), extra_ic_state());
Steve Blocka7e24c12009-10-30 11:49:00 +00007201 if (ic_state() == MONOMORPHIC) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007202 PrintF(out, "type = %s\n", PropertyType2String(type()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007203 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007204 if (is_call_stub() || is_keyed_call_stub()) {
7205 PrintF(out, "argc = %d\n", arguments_count());
7206 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007207 }
7208 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007209 PrintF(out, "name = %s\n", name);
7210 }
7211 if (kind() == OPTIMIZED_FUNCTION) {
7212 PrintF(out, "stack_slots = %d\n", stack_slots());
Steve Blocka7e24c12009-10-30 11:49:00 +00007213 }
7214
Ben Murdochb0fe1622011-05-05 13:52:32 +01007215 PrintF(out, "Instructions (size = %d)\n", instruction_size());
7216 Disassembler::Decode(out, this);
7217 PrintF(out, "\n");
7218
Ben Murdochb0fe1622011-05-05 13:52:32 +01007219 if (kind() == FUNCTION) {
7220 DeoptimizationOutputData* data =
7221 DeoptimizationOutputData::cast(this->deoptimization_data());
7222 data->DeoptimizationOutputDataPrint(out);
7223 } else if (kind() == OPTIMIZED_FUNCTION) {
7224 DeoptimizationInputData* data =
7225 DeoptimizationInputData::cast(this->deoptimization_data());
7226 data->DeoptimizationInputDataPrint(out);
7227 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007228 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007229
7230 if (kind() == OPTIMIZED_FUNCTION) {
7231 SafepointTable table(this);
7232 PrintF(out, "Safepoints (size = %u)\n", table.size());
7233 for (unsigned i = 0; i < table.length(); i++) {
7234 unsigned pc_offset = table.GetPcOffset(i);
7235 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
7236 table.PrintEntry(i);
7237 PrintF(out, " (sp -> fp)");
Ben Murdochb8e0da22011-05-16 14:20:40 +01007238 SafepointEntry entry = table.GetEntry(i);
7239 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
7240 PrintF(out, " %6d", entry.deoptimization_index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007241 } else {
7242 PrintF(out, " <none>");
7243 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01007244 if (entry.argument_count() > 0) {
7245 PrintF(out, " argc: %d", entry.argument_count());
7246 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007247 PrintF(out, "\n");
7248 }
7249 PrintF(out, "\n");
7250 } else if (kind() == FUNCTION) {
Steve Block1e0659c2011-05-24 12:43:12 +01007251 unsigned offset = stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007252 // If there is no stack check table, the "table start" will at or after
7253 // (due to alignment) the end of the instruction stream.
7254 if (static_cast<int>(offset) < instruction_size()) {
7255 unsigned* address =
7256 reinterpret_cast<unsigned*>(instruction_start() + offset);
7257 unsigned length = address[0];
7258 PrintF(out, "Stack checks (size = %u)\n", length);
7259 PrintF(out, "ast_id pc_offset\n");
7260 for (unsigned i = 0; i < length; ++i) {
7261 unsigned index = (2 * i) + 1;
7262 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
7263 }
7264 PrintF(out, "\n");
7265 }
7266 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007267
7268 PrintF("RelocInfo (size = %d)\n", relocation_size());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007269 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
7270 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00007271}
7272#endif // ENABLE_DISASSEMBLER
7273
7274
Ben Murdoch85b71792012-04-11 18:30:58 +01007275static void CopyFastElementsToFast(FixedArray* source,
7276 FixedArray* destination,
7277 WriteBarrierMode mode) {
7278 uint32_t count = static_cast<uint32_t>(source->length());
7279 for (uint32_t i = 0; i < count; ++i) {
7280 destination->set(i, source->get(i), mode);
7281 }
7282}
7283
7284
7285static void CopySlowElementsToFast(SeededNumberDictionary* source,
7286 FixedArray* destination,
7287 WriteBarrierMode mode) {
7288 for (int i = 0; i < source->Capacity(); ++i) {
7289 Object* key = source->KeyAt(i);
7290 if (key->IsNumber()) {
7291 uint32_t entry = static_cast<uint32_t>(key->Number());
7292 destination->set(entry, source->ValueAt(i), mode);
7293 }
7294 }
7295}
7296
7297
7298MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
7299 int length) {
Steve Block44f0eee2011-05-26 01:26:41 +01007300 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00007301 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01007302 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01007303
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007304 // Allocate a new fast elements backing store.
Ben Murdoch85b71792012-04-11 18:30:58 +01007305 FixedArray* new_elements = NULL;
7306 { Object* object;
7307 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
7308 if (!maybe->ToObject(&object)) return maybe;
7309 new_elements = FixedArray::cast(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007310 }
7311
7312 // Find the new map to use for this object if there is a map change.
7313 Map* new_map = NULL;
7314 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01007315 Object* object;
7316 MaybeObject* maybe = map()->GetFastElementsMap();
7317 if (!maybe->ToObject(&object)) return maybe;
7318 new_map = Map::cast(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007319 }
7320
Ben Murdoch85b71792012-04-11 18:30:58 +01007321 switch (GetElementsKind()) {
7322 case FAST_ELEMENTS: {
7323 AssertNoAllocation no_gc;
7324 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7325 CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
7326 set_map(new_map);
7327 set_elements(new_elements);
7328 break;
7329 }
7330 case DICTIONARY_ELEMENTS: {
7331 AssertNoAllocation no_gc;
7332 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7333 CopySlowElementsToFast(SeededNumberDictionary::cast(elements()),
7334 new_elements,
7335 mode);
7336 set_map(new_map);
7337 set_elements(new_elements);
7338 break;
7339 }
7340 case NON_STRICT_ARGUMENTS_ELEMENTS: {
7341 AssertNoAllocation no_gc;
7342 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7343 // The object's map and the parameter map are unchanged, the unaliased
7344 // arguments are copied to the new backing store.
7345 FixedArray* parameter_map = FixedArray::cast(elements());
7346 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7347 if (arguments->IsDictionary()) {
7348 CopySlowElementsToFast(SeededNumberDictionary::cast(arguments),
7349 new_elements,
7350 mode);
7351 } else {
7352 CopyFastElementsToFast(arguments, new_elements, mode);
7353 }
7354 parameter_map->set(1, new_elements);
7355 break;
7356 }
7357 case FAST_DOUBLE_ELEMENTS: {
7358 FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements());
7359 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
7360 // Fill out the new array with this content and array holes.
7361 for (uint32_t i = 0; i < old_length; i++) {
7362 if (!old_elements->is_the_hole(i)) {
7363 Object* obj;
7364 // Objects must be allocated in the old object space, since the
7365 // overall number of HeapNumbers needed for the conversion might
7366 // exceed the capacity of new space, and we would fail repeatedly
7367 // trying to convert the FixedDoubleArray.
7368 MaybeObject* maybe_value_object =
7369 GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
7370 TENURED);
7371 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
7372 // Force write barrier. It's not worth trying to exploit
7373 // elems->GetWriteBarrierMode(), since it requires an
7374 // AssertNoAllocation stack object that would have to be positioned
7375 // after the HeapNumber allocation anyway.
7376 new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
7377 }
7378 }
7379 set_map(new_map);
7380 set_elements(new_elements);
7381 break;
7382 }
7383 case EXTERNAL_BYTE_ELEMENTS:
7384 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7385 case EXTERNAL_SHORT_ELEMENTS:
7386 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7387 case EXTERNAL_INT_ELEMENTS:
7388 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7389 case EXTERNAL_FLOAT_ELEMENTS:
7390 case EXTERNAL_DOUBLE_ELEMENTS:
7391 case EXTERNAL_PIXEL_ELEMENTS:
7392 UNREACHABLE();
7393 break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007394 }
7395
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007396 // Update the length if necessary.
7397 if (IsJSArray()) {
7398 JSArray::cast(this)->set_length(Smi::FromInt(length));
7399 }
7400
7401 return new_elements;
7402}
7403
7404
7405MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
7406 int capacity,
7407 int length) {
7408 Heap* heap = GetHeap();
7409 // We should never end in here with a pixel or external array.
7410 ASSERT(!HasExternalArrayElements());
7411
Ben Murdoch85b71792012-04-11 18:30:58 +01007412 Object* obj;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007413 { MaybeObject* maybe_obj =
7414 heap->AllocateUninitializedFixedDoubleArray(capacity);
Ben Murdoch85b71792012-04-11 18:30:58 +01007415 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7416 }
7417 FixedDoubleArray* elems = FixedDoubleArray::cast(obj);
7418
7419 { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap();
7420 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7421 }
7422 Map* new_map = Map::cast(obj);
7423
7424 AssertNoAllocation no_gc;
7425 switch (GetElementsKind()) {
7426 case FAST_ELEMENTS: {
7427 elems->Initialize(FixedArray::cast(elements()));
7428 break;
7429 }
7430 case FAST_DOUBLE_ELEMENTS: {
7431 elems->Initialize(FixedDoubleArray::cast(elements()));
7432 break;
7433 }
7434 case DICTIONARY_ELEMENTS: {
7435 elems->Initialize(SeededNumberDictionary::cast(elements()));
7436 break;
7437 }
7438 default:
7439 UNREACHABLE();
7440 break;
John Reck59135872010-11-02 12:39:01 -07007441 }
Steve Block8defd9f2010-07-08 12:39:36 +01007442
Ben Murdoch85b71792012-04-11 18:30:58 +01007443 ASSERT(new_map->has_fast_double_elements());
7444 set_map(new_map);
7445 ASSERT(elems->IsFixedDoubleArray());
7446 set_elements(elems);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007447
Steve Block8defd9f2010-07-08 12:39:36 +01007448 if (IsJSArray()) {
7449 JSArray::cast(this)->set_length(Smi::FromInt(length));
7450 }
7451
7452 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00007453}
7454
7455
Ben Murdoch85b71792012-04-11 18:30:58 +01007456MaybeObject* JSObject::SetSlowElements(Object* len) {
7457 // We should never end in here with a pixel or external array.
7458 ASSERT(!HasExternalArrayElements());
7459
7460 uint32_t new_length = static_cast<uint32_t>(len->Number());
7461
7462 switch (GetElementsKind()) {
7463 case FAST_ELEMENTS: {
7464 case FAST_DOUBLE_ELEMENTS:
7465 // Make sure we never try to shrink dense arrays into sparse arrays.
7466 ASSERT(static_cast<uint32_t>(
7467 FixedArrayBase::cast(elements())->length()) <= new_length);
7468 MaybeObject* result = NormalizeElements();
7469 if (result->IsFailure()) return result;
7470
7471 // Update length for JSArrays.
7472 if (IsJSArray()) JSArray::cast(this)->set_length(len);
7473 break;
7474 }
7475 case DICTIONARY_ELEMENTS: {
7476 if (IsJSArray()) {
7477 uint32_t old_length =
7478 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
7479 element_dictionary()->RemoveNumberEntries(new_length, old_length),
7480 JSArray::cast(this)->set_length(len);
7481 }
7482 break;
7483 }
7484 case NON_STRICT_ARGUMENTS_ELEMENTS:
7485 UNIMPLEMENTED();
7486 break;
7487 case EXTERNAL_BYTE_ELEMENTS:
7488 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7489 case EXTERNAL_SHORT_ELEMENTS:
7490 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7491 case EXTERNAL_INT_ELEMENTS:
7492 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7493 case EXTERNAL_FLOAT_ELEMENTS:
7494 case EXTERNAL_DOUBLE_ELEMENTS:
7495 case EXTERNAL_PIXEL_ELEMENTS:
7496 UNREACHABLE();
7497 break;
7498 }
7499 return this;
7500}
7501
7502
John Reck59135872010-11-02 12:39:01 -07007503MaybeObject* JSArray::Initialize(int capacity) {
Steve Block44f0eee2011-05-26 01:26:41 +01007504 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007505 ASSERT(capacity >= 0);
Leon Clarke4515c472010-02-03 11:58:03 +00007506 set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00007507 FixedArray* new_elements;
7508 if (capacity == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01007509 new_elements = heap->empty_fixed_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00007510 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +01007511 Object* obj;
7512 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
7513 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7514 }
7515 new_elements = FixedArray::cast(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00007516 }
7517 set_elements(new_elements);
7518 return this;
7519}
7520
7521
7522void JSArray::Expand(int required_size) {
Ben Murdoch85b71792012-04-11 18:30:58 +01007523 Handle<JSArray> self(this);
7524 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
7525 int old_size = old_backing->length();
7526 int new_size = required_size > old_size ? required_size : old_size;
7527 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
7528 // Can't use this any more now because we may have had a GC!
7529 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
7530 self->SetContent(*new_backing);
Steve Blocka7e24c12009-10-30 11:49:00 +00007531}
7532
7533
Ben Murdoch85b71792012-04-11 18:30:58 +01007534static Failure* ArrayLengthRangeError(Heap* heap) {
7535 HandleScope scope(heap->isolate());
7536 return heap->isolate()->Throw(
7537 *FACTORY->NewRangeError("invalid_array_length",
7538 HandleVector<Object>(NULL, 0)));
7539}
7540
7541
7542MaybeObject* JSObject::SetElementsLength(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00007543 // We should never end in here with a pixel or external array.
Steve Block6ded16b2010-05-10 14:33:55 +01007544 ASSERT(AllowsSetElementsLength());
Ben Murdoch85b71792012-04-11 18:30:58 +01007545
7546 MaybeObject* maybe_smi_length = len->ToSmi();
7547 Object* smi_length = Smi::FromInt(0);
7548 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
7549 const int value = Smi::cast(smi_length)->value();
7550 if (value < 0) return ArrayLengthRangeError(GetHeap());
7551 ElementsKind elements_kind = GetElementsKind();
7552 switch (elements_kind) {
7553 case FAST_ELEMENTS:
7554 case FAST_DOUBLE_ELEMENTS: {
7555 int old_capacity = FixedArrayBase::cast(elements())->length();
7556 if (value <= old_capacity) {
7557 if (IsJSArray()) {
7558 Object* obj;
7559 if (elements_kind == FAST_ELEMENTS) {
7560 MaybeObject* maybe_obj = EnsureWritableFastElements();
7561 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7562 }
7563 if (2 * value <= old_capacity) {
7564 // If more than half the elements won't be used, trim the array.
7565 if (value == 0) {
7566 initialize_elements();
7567 } else {
7568 Address filler_start;
7569 int filler_size;
7570 if (GetElementsKind() == FAST_ELEMENTS) {
7571 FixedArray* fast_elements = FixedArray::cast(elements());
7572 fast_elements->set_length(value);
7573 filler_start = fast_elements->address() +
7574 FixedArray::OffsetOfElementAt(value);
7575 filler_size = (old_capacity - value) * kPointerSize;
7576 } else {
7577 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7578 FixedDoubleArray* fast_double_elements =
7579 FixedDoubleArray::cast(elements());
7580 fast_double_elements->set_length(value);
7581 filler_start = fast_double_elements->address() +
7582 FixedDoubleArray::OffsetOfElementAt(value);
7583 filler_size = (old_capacity - value) * kDoubleSize;
7584 }
7585 GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
7586 }
7587 } else {
7588 // Otherwise, fill the unused tail with holes.
7589 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
7590 if (GetElementsKind() == FAST_ELEMENTS) {
7591 FixedArray* fast_elements = FixedArray::cast(elements());
7592 for (int i = value; i < old_length; i++) {
7593 fast_elements->set_the_hole(i);
7594 }
7595 } else {
7596 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7597 FixedDoubleArray* fast_double_elements =
7598 FixedDoubleArray::cast(elements());
7599 for (int i = value; i < old_length; i++) {
7600 fast_double_elements->set_the_hole(i);
7601 }
7602 }
7603 }
7604 JSArray::cast(this)->set_length(Smi::cast(smi_length));
7605 }
7606 return this;
7607 }
7608 int min = NewElementsCapacity(old_capacity);
7609 int new_capacity = value > min ? value : min;
7610 if (!ShouldConvertToSlowElements(new_capacity)) {
7611 MaybeObject* result;
7612 if (GetElementsKind() == FAST_ELEMENTS) {
7613 result = SetFastElementsCapacityAndLength(new_capacity, value);
7614 } else {
7615 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7616 result = SetFastDoubleElementsCapacityAndLength(new_capacity,
7617 value);
7618 }
7619 if (result->IsFailure()) return result;
7620 return this;
7621 }
7622 break;
7623 }
7624 case DICTIONARY_ELEMENTS: {
7625 if (IsJSArray()) {
7626 if (value == 0) {
7627 // If the length of a slow array is reset to zero, we clear
7628 // the array and flush backing storage. This has the added
7629 // benefit that the array returns to fast mode.
7630 Object* obj;
7631 { MaybeObject* maybe_obj = ResetElements();
7632 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7633 }
7634 } else {
7635 // Remove deleted elements.
7636 uint32_t old_length =
7637 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
7638 element_dictionary()->RemoveNumberEntries(value, old_length);
7639 }
7640 JSArray::cast(this)->set_length(Smi::cast(smi_length));
7641 }
7642 return this;
7643 }
7644 case NON_STRICT_ARGUMENTS_ELEMENTS:
7645 case EXTERNAL_BYTE_ELEMENTS:
7646 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7647 case EXTERNAL_SHORT_ELEMENTS:
7648 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7649 case EXTERNAL_INT_ELEMENTS:
7650 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7651 case EXTERNAL_FLOAT_ELEMENTS:
7652 case EXTERNAL_DOUBLE_ELEMENTS:
7653 case EXTERNAL_PIXEL_ELEMENTS:
7654 UNREACHABLE();
7655 break;
7656 }
7657 }
7658
7659 // General slow case.
7660 if (len->IsNumber()) {
7661 uint32_t length;
7662 if (len->ToArrayIndex(&length)) {
7663 return SetSlowElements(len);
7664 } else {
7665 return ArrayLengthRangeError(GetHeap());
7666 }
7667 }
7668
7669 // len is not a number so make the array size one and
7670 // set only element to len.
7671 Object* obj;
7672 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
7673 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7674 }
7675 FixedArray::cast(obj)->set(0, len);
7676 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
7677 set_elements(FixedArray::cast(obj));
7678 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00007679}
7680
7681
Steve Block053d10c2011-06-13 19:13:29 +01007682Object* Map::GetPrototypeTransition(Object* prototype) {
7683 FixedArray* cache = prototype_transitions();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007684 int number_of_transitions = NumberOfProtoTransitions();
7685 const int proto_offset =
7686 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
7687 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
7688 const int step = kProtoTransitionElementsPerEntry;
7689 for (int i = 0; i < number_of_transitions; i++) {
7690 if (cache->get(proto_offset + i * step) == prototype) {
7691 Object* map = cache->get(map_offset + i * step);
7692 ASSERT(map->IsMap());
7693 return map;
7694 }
Steve Block053d10c2011-06-13 19:13:29 +01007695 }
7696 return NULL;
7697}
7698
7699
7700MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007701 ASSERT(map->IsMap());
7702 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
Steve Block053d10c2011-06-13 19:13:29 +01007703 // Don't cache prototype transition if this map is shared.
7704 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
7705
7706 FixedArray* cache = prototype_transitions();
7707
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007708 const int step = kProtoTransitionElementsPerEntry;
7709 const int header = kProtoTransitionHeaderSize;
Steve Block053d10c2011-06-13 19:13:29 +01007710
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007711 int capacity = (cache->length() - header) / step;
Steve Block053d10c2011-06-13 19:13:29 +01007712
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007713 int transitions = NumberOfProtoTransitions() + 1;
7714
7715 if (transitions > capacity) {
Steve Block053d10c2011-06-13 19:13:29 +01007716 if (capacity > kMaxCachedPrototypeTransitions) return this;
7717
7718 FixedArray* new_cache;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007719 // Grow array by factor 2 over and above what we need.
7720 { MaybeObject* maybe_cache =
Ben Murdoch85b71792012-04-11 18:30:58 +01007721 heap()->AllocateFixedArray(transitions * 2 * step + header);
7722 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
Steve Block053d10c2011-06-13 19:13:29 +01007723 }
7724
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007725 for (int i = 0; i < capacity * step; i++) {
7726 new_cache->set(i + header, cache->get(i + header));
7727 }
Steve Block053d10c2011-06-13 19:13:29 +01007728 cache = new_cache;
7729 set_prototype_transitions(cache);
7730 }
7731
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007732 int last = transitions - 1;
7733
7734 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
7735 cache->set(header + last * step + kProtoTransitionMapOffset, map);
7736 SetNumberOfProtoTransitions(transitions);
Steve Block053d10c2011-06-13 19:13:29 +01007737
7738 return cache;
7739}
7740
7741
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007742MaybeObject* JSReceiver::SetPrototype(Object* value,
7743 bool skip_hidden_prototypes) {
7744#ifdef DEBUG
7745 int size = Size();
7746#endif
7747
Steve Block44f0eee2011-05-26 01:26:41 +01007748 Heap* heap = GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +00007749 // Silently ignore the change if value is not a JSObject or null.
7750 // SpiderMonkey behaves this way.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007751 if (!value->IsJSReceiver() && !value->IsNull()) return value;
Andrei Popescu402d9372010-02-26 13:31:12 +00007752
Ben Murdoch8b112d22011-06-08 16:22:53 +01007753 // From 8.6.2 Object Internal Methods
7754 // ...
7755 // In addition, if [[Extensible]] is false the value of the [[Class]] and
7756 // [[Prototype]] internal properties of the object may not be modified.
7757 // ...
7758 // Implementation specific extensions that modify [[Class]], [[Prototype]]
7759 // or [[Extensible]] must not violate the invariants defined in the preceding
7760 // paragraph.
7761 if (!this->map()->is_extensible()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007762 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01007763 Handle<Object> handle(this, heap->isolate());
7764 return heap->isolate()->Throw(
7765 *FACTORY->NewTypeError("non_extensible_proto",
7766 HandleVector<Object>(&handle, 1)));
7767 }
7768
Andrei Popescu402d9372010-02-26 13:31:12 +00007769 // Before we can set the prototype we need to be sure
7770 // prototype cycles are prevented.
7771 // It is sufficient to validate that the receiver is not in the new prototype
7772 // chain.
Steve Block44f0eee2011-05-26 01:26:41 +01007773 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01007774 if (JSObject::cast(pt) == this) {
Andrei Popescu402d9372010-02-26 13:31:12 +00007775 // Cycle detected.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007776 HandleScope scope(heap->isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01007777 return heap->isolate()->Throw(
7778 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
Andrei Popescu402d9372010-02-26 13:31:12 +00007779 }
7780 }
7781
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007782 JSReceiver* real_receiver = this;
Andrei Popescu402d9372010-02-26 13:31:12 +00007783
7784 if (skip_hidden_prototypes) {
7785 // Find the first object in the chain whose prototype object is not
7786 // hidden and set the new prototype on that object.
7787 Object* current_proto = real_receiver->GetPrototype();
7788 while (current_proto->IsJSObject() &&
Ben Murdoch85b71792012-04-11 18:30:58 +01007789 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
7790 real_receiver = JSObject::cast(current_proto);
Andrei Popescu402d9372010-02-26 13:31:12 +00007791 current_proto = current_proto->GetPrototype();
7792 }
7793 }
7794
7795 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +01007796 Map* map = real_receiver->map();
7797
7798 // Nothing to do if prototype is already set.
7799 if (map->prototype() == value) return value;
7800
7801 Object* new_map = map->GetPrototypeTransition(value);
7802 if (new_map == NULL) {
7803 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
7804 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
7805 }
7806
7807 { MaybeObject* maybe_new_cache =
7808 map->PutPrototypeTransition(value, Map::cast(new_map));
7809 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
7810 }
7811
7812 Map::cast(new_map)->set_prototype(value);
John Reck59135872010-11-02 12:39:01 -07007813 }
Steve Block053d10c2011-06-13 19:13:29 +01007814 ASSERT(Map::cast(new_map)->prototype() == value);
Andrei Popescu402d9372010-02-26 13:31:12 +00007815 real_receiver->set_map(Map::cast(new_map));
7816
Steve Block44f0eee2011-05-26 01:26:41 +01007817 heap->ClearInstanceofCache();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007818 ASSERT(size == Size());
Andrei Popescu402d9372010-02-26 13:31:12 +00007819 return value;
7820}
7821
7822
Ben Murdoch85b71792012-04-11 18:30:58 +01007823bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
7824 switch (GetElementsKind()) {
7825 case FAST_ELEMENTS: {
7826 uint32_t length = IsJSArray() ?
7827 static_cast<uint32_t>
7828 (Smi::cast(JSArray::cast(this)->length())->value()) :
7829 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7830 if ((index < length) &&
7831 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7832 return true;
7833 }
7834 break;
7835 }
7836 case FAST_DOUBLE_ELEMENTS: {
7837 uint32_t length = IsJSArray() ?
7838 static_cast<uint32_t>
7839 (Smi::cast(JSArray::cast(this)->length())->value()) :
7840 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
7841 if ((index < length) &&
7842 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
7843 return true;
7844 }
7845 break;
7846 }
7847 case EXTERNAL_PIXEL_ELEMENTS: {
7848 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
7849 if (index < static_cast<uint32_t>(pixels->length())) {
7850 return true;
7851 }
7852 break;
7853 }
7854 case EXTERNAL_BYTE_ELEMENTS:
7855 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7856 case EXTERNAL_SHORT_ELEMENTS:
7857 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7858 case EXTERNAL_INT_ELEMENTS:
7859 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7860 case EXTERNAL_FLOAT_ELEMENTS:
7861 case EXTERNAL_DOUBLE_ELEMENTS: {
7862 ExternalArray* array = ExternalArray::cast(elements());
7863 if (index < static_cast<uint32_t>(array->length())) {
7864 return true;
7865 }
7866 break;
7867 }
7868 case DICTIONARY_ELEMENTS: {
7869 if (element_dictionary()->FindEntry(index)
7870 != SeededNumberDictionary::kNotFound) {
7871 return true;
7872 }
7873 break;
7874 }
7875 case NON_STRICT_ARGUMENTS_ELEMENTS:
7876 UNREACHABLE();
7877 break;
7878 }
7879
7880 // Handle [] on String objects.
7881 if (this->IsStringObjectWithCharacterAt(index)) return true;
7882
7883 Object* pt = GetPrototype();
7884 if (pt->IsNull()) return false;
7885 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007886}
7887
7888
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007889bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007890 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007891 // Make sure that the top context does not change when doing
7892 // callbacks or interceptor calls.
7893 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007894 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007895 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007896 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00007897 Handle<JSObject> holder_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01007898 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007899 v8::AccessorInfo info(args.end());
7900 if (!interceptor->query()->IsUndefined()) {
7901 v8::IndexedPropertyQuery query =
7902 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01007903 LOG(isolate,
7904 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
Iain Merrick75681382010-08-19 15:07:18 +01007905 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007906 {
7907 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007908 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007909 result = query(index, info);
7910 }
Iain Merrick75681382010-08-19 15:07:18 +01007911 if (!result.IsEmpty()) {
7912 ASSERT(result->IsInt32());
7913 return true; // absence of property is signaled by empty handle.
7914 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007915 } else if (!interceptor->getter()->IsUndefined()) {
7916 v8::IndexedPropertyGetter getter =
7917 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007918 LOG(isolate,
7919 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
Steve Blocka7e24c12009-10-30 11:49:00 +00007920 v8::Handle<v8::Value> result;
7921 {
7922 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007923 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007924 result = getter(index, info);
7925 }
7926 if (!result.IsEmpty()) return true;
7927 }
Ben Murdoch85b71792012-04-11 18:30:58 +01007928 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00007929}
7930
7931
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007932JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007933 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007934 if (IsAccessCheckNeeded()) {
7935 Heap* heap = GetHeap();
7936 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7937 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7938 return UNDEFINED_ELEMENT;
7939 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007940 }
7941
Steve Block1e0659c2011-05-24 12:43:12 +01007942 if (IsJSGlobalProxy()) {
7943 Object* proto = GetPrototype();
7944 if (proto->IsNull()) return UNDEFINED_ELEMENT;
7945 ASSERT(proto->IsJSGlobalObject());
7946 return JSObject::cast(proto)->HasLocalElement(index);
7947 }
7948
Steve Blocka7e24c12009-10-30 11:49:00 +00007949 // Check for lookup interceptor
7950 if (HasIndexedInterceptor()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007951 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
7952 : UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00007953 }
7954
7955 // Handle [] on String objects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007956 if (this->IsStringObjectWithCharacterAt(index)) {
7957 return STRING_CHARACTER_ELEMENT;
7958 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007959
7960 switch (GetElementsKind()) {
7961 case FAST_ELEMENTS: {
7962 uint32_t length = IsJSArray() ?
7963 static_cast<uint32_t>
7964 (Smi::cast(JSArray::cast(this)->length())->value()) :
7965 static_cast<uint32_t>(FixedArray::cast(elements())->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007966 if ((index < length) &&
7967 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7968 return FAST_ELEMENT;
7969 }
7970 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007971 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007972 case FAST_DOUBLE_ELEMENTS: {
7973 uint32_t length = IsJSArray() ?
7974 static_cast<uint32_t>
7975 (Smi::cast(JSArray::cast(this)->length())->value()) :
7976 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
7977 if ((index < length) &&
7978 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
7979 return FAST_ELEMENT;
7980 }
7981 break;
7982 }
Steve Block44f0eee2011-05-26 01:26:41 +01007983 case EXTERNAL_PIXEL_ELEMENTS: {
7984 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007985 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
7986 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007987 }
Steve Block3ce2e202009-11-05 08:53:23 +00007988 case EXTERNAL_BYTE_ELEMENTS:
7989 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7990 case EXTERNAL_SHORT_ELEMENTS:
7991 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7992 case EXTERNAL_INT_ELEMENTS:
7993 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00007994 case EXTERNAL_FLOAT_ELEMENTS:
7995 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00007996 ExternalArray* array = ExternalArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007997 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
7998 break;
Steve Block3ce2e202009-11-05 08:53:23 +00007999 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008000 case DICTIONARY_ELEMENTS: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008001 if (element_dictionary()->FindEntry(index) !=
Ben Murdochc7cc0282012-03-05 14:35:55 +00008002 SeededNumberDictionary::kNotFound) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008003 return DICTIONARY_ELEMENT;
8004 }
8005 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008006 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008007 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8008 // Aliased parameters and non-aliased elements in a fast backing store
8009 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
8010 // backing store behave as DICTIONARY_ELEMENT.
8011 FixedArray* parameter_map = FixedArray::cast(elements());
8012 uint32_t length = parameter_map->length();
8013 Object* probe =
8014 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
8015 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8016 // If not aliased, check the arguments.
8017 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8018 if (arguments->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008019 SeededNumberDictionary* dictionary =
8020 SeededNumberDictionary::cast(arguments);
8021 if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008022 return DICTIONARY_ELEMENT;
8023 }
8024 } else {
8025 length = arguments->length();
8026 probe = (index < length) ? arguments->get(index) : NULL;
8027 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8028 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008029 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008030 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008031 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008032
8033 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00008034}
8035
8036
Ben Murdoch85b71792012-04-11 18:30:58 +01008037bool JSObject::HasElementInElements(FixedArray* elements,
8038 ElementsKind kind,
8039 uint32_t index) {
8040 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
8041 if (kind == FAST_ELEMENTS) {
8042 int length = IsJSArray()
8043 ? Smi::cast(JSArray::cast(this)->length())->value()
8044 : elements->length();
8045 if (index < static_cast<uint32_t>(length) &&
8046 !elements->get(index)->IsTheHole()) {
8047 return true;
8048 }
8049 } else {
8050 if (SeededNumberDictionary::cast(elements)->FindEntry(index) !=
8051 SeededNumberDictionary::kNotFound) {
8052 return true;
8053 }
8054 }
8055 return false;
8056}
8057
8058
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008059bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008060 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008061 if (IsAccessCheckNeeded()) {
8062 Heap* heap = GetHeap();
8063 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8064 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8065 return false;
8066 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008067 }
8068
8069 // Check for lookup interceptor
8070 if (HasIndexedInterceptor()) {
8071 return HasElementWithInterceptor(receiver, index);
8072 }
8073
Ben Murdoch85b71792012-04-11 18:30:58 +01008074 ElementsKind kind = GetElementsKind();
8075 switch (kind) {
8076 case FAST_ELEMENTS: {
8077 uint32_t length = IsJSArray() ?
8078 static_cast<uint32_t>
8079 (Smi::cast(JSArray::cast(this)->length())->value()) :
8080 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8081 if ((index < length) &&
8082 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
8083 break;
8084 }
8085 case FAST_DOUBLE_ELEMENTS: {
8086 uint32_t length = IsJSArray() ?
8087 static_cast<uint32_t>
8088 (Smi::cast(JSArray::cast(this)->length())->value()) :
8089 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8090 if ((index < length) &&
8091 !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
8092 break;
8093 }
8094 case EXTERNAL_PIXEL_ELEMENTS: {
8095 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
8096 if (index < static_cast<uint32_t>(pixels->length())) {
8097 return true;
8098 }
8099 break;
8100 }
8101 case EXTERNAL_BYTE_ELEMENTS:
8102 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8103 case EXTERNAL_SHORT_ELEMENTS:
8104 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8105 case EXTERNAL_INT_ELEMENTS:
8106 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8107 case EXTERNAL_FLOAT_ELEMENTS:
8108 case EXTERNAL_DOUBLE_ELEMENTS: {
8109 ExternalArray* array = ExternalArray::cast(elements());
8110 if (index < static_cast<uint32_t>(array->length())) {
8111 return true;
8112 }
8113 break;
8114 }
8115 case DICTIONARY_ELEMENTS: {
8116 if (element_dictionary()->FindEntry(index)
8117 != SeededNumberDictionary::kNotFound) {
8118 return true;
8119 }
8120 break;
8121 }
8122 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8123 FixedArray* parameter_map = FixedArray::cast(elements());
8124 uint32_t length = parameter_map->length();
8125 Object* probe =
8126 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
8127 if (probe != NULL && !probe->IsTheHole()) return true;
8128
8129 // Not a mapped parameter, check the arguments.
8130 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8131 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
8132 if (HasElementInElements(arguments, kind, index)) return true;
8133 break;
8134 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008135 }
8136
8137 // Handle [] on String objects.
8138 if (this->IsStringObjectWithCharacterAt(index)) return true;
8139
8140 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01008141 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008142 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8143}
8144
8145
John Reck59135872010-11-02 12:39:01 -07008146MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01008147 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008148 StrictModeFlag strict_mode,
Ben Murdoch85b71792012-04-11 18:30:58 +01008149 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01008150 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008151 // Make sure that the top context does not change when doing
8152 // callbacks or interceptor calls.
8153 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008154 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008155 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8156 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01008157 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008158 if (!interceptor->setter()->IsUndefined()) {
8159 v8::IndexedPropertySetter setter =
8160 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +01008161 LOG(isolate,
8162 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
8163 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008164 v8::AccessorInfo info(args.end());
8165 v8::Handle<v8::Value> result;
8166 {
8167 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008168 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008169 result = setter(index, v8::Utils::ToLocal(value_handle), info);
8170 }
Steve Block44f0eee2011-05-26 01:26:41 +01008171 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008172 if (!result.IsEmpty()) return *value_handle;
8173 }
John Reck59135872010-11-02 12:39:01 -07008174 MaybeObject* raw_result =
Steve Block9fac8402011-05-12 15:51:54 +01008175 this_handle->SetElementWithoutInterceptor(index,
8176 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008177 strict_mode,
Ben Murdoch85b71792012-04-11 18:30:58 +01008178 check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01008179 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008180 return raw_result;
8181}
8182
8183
John Reck59135872010-11-02 12:39:01 -07008184MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
8185 Object* structure,
8186 uint32_t index,
8187 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01008188 Isolate* isolate = GetIsolate();
Ben Murdoch257744e2011-11-30 15:57:28 +00008189 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01008190
8191 // api style callbacks.
8192 if (structure->IsAccessorInfo()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00008193 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01008194 Object* fun_obj = data->getter();
8195 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Steve Block44f0eee2011-05-26 01:26:41 +01008196 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008197 Handle<JSObject> self(JSObject::cast(receiver));
8198 Handle<JSObject> holder_handle(JSObject::cast(holder));
Steve Block44f0eee2011-05-26 01:26:41 +01008199 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008200 Handle<String> key = isolate->factory()->NumberToString(number);
Steve Block44f0eee2011-05-26 01:26:41 +01008201 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
8202 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01008203 v8::AccessorInfo info(args.end());
8204 v8::Handle<v8::Value> result;
8205 {
8206 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008207 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01008208 result = call_fun(v8::Utils::ToLocal(key), info);
8209 }
Steve Block44f0eee2011-05-26 01:26:41 +01008210 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8211 if (result.IsEmpty()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008212 return *v8::Utils::OpenHandle(*result);
8213 }
8214
8215 // __defineGetter__ callback
Ben Murdoch85b71792012-04-11 18:30:58 +01008216 if (structure->IsFixedArray()) {
8217 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
8218 if (getter->IsJSFunction()) {
8219 return Object::GetPropertyWithDefinedGetter(receiver,
8220 JSFunction::cast(getter));
Leon Clarkef7060e22010-06-03 12:02:55 +01008221 }
8222 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +01008223 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008224 }
8225
8226 UNREACHABLE();
8227 return NULL;
8228}
8229
8230
John Reck59135872010-11-02 12:39:01 -07008231MaybeObject* JSObject::SetElementWithCallback(Object* structure,
8232 uint32_t index,
8233 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008234 JSObject* holder,
8235 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01008236 Isolate* isolate = GetIsolate();
8237 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008238
8239 // We should never get here to initialize a const with the hole
8240 // value since a const declaration would conflict with the setter.
8241 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01008242 Handle<Object> value_handle(value, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008243
8244 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00008245 // data structure used to store the callbacks. Eventually foreign
Leon Clarkef7060e22010-06-03 12:02:55 +01008246 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00008247 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01008248
8249 if (structure->IsAccessorInfo()) {
8250 // api style callbacks
Ben Murdoch257744e2011-11-30 15:57:28 +00008251 Handle<JSObject> self(this);
8252 Handle<JSObject> holder_handle(JSObject::cast(holder));
8253 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01008254 Object* call_obj = data->setter();
8255 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
8256 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +01008257 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8258 Handle<String> key(isolate->factory()->NumberToString(number));
Ben Murdoch257744e2011-11-30 15:57:28 +00008259 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
8260 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01008261 v8::AccessorInfo info(args.end());
8262 {
8263 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008264 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01008265 call_fun(v8::Utils::ToLocal(key),
8266 v8::Utils::ToLocal(value_handle),
8267 info);
8268 }
Steve Block44f0eee2011-05-26 01:26:41 +01008269 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008270 return *value_handle;
8271 }
8272
Ben Murdoch85b71792012-04-11 18:30:58 +01008273 if (structure->IsFixedArray()) {
8274 Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
8275 if (setter->IsJSFunction()) {
8276 return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value);
Leon Clarkef7060e22010-06-03 12:02:55 +01008277 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008278 if (strict_mode == kNonStrictMode) {
8279 return value;
8280 }
Steve Block44f0eee2011-05-26 01:26:41 +01008281 Handle<Object> holder_handle(holder, isolate);
8282 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Leon Clarkef7060e22010-06-03 12:02:55 +01008283 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01008284 return isolate->Throw(
8285 *isolate->factory()->NewTypeError("no_setter_in_callback",
8286 HandleVector(args, 2)));
Leon Clarkef7060e22010-06-03 12:02:55 +01008287 }
8288 }
8289
8290 UNREACHABLE();
8291 return NULL;
8292}
8293
8294
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008295bool JSObject::HasFastArgumentsElements() {
8296 Heap* heap = GetHeap();
8297 if (!elements()->IsFixedArray()) return false;
8298 FixedArray* elements = FixedArray::cast(this->elements());
8299 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8300 return false;
8301 }
8302 FixedArray* arguments = FixedArray::cast(elements->get(1));
8303 return !arguments->IsDictionary();
8304}
8305
8306
8307bool JSObject::HasDictionaryArgumentsElements() {
8308 Heap* heap = GetHeap();
8309 if (!elements()->IsFixedArray()) return false;
8310 FixedArray* elements = FixedArray::cast(this->elements());
8311 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8312 return false;
8313 }
8314 FixedArray* arguments = FixedArray::cast(elements->get(1));
8315 return arguments->IsDictionary();
8316}
8317
8318
Steve Blocka7e24c12009-10-30 11:49:00 +00008319// Adding n elements in fast case is O(n*n).
8320// Note: revisit design to have dual undefined values to capture absent
8321// elements.
Steve Block9fac8402011-05-12 15:51:54 +01008322MaybeObject* JSObject::SetFastElement(uint32_t index,
8323 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008324 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008325 bool check_prototype) {
Ben Murdoch85b71792012-04-11 18:30:58 +01008326 ASSERT(HasFastElements() || HasFastArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008327
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008328 FixedArray* backing_store = FixedArray::cast(elements());
8329 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
8330 backing_store = FixedArray::cast(backing_store->get(1));
8331 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +01008332 Object* writable;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008333 MaybeObject* maybe = EnsureWritableFastElements();
Ben Murdoch85b71792012-04-11 18:30:58 +01008334 if (!maybe->ToObject(&writable)) return maybe;
8335 backing_store = FixedArray::cast(writable);
John Reck59135872010-11-02 12:39:01 -07008336 }
Ben Murdoch85b71792012-04-11 18:30:58 +01008337 uint32_t length = static_cast<uint32_t>(backing_store->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008338
Steve Block9fac8402011-05-12 15:51:54 +01008339 if (check_prototype &&
Ben Murdoch85b71792012-04-11 18:30:58 +01008340 (index >= length || backing_store->get(index)->IsTheHole())) {
Steve Block1e0659c2011-05-24 12:43:12 +01008341 bool found;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008342 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8343 value,
8344 &found,
8345 strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +01008346 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00008347 }
8348
Ben Murdoch85b71792012-04-11 18:30:58 +01008349 // Check whether there is extra space in fixed array.
8350 if (index < length) {
8351 backing_store->set(index, value);
8352 if (IsJSArray()) {
8353 // Update the length of the array if needed.
8354 uint32_t array_length = 0;
8355 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
8356 if (index >= array_length) {
8357 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008358 }
8359 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008360 return value;
8361 }
Ben Murdoch85b71792012-04-11 18:30:58 +01008362
8363 // Allow gap in fast case.
8364 if ((index - length) < kMaxGap) {
8365 // Try allocating extra space.
8366 int new_capacity = NewElementsCapacity(index + 1);
8367 if (!ShouldConvertToSlowElements(new_capacity)) {
8368 ASSERT(static_cast<uint32_t>(new_capacity) > index);
8369 Object* new_elements;
8370 MaybeObject* maybe =
8371 SetFastElementsCapacityAndLength(new_capacity, index + 1);
8372 if (!maybe->ToObject(&new_elements)) return maybe;
8373 FixedArray::cast(new_elements)->set(index, value);
8374 return value;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008375 }
8376 }
Ben Murdoch85b71792012-04-11 18:30:58 +01008377
8378 // Otherwise default to slow case.
8379 MaybeObject* result = NormalizeElements();
8380 if (result->IsFailure()) return result;
8381 return SetDictionaryElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008382}
8383
8384
8385MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
8386 Object* value,
8387 StrictModeFlag strict_mode,
Ben Murdoch85b71792012-04-11 18:30:58 +01008388 bool check_prototype) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008389 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
8390 Isolate* isolate = GetIsolate();
8391 Heap* heap = isolate->heap();
8392
8393 // Insert element in the dictionary.
8394 FixedArray* elements = FixedArray::cast(this->elements());
8395 bool is_arguments =
8396 (elements->map() == heap->non_strict_arguments_elements_map());
Ben Murdochc7cc0282012-03-05 14:35:55 +00008397 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008398 if (is_arguments) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008399 dictionary = SeededNumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008400 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008401 dictionary = SeededNumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008402 }
8403
8404 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00008405 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008406 Object* element = dictionary->ValueAt(entry);
8407 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdoch85b71792012-04-11 18:30:58 +01008408 if (details.type() == CALLBACKS) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008409 return SetElementWithCallback(element, index, value, this, strict_mode);
8410 } else {
8411 dictionary->UpdateMaxNumberKey(index);
Ben Murdoch85b71792012-04-11 18:30:58 +01008412 // If put fails in strict mode, throw an exception.
8413 if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) {
8414 Handle<Object> holder(this);
8415 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8416 Handle<Object> args[2] = { number, holder };
8417 Handle<Object> error =
8418 isolate->factory()->NewTypeError("strict_read_only_property",
8419 HandleVector(args, 2));
8420 return isolate->Throw(*error);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008421 }
8422 }
8423 } else {
8424 // Index not already used. Look for an accessor in the prototype chain.
8425 if (check_prototype) {
8426 bool found;
8427 MaybeObject* result =
8428 SetElementWithCallbackSetterInPrototypes(
8429 index, value, &found, strict_mode);
8430 if (found) return result;
8431 }
8432 // When we set the is_extensible flag to false we always force the
8433 // element into dictionary mode (and force them to stay there).
8434 if (!map()->is_extensible()) {
8435 if (strict_mode == kNonStrictMode) {
8436 return isolate->heap()->undefined_value();
8437 } else {
8438 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8439 Handle<String> name = isolate->factory()->NumberToString(number);
8440 Handle<Object> args[1] = { name };
8441 Handle<Object> error =
8442 isolate->factory()->NewTypeError("object_not_extensible",
8443 HandleVector(args, 1));
8444 return isolate->Throw(*error);
8445 }
8446 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008447 FixedArrayBase* new_dictionary;
Ben Murdoch85b71792012-04-11 18:30:58 +01008448 MaybeObject* maybe = dictionary->AtNumberPut(index, value);
8449 if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
Ben Murdochc7cc0282012-03-05 14:35:55 +00008450 if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008451 if (is_arguments) {
8452 elements->set(1, new_dictionary);
8453 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008454 set_elements(new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008455 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00008456 dictionary = SeededNumberDictionary::cast(new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008457 }
8458 }
8459
8460 // Update the array length if this JSObject is an array.
8461 if (IsJSArray()) {
8462 MaybeObject* result =
8463 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
8464 if (result->IsFailure()) return result;
8465 }
8466
8467 // Attempt to put this object back in fast case.
8468 if (ShouldConvertToFastElements()) {
8469 uint32_t new_length = 0;
8470 if (IsJSArray()) {
8471 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
8472 } else {
8473 new_length = dictionary->max_number_key() + 1;
8474 }
Ben Murdoch85b71792012-04-11 18:30:58 +01008475 MaybeObject* result = CanConvertToFastDoubleElements()
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008476 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
Ben Murdoch85b71792012-04-11 18:30:58 +01008477 : SetFastElementsCapacityAndLength(new_length, new_length);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008478 if (result->IsFailure()) return result;
8479#ifdef DEBUG
8480 if (FLAG_trace_normalization) {
8481 PrintF("Object elements are fast case again:\n");
8482 Print();
8483 }
8484#endif
8485 }
8486 return value;
8487}
8488
8489
8490MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
8491 uint32_t index,
8492 Object* value,
8493 StrictModeFlag strict_mode,
8494 bool check_prototype) {
8495 ASSERT(HasFastDoubleElements());
8496
Ben Murdoch85b71792012-04-11 18:30:58 +01008497 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8498 uint32_t elms_length = static_cast<uint32_t>(elms->length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008499
8500 // If storing to an element that isn't in the array, pass the store request
8501 // up the prototype chain before storing in the receiver's elements.
8502 if (check_prototype &&
Ben Murdoch85b71792012-04-11 18:30:58 +01008503 (index >= elms_length || elms->is_the_hole(index))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008504 bool found;
8505 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8506 value,
8507 &found,
8508 strict_mode);
8509 if (found) return result;
8510 }
8511
8512 // If the value object is not a heap number, switch to fast elements and try
8513 // again.
8514 bool value_is_smi = value->IsSmi();
8515 if (!value->IsNumber()) {
8516 Object* obj;
8517 uint32_t length = elms_length;
8518 if (IsJSArray()) {
8519 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
8520 }
Ben Murdoch85b71792012-04-11 18:30:58 +01008521 MaybeObject* maybe_obj =
8522 SetFastElementsCapacityAndLength(elms_length, length);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008523 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Ben Murdoch85b71792012-04-11 18:30:58 +01008524 return SetFastElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008525 }
8526
8527 double double_value = value_is_smi
8528 ? static_cast<double>(Smi::cast(value)->value())
8529 : HeapNumber::cast(value)->value();
8530
8531 // Check whether there is extra space in the fixed array.
Steve Blocka7e24c12009-10-30 11:49:00 +00008532 if (index < elms_length) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008533 elms->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00008534 if (IsJSArray()) {
8535 // Update the length of the array if needed.
8536 uint32_t array_length = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008537 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00008538 if (index >= array_length) {
Leon Clarke4515c472010-02-03 11:58:03 +00008539 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00008540 }
8541 }
8542 return value;
8543 }
8544
8545 // Allow gap in fast case.
8546 if ((index - elms_length) < kMaxGap) {
8547 // Try allocating extra space.
8548 int new_capacity = NewElementsCapacity(index+1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008549 if (!ShouldConvertToSlowElements(new_capacity)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008550 ASSERT(static_cast<uint32_t>(new_capacity) > index);
John Reck59135872010-11-02 12:39:01 -07008551 Object* obj;
8552 { MaybeObject* maybe_obj =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008553 SetFastDoubleElementsCapacityAndLength(new_capacity,
8554 index + 1);
John Reck59135872010-11-02 12:39:01 -07008555 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8556 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008557 FixedDoubleArray::cast(elements())->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00008558 return value;
8559 }
8560 }
8561
8562 // Otherwise default to slow case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008563 ASSERT(HasFastDoubleElements());
8564 ASSERT(map()->has_fast_double_elements());
8565 ASSERT(elements()->IsFixedDoubleArray());
John Reck59135872010-11-02 12:39:01 -07008566 Object* obj;
8567 { MaybeObject* maybe_obj = NormalizeElements();
8568 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8569 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008570 ASSERT(HasDictionaryElements());
Ben Murdoch85b71792012-04-11 18:30:58 +01008571 return SetElement(index, value, strict_mode, check_prototype);
Ben Murdochc7cc0282012-03-05 14:35:55 +00008572}
8573
8574
Steve Block9fac8402011-05-12 15:51:54 +01008575MaybeObject* JSObject::SetElement(uint32_t index,
8576 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008577 StrictModeFlag strict_mode,
Ben Murdoch85b71792012-04-11 18:30:58 +01008578 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008579 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008580 if (IsAccessCheckNeeded()) {
8581 Heap* heap = GetHeap();
8582 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008583 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01008584 Handle<Object> value_handle(value);
8585 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
8586 return *value_handle;
8587 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008588 }
8589
8590 if (IsJSGlobalProxy()) {
8591 Object* proto = GetPrototype();
8592 if (proto->IsNull()) return value;
8593 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008594 return JSObject::cast(proto)->SetElement(index,
8595 value,
8596 strict_mode,
Ben Murdoch85b71792012-04-11 18:30:58 +01008597 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008598 }
8599
8600 // Check for lookup interceptor
8601 if (HasIndexedInterceptor()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008602 return SetElementWithInterceptor(index,
8603 value,
8604 strict_mode,
Ben Murdoch85b71792012-04-11 18:30:58 +01008605 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008606 }
8607
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008608 return SetElementWithoutInterceptor(index,
8609 value,
8610 strict_mode,
Ben Murdoch85b71792012-04-11 18:30:58 +01008611 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008612}
8613
8614
John Reck59135872010-11-02 12:39:01 -07008615MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01008616 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008617 StrictModeFlag strict_mode,
Ben Murdoch85b71792012-04-11 18:30:58 +01008618 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01008619 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008620 switch (GetElementsKind()) {
8621 case FAST_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008622 return SetFastElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008623 case FAST_DOUBLE_ELEMENTS:
8624 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01008625 case EXTERNAL_PIXEL_ELEMENTS: {
8626 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008627 return pixels->SetValue(index, value);
8628 }
Steve Block3ce2e202009-11-05 08:53:23 +00008629 case EXTERNAL_BYTE_ELEMENTS: {
8630 ExternalByteArray* array = ExternalByteArray::cast(elements());
8631 return array->SetValue(index, value);
8632 }
8633 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8634 ExternalUnsignedByteArray* array =
8635 ExternalUnsignedByteArray::cast(elements());
8636 return array->SetValue(index, value);
8637 }
8638 case EXTERNAL_SHORT_ELEMENTS: {
8639 ExternalShortArray* array = ExternalShortArray::cast(elements());
8640 return array->SetValue(index, value);
8641 }
8642 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8643 ExternalUnsignedShortArray* array =
8644 ExternalUnsignedShortArray::cast(elements());
8645 return array->SetValue(index, value);
8646 }
8647 case EXTERNAL_INT_ELEMENTS: {
8648 ExternalIntArray* array = ExternalIntArray::cast(elements());
8649 return array->SetValue(index, value);
8650 }
8651 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8652 ExternalUnsignedIntArray* array =
8653 ExternalUnsignedIntArray::cast(elements());
8654 return array->SetValue(index, value);
8655 }
8656 case EXTERNAL_FLOAT_ELEMENTS: {
8657 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
8658 return array->SetValue(index, value);
8659 }
Ben Murdoch257744e2011-11-30 15:57:28 +00008660 case EXTERNAL_DOUBLE_ELEMENTS: {
8661 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
8662 return array->SetValue(index, value);
8663 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008664 case DICTIONARY_ELEMENTS:
Ben Murdoch85b71792012-04-11 18:30:58 +01008665 return SetDictionaryElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008666 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8667 FixedArray* parameter_map = FixedArray::cast(elements());
8668 uint32_t length = parameter_map->length();
8669 Object* probe =
8670 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
8671 if (probe != NULL && !probe->IsTheHole()) {
8672 Context* context = Context::cast(parameter_map->get(0));
8673 int context_index = Smi::cast(probe)->value();
8674 ASSERT(!context->get(context_index)->IsTheHole());
8675 context->set(context_index, value);
Ben Murdoch85b71792012-04-11 18:30:58 +01008676 return value;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01008677 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +01008678 // Object is not mapped, defer to the arguments.
8679 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8680 if (arguments->IsDictionary()) {
8681 return SetDictionaryElement(index, value, strict_mode,
8682 check_prototype);
8683 } else {
8684 return SetFastElement(index, value, strict_mode, check_prototype);
8685 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01008686 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008687 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008688 }
8689 // All possible cases have been handled above. Add a return to avoid the
8690 // complaints from the compiler.
8691 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01008692 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008693}
8694
8695
John Reck59135872010-11-02 12:39:01 -07008696MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
8697 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008698 uint32_t old_len = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008699 CHECK(length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +00008700 // Check to see if we need to update the length. For now, we make
8701 // sure that the length stays within 32-bits (unsigned).
8702 if (index >= old_len && index != 0xffffffff) {
John Reck59135872010-11-02 12:39:01 -07008703 Object* len;
8704 { MaybeObject* maybe_len =
Steve Block44f0eee2011-05-26 01:26:41 +01008705 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
John Reck59135872010-11-02 12:39:01 -07008706 if (!maybe_len->ToObject(&len)) return maybe_len;
8707 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008708 set_length(len);
8709 }
8710 return value;
8711}
8712
8713
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008714MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07008715 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01008716 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008717 // Make sure that the top context does not change when doing
8718 // callbacks or interceptor calls.
8719 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008720 HandleScope scope(isolate);
8721 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
8722 Handle<Object> this_handle(receiver, isolate);
8723 Handle<JSObject> holder_handle(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008724 if (!interceptor->getter()->IsUndefined()) {
8725 v8::IndexedPropertyGetter getter =
8726 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008727 LOG(isolate,
8728 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
8729 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008730 v8::AccessorInfo info(args.end());
8731 v8::Handle<v8::Value> result;
8732 {
8733 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008734 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008735 result = getter(index, info);
8736 }
Steve Block44f0eee2011-05-26 01:26:41 +01008737 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008738 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
8739 }
8740
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008741 Heap* heap = holder_handle->GetHeap();
8742 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
Ben Murdoch85b71792012-04-11 18:30:58 +01008743 MaybeObject* raw_result = handler->Get(holder_handle->elements(),
8744 index,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008745 *holder_handle,
Ben Murdoch85b71792012-04-11 18:30:58 +01008746 *this_handle);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008747 if (raw_result != heap->the_hole_value()) return raw_result;
8748
Steve Block44f0eee2011-05-26 01:26:41 +01008749 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008750
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008751 Object* pt = holder_handle->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01008752 if (pt == heap->null_value()) return heap->undefined_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008753 return pt->GetElementWithReceiver(*this_handle, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00008754}
8755
8756
8757bool JSObject::HasDenseElements() {
8758 int capacity = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008759 int used = 0;
8760 GetElementsCapacityAndUsage(&capacity, &used);
8761 return (capacity == 0) || (used > (capacity / 2));
8762}
8763
8764
8765void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
8766 *capacity = 0;
8767 *used = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00008768
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008769 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
8770 FixedArray* backing_store = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00008771 switch (GetElementsKind()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008772 case NON_STRICT_ARGUMENTS_ELEMENTS:
8773 backing_store_base =
8774 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
8775 backing_store = FixedArray::cast(backing_store_base);
8776 if (backing_store->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008777 SeededNumberDictionary* dictionary =
8778 SeededNumberDictionary::cast(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008779 *capacity = dictionary->Capacity();
8780 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008781 break;
8782 }
8783 // Fall through.
8784 case FAST_ELEMENTS:
8785 backing_store = FixedArray::cast(backing_store_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008786 *capacity = backing_store->length();
8787 for (int i = 0; i < *capacity; ++i) {
8788 if (!backing_store->get(i)->IsTheHole()) ++(*used);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008789 }
8790 break;
8791 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008792 SeededNumberDictionary* dictionary =
8793 SeededNumberDictionary::cast(FixedArray::cast(elements()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008794 *capacity = dictionary->Capacity();
8795 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008796 break;
8797 }
8798 case FAST_DOUBLE_ELEMENTS: {
8799 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008800 *capacity = elms->length();
8801 for (int i = 0; i < *capacity; i++) {
8802 if (!elms->is_the_hole(i)) ++(*used);
Steve Blocka7e24c12009-10-30 11:49:00 +00008803 }
8804 break;
8805 }
Steve Block3ce2e202009-11-05 08:53:23 +00008806 case EXTERNAL_BYTE_ELEMENTS:
8807 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8808 case EXTERNAL_SHORT_ELEMENTS:
8809 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8810 case EXTERNAL_INT_ELEMENTS:
8811 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008812 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008813 case EXTERNAL_DOUBLE_ELEMENTS:
8814 case EXTERNAL_PIXEL_ELEMENTS:
8815 // External arrays are considered 100% used.
8816 ExternalArray* external_array = ExternalArray::cast(elements());
8817 *capacity = external_array->length();
8818 *used = external_array->length();
8819 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008820 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008821}
8822
8823
8824bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008825 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
8826 kMaxUncheckedFastElementsLength);
8827 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
8828 (new_capacity <= kMaxUncheckedFastElementsLength &&
8829 GetHeap()->InNewSpace(this))) {
8830 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008831 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008832 // If the fast-case backing storage takes up roughly three times as
8833 // much space (in machine words) as a dictionary backing storage
8834 // would, the object should have slow elements.
8835 int old_capacity = 0;
8836 int used_elements = 0;
8837 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdochc7cc0282012-03-05 14:35:55 +00008838 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
8839 SeededNumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008840 return 3 * dictionary_size <= new_capacity;
Steve Blocka7e24c12009-10-30 11:49:00 +00008841}
8842
8843
8844bool JSObject::ShouldConvertToFastElements() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008845 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008846 // If the elements are sparse, we should not go back to fast case.
8847 if (!HasDenseElements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008848 // An object requiring access checks is never allowed to have fast
8849 // elements. If it had fast elements we would skip security checks.
8850 if (IsAccessCheckNeeded()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008851
8852 FixedArray* elements = FixedArray::cast(this->elements());
Ben Murdochc7cc0282012-03-05 14:35:55 +00008853 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008854 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008855 dictionary = SeededNumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008856 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008857 dictionary = SeededNumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008858 }
8859 // If an element has been added at a very high index in the elements
8860 // dictionary, we cannot go back to fast case.
8861 if (dictionary->requires_slow_elements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008862 // If the dictionary backing storage takes up roughly half as much
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008863 // space (in machine words) as a fast-case backing storage would,
8864 // the object should have fast elements.
8865 uint32_t array_size = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00008866 if (IsJSArray()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008867 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
Steve Blocka7e24c12009-10-30 11:49:00 +00008868 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008869 array_size = dictionary->max_number_key();
Steve Blocka7e24c12009-10-30 11:49:00 +00008870 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008871 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
Ben Murdochc7cc0282012-03-05 14:35:55 +00008872 SeededNumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008873 return 2 * dictionary_size >= array_size;
Steve Blocka7e24c12009-10-30 11:49:00 +00008874}
8875
8876
Ben Murdoch85b71792012-04-11 18:30:58 +01008877bool JSObject::CanConvertToFastDoubleElements() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008878 if (FLAG_unbox_double_arrays) {
8879 ASSERT(HasDictionaryElements());
Ben Murdochc7cc0282012-03-05 14:35:55 +00008880 SeededNumberDictionary* dictionary =
8881 SeededNumberDictionary::cast(elements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008882 for (int i = 0; i < dictionary->Capacity(); i++) {
8883 Object* key = dictionary->KeyAt(i);
8884 if (key->IsNumber()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01008885 if (!dictionary->ValueAt(i)->IsNumber()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008886 }
8887 }
Ben Murdoch85b71792012-04-11 18:30:58 +01008888 return true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008889 } else {
8890 return false;
8891 }
8892}
8893
8894
Steve Blocka7e24c12009-10-30 11:49:00 +00008895// Certain compilers request function template instantiation when they
8896// see the definition of the other template functions in the
8897// class. This requires us to have the template functions put
8898// together, so even though this function belongs in objects-debug.cc,
8899// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +01008900#ifdef OBJECT_PRINT
Steve Blocka7e24c12009-10-30 11:49:00 +00008901template<typename Shape, typename Key>
Ben Murdochb0fe1622011-05-05 13:52:32 +01008902void Dictionary<Shape, Key>::Print(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008903 int capacity = HashTable<Shape, Key>::Capacity();
8904 for (int i = 0; i < capacity; i++) {
8905 Object* k = HashTable<Shape, Key>::KeyAt(i);
8906 if (HashTable<Shape, Key>::IsKey(k)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008907 PrintF(out, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00008908 if (k->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008909 String::cast(k)->StringPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00008910 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008911 k->ShortPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00008912 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008913 PrintF(out, ": ");
8914 ValueAt(i)->ShortPrint(out);
8915 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00008916 }
8917 }
8918}
8919#endif
8920
8921
8922template<typename Shape, typename Key>
8923void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
8924 int pos = 0;
8925 int capacity = HashTable<Shape, Key>::Capacity();
Leon Clarke4515c472010-02-03 11:58:03 +00008926 AssertNoAllocation no_gc;
8927 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008928 for (int i = 0; i < capacity; i++) {
8929 Object* k = Dictionary<Shape, Key>::KeyAt(i);
8930 if (Dictionary<Shape, Key>::IsKey(k)) {
8931 elements->set(pos++, ValueAt(i), mode);
8932 }
8933 }
8934 ASSERT(pos == elements->length());
8935}
8936
8937
8938InterceptorInfo* JSObject::GetNamedInterceptor() {
8939 ASSERT(map()->has_named_interceptor());
8940 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01008941 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00008942 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01008943 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00008944 return InterceptorInfo::cast(result);
8945}
8946
8947
8948InterceptorInfo* JSObject::GetIndexedInterceptor() {
8949 ASSERT(map()->has_indexed_interceptor());
8950 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01008951 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00008952 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01008953 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00008954 return InterceptorInfo::cast(result);
8955}
8956
8957
John Reck59135872010-11-02 12:39:01 -07008958MaybeObject* JSObject::GetPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008959 JSReceiver* receiver,
John Reck59135872010-11-02 12:39:01 -07008960 String* name,
8961 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008962 // Check local property in holder, ignore interceptor.
Ben Murdoch85b71792012-04-11 18:30:58 +01008963 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +00008964 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008965 if (result.IsProperty()) {
8966 return GetProperty(receiver, &result, name, attributes);
8967 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008968 // Continue searching via the prototype chain.
8969 Object* pt = GetPrototype();
8970 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +01008971 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008972 return pt->GetPropertyWithReceiver(receiver, name, attributes);
8973}
8974
8975
John Reck59135872010-11-02 12:39:01 -07008976MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008977 JSReceiver* receiver,
Steve Blockd0582a62009-12-15 09:54:21 +00008978 String* name,
8979 PropertyAttributes* attributes) {
8980 // Check local property in holder, ignore interceptor.
Ben Murdoch85b71792012-04-11 18:30:58 +01008981 LookupResult result;
Steve Blockd0582a62009-12-15 09:54:21 +00008982 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008983 if (result.IsProperty()) {
8984 return GetProperty(receiver, &result, name, attributes);
8985 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01008986 return GetHeap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00008987}
8988
8989
John Reck59135872010-11-02 12:39:01 -07008990MaybeObject* JSObject::GetPropertyWithInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008991 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00008992 String* name,
8993 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01008994 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008995 InterceptorInfo* interceptor = GetNamedInterceptor();
Steve Block44f0eee2011-05-26 01:26:41 +01008996 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008997 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00008998 Handle<JSObject> holder_handle(this);
8999 Handle<String> name_handle(name);
9000
9001 if (!interceptor->getter()->IsUndefined()) {
9002 v8::NamedPropertyGetter getter =
9003 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01009004 LOG(isolate,
9005 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
9006 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00009007 v8::AccessorInfo info(args.end());
9008 v8::Handle<v8::Value> result;
9009 {
9010 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01009011 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009012 result = getter(v8::Utils::ToLocal(name_handle), info);
9013 }
Steve Block44f0eee2011-05-26 01:26:41 +01009014 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009015 if (!result.IsEmpty()) {
9016 *attributes = NONE;
9017 return *v8::Utils::OpenHandle(*result);
9018 }
9019 }
9020
John Reck59135872010-11-02 12:39:01 -07009021 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00009022 *receiver_handle,
9023 *name_handle,
9024 attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01009025 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009026 return result;
9027}
9028
9029
9030bool JSObject::HasRealNamedProperty(String* key) {
9031 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009032 if (IsAccessCheckNeeded()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01009033 Heap* heap = GetHeap();
9034 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9035 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009036 return false;
9037 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009038 }
9039
Ben Murdoch85b71792012-04-11 18:30:58 +01009040 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +00009041 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009042 return result.IsProperty() && (result.type() != INTERCEPTOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00009043}
9044
9045
9046bool JSObject::HasRealElementProperty(uint32_t index) {
9047 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009048 if (IsAccessCheckNeeded()) {
9049 Heap* heap = GetHeap();
9050 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
9051 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9052 return false;
9053 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009054 }
9055
9056 // Handle [] on String objects.
9057 if (this->IsStringObjectWithCharacterAt(index)) return true;
9058
9059 switch (GetElementsKind()) {
9060 case FAST_ELEMENTS: {
9061 uint32_t length = IsJSArray() ?
9062 static_cast<uint32_t>(
9063 Smi::cast(JSArray::cast(this)->length())->value()) :
9064 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9065 return (index < length) &&
9066 !FixedArray::cast(elements())->get(index)->IsTheHole();
9067 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009068 case FAST_DOUBLE_ELEMENTS: {
9069 uint32_t length = IsJSArray() ?
9070 static_cast<uint32_t>(
9071 Smi::cast(JSArray::cast(this)->length())->value()) :
9072 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
9073 return (index < length) &&
9074 !FixedDoubleArray::cast(elements())->is_the_hole(index);
9075 break;
9076 }
Steve Block44f0eee2011-05-26 01:26:41 +01009077 case EXTERNAL_PIXEL_ELEMENTS: {
9078 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009079 return index < static_cast<uint32_t>(pixels->length());
9080 }
Steve Block3ce2e202009-11-05 08:53:23 +00009081 case EXTERNAL_BYTE_ELEMENTS:
9082 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9083 case EXTERNAL_SHORT_ELEMENTS:
9084 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9085 case EXTERNAL_INT_ELEMENTS:
9086 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009087 case EXTERNAL_FLOAT_ELEMENTS:
9088 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00009089 ExternalArray* array = ExternalArray::cast(elements());
9090 return index < static_cast<uint32_t>(array->length());
9091 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009092 case DICTIONARY_ELEMENTS: {
9093 return element_dictionary()->FindEntry(index)
Ben Murdochc7cc0282012-03-05 14:35:55 +00009094 != SeededNumberDictionary::kNotFound;
Steve Blocka7e24c12009-10-30 11:49:00 +00009095 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009096 case NON_STRICT_ARGUMENTS_ELEMENTS:
9097 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00009098 break;
9099 }
9100 // All possibilities have been handled above already.
9101 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01009102 return GetHeap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009103}
9104
9105
9106bool JSObject::HasRealNamedCallbackProperty(String* key) {
9107 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009108 if (IsAccessCheckNeeded()) {
Ben Murdoch85b71792012-04-11 18:30:58 +01009109 Heap* heap = GetHeap();
9110 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9111 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009112 return false;
9113 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009114 }
9115
Ben Murdoch85b71792012-04-11 18:30:58 +01009116 LookupResult result;
Steve Blocka7e24c12009-10-30 11:49:00 +00009117 LocalLookupRealNamedProperty(key, &result);
Ben Murdoch85b71792012-04-11 18:30:58 +01009118 return result.IsProperty() && (result.type() == CALLBACKS);
Steve Blocka7e24c12009-10-30 11:49:00 +00009119}
9120
9121
9122int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
Ben Murdoch85b71792012-04-11 18:30:58 +01009123 if (HasFastProperties()) {
9124 DescriptorArray* descs = map()->instance_descriptors();
9125 int result = 0;
9126 for (int i = 0; i < descs->number_of_descriptors(); i++) {
9127 PropertyDetails details(descs->GetDetails(i));
9128 if (details.IsProperty() && (details.attributes() & filter) == 0) {
9129 result++;
9130 }
9131 }
9132 return result;
9133 } else {
9134 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
9135 }
9136}
9137
9138
9139int JSObject::NumberOfEnumProperties() {
9140 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
Steve Blocka7e24c12009-10-30 11:49:00 +00009141}
9142
9143
9144void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
9145 Object* temp = get(i);
9146 set(i, get(j));
9147 set(j, temp);
9148 if (this != numbers) {
9149 temp = numbers->get(i);
Ben Murdoch85b71792012-04-11 18:30:58 +01009150 numbers->set(i, numbers->get(j));
9151 numbers->set(j, temp);
Steve Blocka7e24c12009-10-30 11:49:00 +00009152 }
9153}
9154
9155
9156static void InsertionSortPairs(FixedArray* content,
9157 FixedArray* numbers,
9158 int len) {
9159 for (int i = 1; i < len; i++) {
9160 int j = i;
9161 while (j > 0 &&
9162 (NumberToUint32(numbers->get(j - 1)) >
9163 NumberToUint32(numbers->get(j)))) {
9164 content->SwapPairs(numbers, j - 1, j);
9165 j--;
9166 }
9167 }
9168}
9169
9170
9171void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
9172 // In-place heap sort.
9173 ASSERT(content->length() == numbers->length());
9174
9175 // Bottom-up max-heap construction.
9176 for (int i = 1; i < len; ++i) {
9177 int child_index = i;
9178 while (child_index > 0) {
9179 int parent_index = ((child_index + 1) >> 1) - 1;
9180 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
9181 uint32_t child_value = NumberToUint32(numbers->get(child_index));
9182 if (parent_value < child_value) {
9183 content->SwapPairs(numbers, parent_index, child_index);
9184 } else {
9185 break;
9186 }
9187 child_index = parent_index;
9188 }
9189 }
9190
9191 // Extract elements and create sorted array.
9192 for (int i = len - 1; i > 0; --i) {
9193 // Put max element at the back of the array.
9194 content->SwapPairs(numbers, 0, i);
9195 // Sift down the new top element.
9196 int parent_index = 0;
9197 while (true) {
9198 int child_index = ((parent_index + 1) << 1) - 1;
9199 if (child_index >= i) break;
9200 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
9201 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
9202 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
9203 if (child_index + 1 >= i || child1_value > child2_value) {
9204 if (parent_value > child1_value) break;
9205 content->SwapPairs(numbers, parent_index, child_index);
9206 parent_index = child_index;
9207 } else {
9208 if (parent_value > child2_value) break;
9209 content->SwapPairs(numbers, parent_index, child_index + 1);
9210 parent_index = child_index + 1;
9211 }
9212 }
9213 }
9214}
9215
9216
9217// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
9218void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
9219 ASSERT(this->length() == numbers->length());
9220 // For small arrays, simply use insertion sort.
9221 if (len <= 10) {
9222 InsertionSortPairs(this, numbers, len);
9223 return;
9224 }
9225 // Check the range of indices.
9226 uint32_t min_index = NumberToUint32(numbers->get(0));
9227 uint32_t max_index = min_index;
9228 uint32_t i;
9229 for (i = 1; i < len; i++) {
9230 if (NumberToUint32(numbers->get(i)) < min_index) {
9231 min_index = NumberToUint32(numbers->get(i));
9232 } else if (NumberToUint32(numbers->get(i)) > max_index) {
9233 max_index = NumberToUint32(numbers->get(i));
9234 }
9235 }
9236 if (max_index - min_index + 1 == len) {
9237 // Indices form a contiguous range, unless there are duplicates.
9238 // Do an in-place linear time sort assuming distinct numbers, but
9239 // avoid hanging in case they are not.
9240 for (i = 0; i < len; i++) {
9241 uint32_t p;
9242 uint32_t j = 0;
9243 // While the current element at i is not at its correct position p,
9244 // swap the elements at these two positions.
9245 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
9246 j++ < len) {
9247 SwapPairs(numbers, i, p);
9248 }
9249 }
9250 } else {
9251 HeapSortPairs(this, numbers, len);
9252 return;
9253 }
9254}
9255
9256
9257// Fill in the names of local properties into the supplied storage. The main
9258// purpose of this function is to provide reflection information for the object
9259// mirrors.
9260void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
Ben Murdoch85b71792012-04-11 18:30:58 +01009261 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
Steve Blocka7e24c12009-10-30 11:49:00 +00009262 if (HasFastProperties()) {
9263 DescriptorArray* descs = map()->instance_descriptors();
9264 for (int i = 0; i < descs->number_of_descriptors(); i++) {
9265 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
9266 }
9267 ASSERT(storage->length() >= index);
9268 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009269 property_dictionary()->CopyKeysTo(storage,
9270 index,
9271 StringDictionary::UNSORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +00009272 }
9273}
9274
9275
9276int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
9277 return GetLocalElementKeys(NULL, filter);
9278}
9279
9280
9281int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +00009282 // Fast case for objects with no elements.
9283 if (!IsJSValue() && HasFastElements()) {
9284 uint32_t length = IsJSArray() ?
9285 static_cast<uint32_t>(
9286 Smi::cast(JSArray::cast(this)->length())->value()) :
9287 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9288 if (length == 0) return 0;
9289 }
9290 // Compute the number of enumerable elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00009291 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
9292}
9293
9294
9295int JSObject::GetLocalElementKeys(FixedArray* storage,
9296 PropertyAttributes filter) {
9297 int counter = 0;
9298 switch (GetElementsKind()) {
9299 case FAST_ELEMENTS: {
9300 int length = IsJSArray() ?
9301 Smi::cast(JSArray::cast(this)->length())->value() :
9302 FixedArray::cast(elements())->length();
9303 for (int i = 0; i < length; i++) {
9304 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
9305 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009306 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009307 }
9308 counter++;
9309 }
9310 }
9311 ASSERT(!storage || storage->length() >= counter);
9312 break;
9313 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009314 case FAST_DOUBLE_ELEMENTS: {
9315 int length = IsJSArray() ?
9316 Smi::cast(JSArray::cast(this)->length())->value() :
9317 FixedDoubleArray::cast(elements())->length();
9318 for (int i = 0; i < length; i++) {
9319 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
9320 if (storage != NULL) {
9321 storage->set(counter, Smi::FromInt(i));
9322 }
9323 counter++;
9324 }
9325 }
9326 ASSERT(!storage || storage->length() >= counter);
9327 break;
9328 }
Steve Block44f0eee2011-05-26 01:26:41 +01009329 case EXTERNAL_PIXEL_ELEMENTS: {
9330 int length = ExternalPixelArray::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00009331 while (counter < length) {
9332 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009333 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +00009334 }
9335 counter++;
9336 }
9337 ASSERT(!storage || storage->length() >= counter);
9338 break;
9339 }
Steve Block3ce2e202009-11-05 08:53:23 +00009340 case EXTERNAL_BYTE_ELEMENTS:
9341 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9342 case EXTERNAL_SHORT_ELEMENTS:
9343 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9344 case EXTERNAL_INT_ELEMENTS:
9345 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009346 case EXTERNAL_FLOAT_ELEMENTS:
9347 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00009348 int length = ExternalArray::cast(elements())->length();
9349 while (counter < length) {
9350 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009351 storage->set(counter, Smi::FromInt(counter));
Steve Block3ce2e202009-11-05 08:53:23 +00009352 }
9353 counter++;
9354 }
9355 ASSERT(!storage || storage->length() >= counter);
9356 break;
9357 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009358 case DICTIONARY_ELEMENTS: {
9359 if (storage != NULL) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009360 element_dictionary()->CopyKeysTo(storage,
9361 filter,
Ben Murdochc7cc0282012-03-05 14:35:55 +00009362 SeededNumberDictionary::SORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +00009363 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009364 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +00009365 break;
9366 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009367 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9368 FixedArray* parameter_map = FixedArray::cast(elements());
9369 int mapped_length = parameter_map->length() - 2;
9370 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9371 if (arguments->IsDictionary()) {
9372 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
9373 // will insert in storage starting at index 0.
Ben Murdochc7cc0282012-03-05 14:35:55 +00009374 SeededNumberDictionary* dictionary =
9375 SeededNumberDictionary::cast(arguments);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009376 if (storage != NULL) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009377 dictionary->CopyKeysTo(
9378 storage, filter, SeededNumberDictionary::UNSORTED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009379 }
9380 counter += dictionary->NumberOfElementsFilterAttributes(filter);
9381 for (int i = 0; i < mapped_length; ++i) {
9382 if (!parameter_map->get(i + 2)->IsTheHole()) {
9383 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9384 ++counter;
9385 }
9386 }
9387 if (storage != NULL) storage->SortPairs(storage, counter);
9388
9389 } else {
9390 int backing_length = arguments->length();
9391 int i = 0;
9392 for (; i < mapped_length; ++i) {
9393 if (!parameter_map->get(i + 2)->IsTheHole()) {
9394 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9395 ++counter;
9396 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
9397 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9398 ++counter;
9399 }
9400 }
9401 for (; i < backing_length; ++i) {
9402 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9403 ++counter;
9404 }
9405 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009406 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009407 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009408 }
9409
9410 if (this->IsJSValue()) {
9411 Object* val = JSValue::cast(this)->value();
9412 if (val->IsString()) {
9413 String* str = String::cast(val);
9414 if (storage) {
9415 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00009416 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009417 }
9418 }
9419 counter += str->length();
9420 }
9421 }
9422 ASSERT(!storage || storage->length() == counter);
9423 return counter;
9424}
9425
9426
9427int JSObject::GetEnumElementKeys(FixedArray* storage) {
9428 return GetLocalElementKeys(storage,
9429 static_cast<PropertyAttributes>(DONT_ENUM));
9430}
9431
9432
Steve Blocka7e24c12009-10-30 11:49:00 +00009433// StringKey simply carries a string object as key.
9434class StringKey : public HashTableKey {
9435 public:
9436 explicit StringKey(String* string) :
9437 string_(string),
9438 hash_(HashForObject(string)) { }
9439
9440 bool IsMatch(Object* string) {
9441 // We know that all entries in a hash table had their hash keys created.
9442 // Use that knowledge to have fast failure.
9443 if (hash_ != HashForObject(string)) {
9444 return false;
9445 }
9446 return string_->Equals(String::cast(string));
9447 }
9448
9449 uint32_t Hash() { return hash_; }
9450
9451 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
9452
9453 Object* AsObject() { return string_; }
9454
9455 String* string_;
9456 uint32_t hash_;
9457};
9458
9459
9460// StringSharedKeys are used as keys in the eval cache.
9461class StringSharedKey : public HashTableKey {
9462 public:
Steve Block1e0659c2011-05-24 12:43:12 +01009463 StringSharedKey(String* source,
9464 SharedFunctionInfo* shared,
Ben Murdoch85b71792012-04-11 18:30:58 +01009465 StrictModeFlag strict_mode)
Steve Block1e0659c2011-05-24 12:43:12 +01009466 : source_(source),
9467 shared_(shared),
Ben Murdoch85b71792012-04-11 18:30:58 +01009468 strict_mode_(strict_mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00009469
9470 bool IsMatch(Object* other) {
9471 if (!other->IsFixedArray()) return false;
Ben Murdoch85b71792012-04-11 18:30:58 +01009472 FixedArray* pair = FixedArray::cast(other);
9473 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00009474 if (shared != shared_) return false;
Ben Murdoch85b71792012-04-11 18:30:58 +01009475 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9476 Smi::cast(pair->get(2))->value());
9477 if (strict_mode != strict_mode_) return false;
9478 String* source = String::cast(pair->get(1));
Steve Blocka7e24c12009-10-30 11:49:00 +00009479 return source->Equals(source_);
9480 }
9481
9482 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +01009483 SharedFunctionInfo* shared,
Ben Murdoch85b71792012-04-11 18:30:58 +01009484 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009485 uint32_t hash = source->Hash();
9486 if (shared->HasSourceCode()) {
9487 // Instead of using the SharedFunctionInfo pointer in the hash
9488 // code computation, we use a combination of the hash of the
Ben Murdoch85b71792012-04-11 18:30:58 +01009489 // script source code and the start and end positions. We do
9490 // this to ensure that the cache entries can survive garbage
Steve Blocka7e24c12009-10-30 11:49:00 +00009491 // collection.
9492 Script* script = Script::cast(shared->script());
9493 hash ^= String::cast(script->source())->Hash();
Ben Murdoch85b71792012-04-11 18:30:58 +01009494 if (strict_mode == kStrictMode) hash ^= 0x8000;
9495 hash += shared->start_position();
Steve Blocka7e24c12009-10-30 11:49:00 +00009496 }
9497 return hash;
9498 }
9499
9500 uint32_t Hash() {
Ben Murdoch85b71792012-04-11 18:30:58 +01009501 return StringSharedHashHelper(source_, shared_, strict_mode_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009502 }
9503
9504 uint32_t HashForObject(Object* obj) {
Ben Murdoch85b71792012-04-11 18:30:58 +01009505 FixedArray* pair = FixedArray::cast(obj);
9506 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9507 String* source = String::cast(pair->get(1));
9508 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9509 Smi::cast(pair->get(2))->value());
9510 return StringSharedHashHelper(source, shared, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009511 }
9512
John Reck59135872010-11-02 12:39:01 -07009513 MUST_USE_RESULT MaybeObject* AsObject() {
9514 Object* obj;
Ben Murdoch85b71792012-04-11 18:30:58 +01009515 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
John Reck59135872010-11-02 12:39:01 -07009516 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9517 }
Ben Murdoch85b71792012-04-11 18:30:58 +01009518 FixedArray* pair = FixedArray::cast(obj);
9519 pair->set(0, shared_);
9520 pair->set(1, source_);
9521 pair->set(2, Smi::FromInt(strict_mode_));
9522 return pair;
Steve Blocka7e24c12009-10-30 11:49:00 +00009523 }
9524
9525 private:
9526 String* source_;
9527 SharedFunctionInfo* shared_;
Ben Murdoch85b71792012-04-11 18:30:58 +01009528 StrictModeFlag strict_mode_;
Steve Blocka7e24c12009-10-30 11:49:00 +00009529};
9530
9531
9532// RegExpKey carries the source and flags of a regular expression as key.
9533class RegExpKey : public HashTableKey {
9534 public:
9535 RegExpKey(String* string, JSRegExp::Flags flags)
9536 : string_(string),
9537 flags_(Smi::FromInt(flags.value())) { }
9538
Steve Block3ce2e202009-11-05 08:53:23 +00009539 // Rather than storing the key in the hash table, a pointer to the
9540 // stored value is stored where the key should be. IsMatch then
9541 // compares the search key to the found object, rather than comparing
9542 // a key to a key.
Steve Blocka7e24c12009-10-30 11:49:00 +00009543 bool IsMatch(Object* obj) {
9544 FixedArray* val = FixedArray::cast(obj);
9545 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
9546 && (flags_ == val->get(JSRegExp::kFlagsIndex));
9547 }
9548
9549 uint32_t Hash() { return RegExpHash(string_, flags_); }
9550
9551 Object* AsObject() {
9552 // Plain hash maps, which is where regexp keys are used, don't
9553 // use this function.
9554 UNREACHABLE();
9555 return NULL;
9556 }
9557
9558 uint32_t HashForObject(Object* obj) {
9559 FixedArray* val = FixedArray::cast(obj);
9560 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
9561 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
9562 }
9563
9564 static uint32_t RegExpHash(String* string, Smi* flags) {
9565 return string->Hash() + flags->value();
9566 }
9567
9568 String* string_;
9569 Smi* flags_;
9570};
9571
9572// Utf8SymbolKey carries a vector of chars as key.
9573class Utf8SymbolKey : public HashTableKey {
9574 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +00009575 explicit Utf8SymbolKey(Vector<const char> string, uint32_t seed)
9576 : string_(string), hash_field_(0), seed_(seed) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00009577
9578 bool IsMatch(Object* string) {
9579 return String::cast(string)->IsEqualTo(string_);
9580 }
9581
9582 uint32_t Hash() {
Steve Blockd0582a62009-12-15 09:54:21 +00009583 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00009584 unibrow::Utf8InputBuffer<> buffer(string_.start(),
9585 static_cast<unsigned>(string_.length()));
Ben Murdoch85b71792012-04-11 18:30:58 +01009586 chars_ = buffer.Length();
Ben Murdochc7cc0282012-03-05 14:35:55 +00009587 hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
Steve Blockd0582a62009-12-15 09:54:21 +00009588 uint32_t result = hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00009589 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9590 return result;
9591 }
9592
9593 uint32_t HashForObject(Object* other) {
9594 return String::cast(other)->Hash();
9595 }
9596
John Reck59135872010-11-02 12:39:01 -07009597 MaybeObject* AsObject() {
Steve Blockd0582a62009-12-15 09:54:21 +00009598 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01009599 return Isolate::Current()->heap()->AllocateSymbol(
9600 string_, chars_, hash_field_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009601 }
9602
9603 Vector<const char> string_;
Steve Blockd0582a62009-12-15 09:54:21 +00009604 uint32_t hash_field_;
Steve Blocka7e24c12009-10-30 11:49:00 +00009605 int chars_; // Caches the number of characters when computing the hash code.
Ben Murdochc7cc0282012-03-05 14:35:55 +00009606 uint32_t seed_;
Steve Blocka7e24c12009-10-30 11:49:00 +00009607};
9608
9609
Steve Block9fac8402011-05-12 15:51:54 +01009610template <typename Char>
9611class SequentialSymbolKey : public HashTableKey {
9612 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +00009613 explicit SequentialSymbolKey(Vector<const Char> string, uint32_t seed)
9614 : string_(string), hash_field_(0), seed_(seed) { }
Steve Block9fac8402011-05-12 15:51:54 +01009615
9616 uint32_t Hash() {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009617 StringHasher hasher(string_.length(), seed_);
Steve Block9fac8402011-05-12 15:51:54 +01009618
9619 // Very long strings have a trivial hash that doesn't inspect the
9620 // string contents.
9621 if (hasher.has_trivial_hash()) {
9622 hash_field_ = hasher.GetHashField();
9623 } else {
9624 int i = 0;
9625 // Do the iterative array index computation as long as there is a
9626 // chance this is an array index.
9627 while (i < string_.length() && hasher.is_array_index()) {
9628 hasher.AddCharacter(static_cast<uc32>(string_[i]));
9629 i++;
9630 }
9631
9632 // Process the remaining characters without updating the array
9633 // index.
9634 while (i < string_.length()) {
9635 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
9636 i++;
9637 }
9638 hash_field_ = hasher.GetHashField();
9639 }
9640
9641 uint32_t result = hash_field_ >> String::kHashShift;
9642 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9643 return result;
9644 }
9645
9646
9647 uint32_t HashForObject(Object* other) {
9648 return String::cast(other)->Hash();
9649 }
9650
9651 Vector<const Char> string_;
9652 uint32_t hash_field_;
Ben Murdochc7cc0282012-03-05 14:35:55 +00009653 uint32_t seed_;
Steve Block9fac8402011-05-12 15:51:54 +01009654};
9655
9656
9657
9658class AsciiSymbolKey : public SequentialSymbolKey<char> {
9659 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +00009660 AsciiSymbolKey(Vector<const char> str, uint32_t seed)
9661 : SequentialSymbolKey<char>(str, seed) { }
Steve Block9fac8402011-05-12 15:51:54 +01009662
9663 bool IsMatch(Object* string) {
9664 return String::cast(string)->IsAsciiEqualTo(string_);
9665 }
9666
9667 MaybeObject* AsObject() {
9668 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01009669 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01009670 }
9671};
9672
9673
Ben Murdoch257744e2011-11-30 15:57:28 +00009674class SubStringAsciiSymbolKey : public HashTableKey {
9675 public:
9676 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
9677 int from,
Ben Murdochc7cc0282012-03-05 14:35:55 +00009678 int length,
9679 uint32_t seed)
9680 : string_(string), from_(from), length_(length), seed_(seed) { }
Ben Murdoch257744e2011-11-30 15:57:28 +00009681
9682 uint32_t Hash() {
9683 ASSERT(length_ >= 0);
9684 ASSERT(from_ + length_ <= string_->length());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009685 StringHasher hasher(length_, string_->GetHeap()->HashSeed());
Ben Murdoch257744e2011-11-30 15:57:28 +00009686
9687 // Very long strings have a trivial hash that doesn't inspect the
9688 // string contents.
9689 if (hasher.has_trivial_hash()) {
9690 hash_field_ = hasher.GetHashField();
9691 } else {
9692 int i = 0;
9693 // Do the iterative array index computation as long as there is a
9694 // chance this is an array index.
9695 while (i < length_ && hasher.is_array_index()) {
9696 hasher.AddCharacter(static_cast<uc32>(
9697 string_->SeqAsciiStringGet(i + from_)));
9698 i++;
9699 }
9700
9701 // Process the remaining characters without updating the array
9702 // index.
9703 while (i < length_) {
9704 hasher.AddCharacterNoIndex(static_cast<uc32>(
9705 string_->SeqAsciiStringGet(i + from_)));
9706 i++;
9707 }
9708 hash_field_ = hasher.GetHashField();
9709 }
9710
9711 uint32_t result = hash_field_ >> String::kHashShift;
9712 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9713 return result;
9714 }
9715
9716
9717 uint32_t HashForObject(Object* other) {
9718 return String::cast(other)->Hash();
9719 }
9720
9721 bool IsMatch(Object* string) {
9722 Vector<const char> chars(string_->GetChars() + from_, length_);
9723 return String::cast(string)->IsAsciiEqualTo(chars);
9724 }
9725
9726 MaybeObject* AsObject() {
9727 if (hash_field_ == 0) Hash();
9728 Vector<const char> chars(string_->GetChars() + from_, length_);
9729 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
9730 }
9731
9732 private:
9733 Handle<SeqAsciiString> string_;
9734 int from_;
9735 int length_;
9736 uint32_t hash_field_;
Ben Murdochc7cc0282012-03-05 14:35:55 +00009737 uint32_t seed_;
Ben Murdoch257744e2011-11-30 15:57:28 +00009738};
9739
9740
Steve Block9fac8402011-05-12 15:51:54 +01009741class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
9742 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +00009743 explicit TwoByteSymbolKey(Vector<const uc16> str, uint32_t seed)
9744 : SequentialSymbolKey<uc16>(str, seed) { }
Steve Block9fac8402011-05-12 15:51:54 +01009745
9746 bool IsMatch(Object* string) {
9747 return String::cast(string)->IsTwoByteEqualTo(string_);
9748 }
9749
9750 MaybeObject* AsObject() {
9751 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01009752 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01009753 }
9754};
9755
9756
Steve Blocka7e24c12009-10-30 11:49:00 +00009757// SymbolKey carries a string/symbol object as key.
9758class SymbolKey : public HashTableKey {
9759 public:
Steve Block44f0eee2011-05-26 01:26:41 +01009760 explicit SymbolKey(String* string)
9761 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00009762
9763 bool IsMatch(Object* string) {
9764 return String::cast(string)->Equals(string_);
9765 }
9766
9767 uint32_t Hash() { return string_->Hash(); }
9768
9769 uint32_t HashForObject(Object* other) {
9770 return String::cast(other)->Hash();
9771 }
9772
John Reck59135872010-11-02 12:39:01 -07009773 MaybeObject* AsObject() {
Leon Clarkef7060e22010-06-03 12:02:55 +01009774 // Attempt to flatten the string, so that symbols will most often
9775 // be flat strings.
9776 string_ = string_->TryFlattenGetString();
Steve Block44f0eee2011-05-26 01:26:41 +01009777 Heap* heap = string_->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009778 // Transform string to symbol if possible.
Steve Block44f0eee2011-05-26 01:26:41 +01009779 Map* map = heap->SymbolMapForString(string_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009780 if (map != NULL) {
Ben Murdoch85b71792012-04-11 18:30:58 +01009781 string_->set_map(map);
Steve Blocka7e24c12009-10-30 11:49:00 +00009782 ASSERT(string_->IsSymbol());
9783 return string_;
9784 }
9785 // Otherwise allocate a new symbol.
9786 StringInputBuffer buffer(string_);
Steve Block44f0eee2011-05-26 01:26:41 +01009787 return heap->AllocateInternalSymbol(&buffer,
Steve Blocka7e24c12009-10-30 11:49:00 +00009788 string_->length(),
Steve Blockd0582a62009-12-15 09:54:21 +00009789 string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +00009790 }
9791
9792 static uint32_t StringHash(Object* obj) {
9793 return String::cast(obj)->Hash();
9794 }
9795
9796 String* string_;
9797};
9798
9799
9800template<typename Shape, typename Key>
9801void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
9802 IteratePointers(v, 0, kElementsStartOffset);
9803}
9804
9805
9806template<typename Shape, typename Key>
9807void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
9808 IteratePointers(v,
9809 kElementsStartOffset,
9810 kHeaderSize + length() * kPointerSize);
9811}
9812
9813
9814template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009815MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
9816 PretenureFlag pretenure) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009817 int capacity = ComputeCapacity(at_least_space_for);
9818 if (capacity > HashTable::kMaxCapacity) {
Leon Clarkee46be812010-01-19 14:06:41 +00009819 return Failure::OutOfMemoryException();
9820 }
9821
John Reck59135872010-11-02 12:39:01 -07009822 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01009823 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
9824 AllocateHashTable(EntryToIndex(capacity), pretenure);
John Reck59135872010-11-02 12:39:01 -07009825 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00009826 }
John Reck59135872010-11-02 12:39:01 -07009827 HashTable::cast(obj)->SetNumberOfElements(0);
9828 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
9829 HashTable::cast(obj)->SetCapacity(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00009830 return obj;
9831}
9832
9833
Leon Clarkee46be812010-01-19 14:06:41 +00009834// Find entry for key otherwise return kNotFound.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009835int StringDictionary::FindEntry(String* key) {
9836 if (!key->IsSymbol()) {
9837 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
9838 }
9839
9840 // Optimized for symbol key. Knowledge of the key type allows:
9841 // 1. Move the check if the key is a symbol out of the loop.
Ben Murdoch85b71792012-04-11 18:30:58 +01009842 // 2. Avoid comparing hash codes in symbol to symbol comparision.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009843 // 3. Detect a case when a dictionary key is not a symbol but the key is.
9844 // In case of positive result the dictionary key may be replaced by
9845 // the symbol with minimal performance penalty. It gives a chance to
9846 // perform further lookups in code stubs (and significant performance boost
9847 // a certain style of code).
9848
9849 // EnsureCapacity will guarantee the hash table is never full.
9850 uint32_t capacity = Capacity();
9851 uint32_t entry = FirstProbe(key->Hash(), capacity);
9852 uint32_t count = 1;
9853
9854 while (true) {
9855 int index = EntryToIndex(entry);
9856 Object* element = get(index);
9857 if (element->IsUndefined()) break; // Empty entry.
9858 if (key == element) return entry;
9859 if (!element->IsSymbol() &&
Ben Murdoch85b71792012-04-11 18:30:58 +01009860 !element->IsNull() &&
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009861 String::cast(element)->Equals(key)) {
9862 // Replace a non-symbol key by the equivalent symbol for faster further
9863 // lookups.
9864 set(index, key);
9865 return entry;
9866 }
Ben Murdoch85b71792012-04-11 18:30:58 +01009867 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009868 entry = NextProbe(entry, count++, capacity);
9869 }
9870 return kNotFound;
9871}
9872
9873
Steve Blocka7e24c12009-10-30 11:49:00 +00009874template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009875MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
9876 ASSERT(NumberOfElements() < new_table->Capacity());
9877
9878 AssertNoAllocation no_gc;
9879 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
9880
9881 // Copy prefix to new array.
9882 for (int i = kPrefixStartIndex;
9883 i < kPrefixStartIndex + Shape::kPrefixSize;
9884 i++) {
9885 new_table->set(i, get(i), mode);
9886 }
9887
9888 // Rehash the elements.
9889 int capacity = Capacity();
9890 for (int i = 0; i < capacity; i++) {
9891 uint32_t from_index = EntryToIndex(i);
9892 Object* k = get(from_index);
9893 if (IsKey(k)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009894 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009895 uint32_t insertion_index =
9896 EntryToIndex(new_table->FindInsertionEntry(hash));
9897 for (int j = 0; j < Shape::kEntrySize; j++) {
9898 new_table->set(insertion_index + j, get(from_index + j), mode);
9899 }
9900 }
9901 }
9902 new_table->SetNumberOfElements(NumberOfElements());
9903 new_table->SetNumberOfDeletedElements(0);
9904 return new_table;
9905}
9906
9907
9908template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009909MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009910 int capacity = Capacity();
9911 int nof = NumberOfElements() + n;
Leon Clarkee46be812010-01-19 14:06:41 +00009912 int nod = NumberOfDeletedElements();
9913 // Return if:
9914 // 50% is still free after adding n elements and
9915 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +01009916 if (nod <= (capacity - nof) >> 1) {
9917 int needed_free = nof >> 1;
9918 if (nof + needed_free <= capacity) return this;
9919 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009920
Steve Block6ded16b2010-05-10 14:33:55 +01009921 const int kMinCapacityForPretenure = 256;
9922 bool pretenure =
Ben Murdoch8b112d22011-06-08 16:22:53 +01009923 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
John Reck59135872010-11-02 12:39:01 -07009924 Object* obj;
9925 { MaybeObject* maybe_obj =
9926 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
9927 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9928 }
Leon Clarke4515c472010-02-03 11:58:03 +00009929
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009930 return Rehash(HashTable::cast(obj), key);
9931}
Steve Blocka7e24c12009-10-30 11:49:00 +00009932
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009933
9934template<typename Shape, typename Key>
9935MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
9936 int capacity = Capacity();
9937 int nof = NumberOfElements();
9938
9939 // Shrink to fit the number of elements if only a quarter of the
9940 // capacity is filled with elements.
9941 if (nof > (capacity >> 2)) return this;
9942 // Allocate a new dictionary with room for at least the current
9943 // number of elements. The allocation method will make sure that
9944 // there is extra room in the dictionary for additions. Don't go
9945 // lower than room for 16 elements.
9946 int at_least_room_for = nof;
9947 if (at_least_room_for < 16) return this;
9948
9949 const int kMinCapacityForPretenure = 256;
9950 bool pretenure =
9951 (at_least_room_for > kMinCapacityForPretenure) &&
9952 !GetHeap()->InNewSpace(this);
9953 Object* obj;
9954 { MaybeObject* maybe_obj =
9955 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
9956 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00009957 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009958
9959 return Rehash(HashTable::cast(obj), key);
Steve Blocka7e24c12009-10-30 11:49:00 +00009960}
9961
9962
9963template<typename Shape, typename Key>
9964uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
9965 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +00009966 uint32_t entry = FirstProbe(hash, capacity);
9967 uint32_t count = 1;
9968 // EnsureCapacity will guarantee the hash table is never full.
9969 while (true) {
9970 Object* element = KeyAt(entry);
Ben Murdoch85b71792012-04-11 18:30:58 +01009971 if (element->IsUndefined() || element->IsNull()) break;
Leon Clarkee46be812010-01-19 14:06:41 +00009972 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00009973 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009974 return entry;
9975}
9976
9977// Force instantiation of template instances class.
9978// Please note this list is compiler dependent.
9979
9980template class HashTable<SymbolTableShape, HashTableKey*>;
9981
9982template class HashTable<CompilationCacheShape, HashTableKey*>;
9983
9984template class HashTable<MapCacheShape, HashTableKey*>;
9985
Ben Murdoch85b71792012-04-11 18:30:58 +01009986template class HashTable<ObjectHashTableShape, JSObject*>;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009987
Steve Blocka7e24c12009-10-30 11:49:00 +00009988template class Dictionary<StringDictionaryShape, String*>;
9989
Ben Murdochc7cc0282012-03-05 14:35:55 +00009990template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
Steve Blocka7e24c12009-10-30 11:49:00 +00009991
Ben Murdochc7cc0282012-03-05 14:35:55 +00009992template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
9993
9994template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
9995 Allocate(int at_least_space_for);
9996
9997template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
9998 Allocate(int at_least_space_for);
Steve Blocka7e24c12009-10-30 11:49:00 +00009999
John Reck59135872010-11-02 12:39:01 -070010000template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +000010001 int);
10002
Ben Murdochc7cc0282012-03-05 14:35:55 +000010003template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
Steve Blocka7e24c12009-10-30 11:49:00 +000010004 uint32_t, Object*);
10005
Ben Murdochc7cc0282012-03-05 14:35:55 +000010006template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
10007 AtPut(uint32_t, Object*);
10008
Ben Murdochc7cc0282012-03-05 14:35:55 +000010009template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
10010 SlowReverseLookup(Object* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000010011
10012template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
10013 Object*);
10014
Ben Murdochc7cc0282012-03-05 14:35:55 +000010015template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010016 FixedArray*,
10017 PropertyAttributes,
Ben Murdochc7cc0282012-03-05 14:35:55 +000010018 Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010019
10020template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
10021 int, JSObject::DeleteMode);
10022
Ben Murdochc7cc0282012-03-05 14:35:55 +000010023template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
10024 DeleteProperty(int, JSObject::DeleteMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010025
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010026template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
10027 String*);
10028
Ben Murdochc7cc0282012-03-05 14:35:55 +000010029template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010030 uint32_t);
10031
Steve Blocka7e24c12009-10-30 11:49:00 +000010032template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010033 FixedArray*,
10034 int,
10035 Dictionary<StringDictionaryShape, String*>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010036
10037template int
10038Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
10039 PropertyAttributes);
10040
John Reck59135872010-11-02 12:39:01 -070010041template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000010042 String*, Object*, PropertyDetails);
10043
John Reck59135872010-11-02 12:39:01 -070010044template MaybeObject*
Steve Blocka7e24c12009-10-30 11:49:00 +000010045Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
10046
10047template int
Ben Murdochc7cc0282012-03-05 14:35:55 +000010048Dictionary<SeededNumberDictionaryShape, uint32_t>::
10049 NumberOfElementsFilterAttributes(PropertyAttributes);
Steve Blocka7e24c12009-10-30 11:49:00 +000010050
Ben Murdochc7cc0282012-03-05 14:35:55 +000010051template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000010052 uint32_t, Object*, PropertyDetails);
10053
Ben Murdochc7cc0282012-03-05 14:35:55 +000010054template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
10055 uint32_t, Object*, PropertyDetails);
10056
10057template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
10058 EnsureCapacity(int, uint32_t);
10059
10060template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
John Reck59135872010-11-02 12:39:01 -070010061 EnsureCapacity(int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000010062
John Reck59135872010-11-02 12:39:01 -070010063template MaybeObject* Dictionary<StringDictionaryShape, String*>::
10064 EnsureCapacity(int, String*);
Steve Blocka7e24c12009-10-30 11:49:00 +000010065
Ben Murdochc7cc0282012-03-05 14:35:55 +000010066template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
10067 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
10068
10069template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
10070 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000010071
John Reck59135872010-11-02 12:39:01 -070010072template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +000010073 String*, Object*, PropertyDetails, uint32_t);
10074
10075template
Ben Murdochc7cc0282012-03-05 14:35:55 +000010076int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000010077
10078template
10079int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
10080
Leon Clarkee46be812010-01-19 14:06:41 +000010081template
Ben Murdochc7cc0282012-03-05 14:35:55 +000010082int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
Leon Clarkee46be812010-01-19 14:06:41 +000010083
10084
Steve Blocka7e24c12009-10-30 11:49:00 +000010085// Collates undefined and unexisting elements below limit from position
10086// zero of the elements. The object stays in Dictionary mode.
John Reck59135872010-11-02 12:39:01 -070010087MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010088 ASSERT(HasDictionaryElements());
10089 // Must stay in dictionary mode, either because of requires_slow_elements,
10090 // or because we are not going to sort (and therefore compact) all of the
10091 // elements.
Ben Murdochc7cc0282012-03-05 14:35:55 +000010092 SeededNumberDictionary* dict = element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +000010093 HeapNumber* result_double = NULL;
10094 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10095 // Allocate space for result before we start mutating the object.
John Reck59135872010-11-02 12:39:01 -070010096 Object* new_double;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010097 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070010098 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10099 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010100 result_double = HeapNumber::cast(new_double);
10101 }
10102
John Reck59135872010-11-02 12:39:01 -070010103 Object* obj;
10104 { MaybeObject* maybe_obj =
Ben Murdochc7cc0282012-03-05 14:35:55 +000010105 SeededNumberDictionary::Allocate(dict->NumberOfElements());
John Reck59135872010-11-02 12:39:01 -070010106 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10107 }
Ben Murdochc7cc0282012-03-05 14:35:55 +000010108 SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +000010109
10110 AssertNoAllocation no_alloc;
10111
10112 uint32_t pos = 0;
10113 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010010114 int capacity = dict->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000010115 for (int i = 0; i < capacity; i++) {
10116 Object* k = dict->KeyAt(i);
10117 if (dict->IsKey(k)) {
10118 ASSERT(k->IsNumber());
10119 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
10120 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
10121 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
10122 Object* value = dict->ValueAt(i);
10123 PropertyDetails details = dict->DetailsAt(i);
10124 if (details.type() == CALLBACKS) {
10125 // Bail out and do the sorting of undefineds and array holes in JS.
10126 return Smi::FromInt(-1);
10127 }
10128 uint32_t key = NumberToUint32(k);
John Reck59135872010-11-02 12:39:01 -070010129 // In the following we assert that adding the entry to the new dictionary
10130 // does not cause GC. This is the case because we made sure to allocate
10131 // the dictionary big enough above, so it need not grow.
Steve Blocka7e24c12009-10-30 11:49:00 +000010132 if (key < limit) {
10133 if (value->IsUndefined()) {
10134 undefs++;
10135 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010010136 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10137 // Adding an entry with the key beyond smi-range requires
10138 // allocation. Bailout.
10139 return Smi::FromInt(-1);
10140 }
John Reck59135872010-11-02 12:39:01 -070010141 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010142 pos++;
10143 }
10144 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010010145 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
10146 // Adding an entry with the key beyond smi-range requires
10147 // allocation. Bailout.
10148 return Smi::FromInt(-1);
10149 }
John Reck59135872010-11-02 12:39:01 -070010150 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010151 }
10152 }
10153 }
10154
10155 uint32_t result = pos;
10156 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010157 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010158 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010010159 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10160 // Adding an entry with the key beyond smi-range requires
10161 // allocation. Bailout.
10162 return Smi::FromInt(-1);
10163 }
Steve Block44f0eee2011-05-26 01:26:41 +010010164 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
John Reck59135872010-11-02 12:39:01 -070010165 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010166 pos++;
10167 undefs--;
10168 }
10169
10170 set_elements(new_dict);
10171
10172 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10173 return Smi::FromInt(static_cast<int>(result));
10174 }
10175
10176 ASSERT_NE(NULL, result_double);
10177 result_double->set_value(static_cast<double>(result));
10178 return result_double;
10179}
10180
10181
10182// Collects all defined (non-hole) and non-undefined (array) elements at
10183// the start of the elements array.
10184// If the object is in dictionary mode, it is converted to fast elements
10185// mode.
John Reck59135872010-11-02 12:39:01 -070010186MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
Ben Murdoch85b71792012-04-11 18:30:58 +010010187 ASSERT(!HasExternalArrayElements());
10188
Ben Murdoch8b112d22011-06-08 16:22:53 +010010189 Heap* heap = GetHeap();
10190
Steve Blocka7e24c12009-10-30 11:49:00 +000010191 if (HasDictionaryElements()) {
10192 // Convert to fast elements containing only the existing properties.
10193 // Ordering is irrelevant, since we are going to sort anyway.
Ben Murdochc7cc0282012-03-05 14:35:55 +000010194 SeededNumberDictionary* dict = element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +000010195 if (IsJSArray() || dict->requires_slow_elements() ||
10196 dict->max_number_key() >= limit) {
10197 return PrepareSlowElementsForSort(limit);
10198 }
10199 // Convert to fast elements.
10200
John Reck59135872010-11-02 12:39:01 -070010201 Object* obj;
Ben Murdoch85b71792012-04-11 18:30:58 +010010202 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
John Reck59135872010-11-02 12:39:01 -070010203 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10204 }
Steve Block8defd9f2010-07-08 12:39:36 +010010205 Map* new_map = Map::cast(obj);
10206
Steve Block44f0eee2011-05-26 01:26:41 +010010207 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
John Reck59135872010-11-02 12:39:01 -070010208 Object* new_array;
10209 { MaybeObject* maybe_new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010210 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
John Reck59135872010-11-02 12:39:01 -070010211 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
10212 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010213 FixedArray* fast_elements = FixedArray::cast(new_array);
10214 dict->CopyValuesTo(fast_elements);
Steve Block8defd9f2010-07-08 12:39:36 +010010215
10216 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +000010217 set_elements(fast_elements);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010218 } else if (!HasFastDoubleElements()) {
John Reck59135872010-11-02 12:39:01 -070010219 Object* obj;
10220 { MaybeObject* maybe_obj = EnsureWritableFastElements();
10221 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10222 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010223 }
Ben Murdoch85b71792012-04-11 18:30:58 +010010224 ASSERT(HasFastElements() || HasFastDoubleElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000010225
10226 // Collect holes at the end, undefined before that and the rest at the
10227 // start, and return the number of non-hole, non-undefined values.
10228
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010229 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
10230 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000010231 if (limit > elements_length) {
10232 limit = elements_length ;
10233 }
10234 if (limit == 0) {
10235 return Smi::FromInt(0);
10236 }
10237
10238 HeapNumber* result_double = NULL;
10239 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10240 // Pessimistically allocate space for return value before
10241 // we start mutating the array.
John Reck59135872010-11-02 12:39:01 -070010242 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +010010243 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070010244 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10245 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010246 result_double = HeapNumber::cast(new_double);
10247 }
10248
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010249 uint32_t result = 0;
10250 if (elements_base->map() == heap->fixed_double_array_map()) {
10251 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
10252 // Split elements into defined and the_hole, in that order.
10253 unsigned int holes = limit;
10254 // Assume most arrays contain no holes and undefined values, so minimize the
10255 // number of stores of non-undefined, non-the-hole values.
10256 for (unsigned int i = 0; i < holes; i++) {
10257 if (elements->is_the_hole(i)) {
10258 holes--;
10259 } else {
10260 continue;
10261 }
10262 // Position i needs to be filled.
10263 while (holes > i) {
10264 if (elements->is_the_hole(holes)) {
10265 holes--;
10266 } else {
10267 elements->set(i, elements->get_scalar(holes));
10268 break;
10269 }
10270 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010271 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010272 result = holes;
10273 while (holes < limit) {
10274 elements->set_the_hole(holes);
10275 holes++;
10276 }
10277 } else {
10278 FixedArray* elements = FixedArray::cast(elements_base);
10279 AssertNoAllocation no_alloc;
10280
10281 // Split elements into defined, undefined and the_hole, in that order. Only
10282 // count locations for undefined and the hole, and fill them afterwards.
10283 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
10284 unsigned int undefs = limit;
10285 unsigned int holes = limit;
10286 // Assume most arrays contain no holes and undefined values, so minimize the
10287 // number of stores of non-undefined, non-the-hole values.
10288 for (unsigned int i = 0; i < undefs; i++) {
10289 Object* current = elements->get(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000010290 if (current->IsTheHole()) {
10291 holes--;
10292 undefs--;
10293 } else if (current->IsUndefined()) {
10294 undefs--;
10295 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010296 continue;
10297 }
10298 // Position i needs to be filled.
10299 while (undefs > i) {
10300 current = elements->get(undefs);
10301 if (current->IsTheHole()) {
10302 holes--;
10303 undefs--;
10304 } else if (current->IsUndefined()) {
10305 undefs--;
10306 } else {
10307 elements->set(i, current, write_barrier);
10308 break;
10309 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010310 }
10311 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010312 result = undefs;
10313 while (undefs < holes) {
10314 elements->set_undefined(undefs);
10315 undefs++;
10316 }
10317 while (holes < limit) {
10318 elements->set_the_hole(holes);
10319 holes++;
10320 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010321 }
10322
10323 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10324 return Smi::FromInt(static_cast<int>(result));
10325 }
10326 ASSERT_NE(NULL, result_double);
10327 result_double->set_value(static_cast<double>(result));
10328 return result_double;
10329}
10330
10331
Steve Block44f0eee2011-05-26 01:26:41 +010010332Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010333 uint8_t clamped_value = 0;
10334 if (index < static_cast<uint32_t>(length())) {
10335 if (value->IsSmi()) {
10336 int int_value = Smi::cast(value)->value();
10337 if (int_value < 0) {
10338 clamped_value = 0;
10339 } else if (int_value > 255) {
10340 clamped_value = 255;
10341 } else {
10342 clamped_value = static_cast<uint8_t>(int_value);
10343 }
10344 } else if (value->IsHeapNumber()) {
10345 double double_value = HeapNumber::cast(value)->value();
10346 if (!(double_value > 0)) {
10347 // NaN and less than zero clamp to zero.
10348 clamped_value = 0;
10349 } else if (double_value > 255) {
10350 // Greater than 255 clamp to 255.
10351 clamped_value = 255;
10352 } else {
10353 // Other doubles are rounded to the nearest integer.
10354 clamped_value = static_cast<uint8_t>(double_value + 0.5);
10355 }
10356 } else {
10357 // Clamp undefined to zero (default). All other types have been
10358 // converted to a number type further up in the call chain.
10359 ASSERT(value->IsUndefined());
10360 }
10361 set(index, clamped_value);
10362 }
10363 return Smi::FromInt(clamped_value);
10364}
10365
10366
Steve Block3ce2e202009-11-05 08:53:23 +000010367template<typename ExternalArrayClass, typename ValueType>
Steve Block44f0eee2011-05-26 01:26:41 +010010368static MaybeObject* ExternalArrayIntSetter(Heap* heap,
10369 ExternalArrayClass* receiver,
John Reck59135872010-11-02 12:39:01 -070010370 uint32_t index,
10371 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010372 ValueType cast_value = 0;
10373 if (index < static_cast<uint32_t>(receiver->length())) {
10374 if (value->IsSmi()) {
10375 int int_value = Smi::cast(value)->value();
10376 cast_value = static_cast<ValueType>(int_value);
10377 } else if (value->IsHeapNumber()) {
10378 double double_value = HeapNumber::cast(value)->value();
10379 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
10380 } else {
10381 // Clamp undefined to zero (default). All other types have been
10382 // converted to a number type further up in the call chain.
10383 ASSERT(value->IsUndefined());
10384 }
10385 receiver->set(index, cast_value);
10386 }
Steve Block44f0eee2011-05-26 01:26:41 +010010387 return heap->NumberFromInt32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010388}
10389
10390
John Reck59135872010-11-02 12:39:01 -070010391MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010392 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010393 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010394}
10395
10396
John Reck59135872010-11-02 12:39:01 -070010397MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
10398 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010399 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010400 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010401}
10402
10403
John Reck59135872010-11-02 12:39:01 -070010404MaybeObject* ExternalShortArray::SetValue(uint32_t index,
10405 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010406 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010407 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010408}
10409
10410
John Reck59135872010-11-02 12:39:01 -070010411MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
10412 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010413 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010414 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010415}
10416
10417
John Reck59135872010-11-02 12:39:01 -070010418MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010419 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010420 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010421}
10422
10423
John Reck59135872010-11-02 12:39:01 -070010424MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010425 uint32_t cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010426 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000010427 if (index < static_cast<uint32_t>(length())) {
10428 if (value->IsSmi()) {
10429 int int_value = Smi::cast(value)->value();
10430 cast_value = static_cast<uint32_t>(int_value);
10431 } else if (value->IsHeapNumber()) {
10432 double double_value = HeapNumber::cast(value)->value();
10433 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
10434 } else {
10435 // Clamp undefined to zero (default). All other types have been
10436 // converted to a number type further up in the call chain.
10437 ASSERT(value->IsUndefined());
10438 }
10439 set(index, cast_value);
10440 }
Steve Block44f0eee2011-05-26 01:26:41 +010010441 return heap->NumberFromUint32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010442}
10443
10444
John Reck59135872010-11-02 12:39:01 -070010445MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
Ben Murdoch85b71792012-04-11 18:30:58 +010010446 float cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010447 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000010448 if (index < static_cast<uint32_t>(length())) {
10449 if (value->IsSmi()) {
10450 int int_value = Smi::cast(value)->value();
10451 cast_value = static_cast<float>(int_value);
10452 } else if (value->IsHeapNumber()) {
10453 double double_value = HeapNumber::cast(value)->value();
10454 cast_value = static_cast<float>(double_value);
10455 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +010010456 // Clamp undefined to zero (default). All other types have been
Steve Block3ce2e202009-11-05 08:53:23 +000010457 // converted to a number type further up in the call chain.
10458 ASSERT(value->IsUndefined());
10459 }
10460 set(index, cast_value);
10461 }
Steve Block44f0eee2011-05-26 01:26:41 +010010462 return heap->AllocateHeapNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010463}
10464
10465
Ben Murdoch257744e2011-11-30 15:57:28 +000010466MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
Ben Murdoch85b71792012-04-11 18:30:58 +010010467 double double_value = 0;
Ben Murdoch257744e2011-11-30 15:57:28 +000010468 Heap* heap = GetHeap();
10469 if (index < static_cast<uint32_t>(length())) {
10470 if (value->IsSmi()) {
10471 int int_value = Smi::cast(value)->value();
10472 double_value = static_cast<double>(int_value);
10473 } else if (value->IsHeapNumber()) {
10474 double_value = HeapNumber::cast(value)->value();
10475 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +010010476 // Clamp undefined to zero (default). All other types have been
Ben Murdoch257744e2011-11-30 15:57:28 +000010477 // converted to a number type further up in the call chain.
10478 ASSERT(value->IsUndefined());
10479 }
10480 set(index, double_value);
10481 }
10482 return heap->AllocateHeapNumber(double_value);
10483}
10484
10485
Ben Murdochb0fe1622011-05-05 13:52:32 +010010486JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010487 ASSERT(!HasFastProperties());
10488 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010489 return JSGlobalPropertyCell::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000010490}
10491
10492
John Reck59135872010-11-02 12:39:01 -070010493MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010494 ASSERT(!HasFastProperties());
10495 int entry = property_dictionary()->FindEntry(name);
10496 if (entry == StringDictionary::kNotFound) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010497 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -070010498 Object* cell;
10499 { MaybeObject* maybe_cell =
Steve Block44f0eee2011-05-26 01:26:41 +010010500 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
John Reck59135872010-11-02 12:39:01 -070010501 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
10502 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010503 PropertyDetails details(NONE, NORMAL);
10504 details = details.AsDeleted();
John Reck59135872010-11-02 12:39:01 -070010505 Object* dictionary;
10506 { MaybeObject* maybe_dictionary =
10507 property_dictionary()->Add(name, cell, details);
10508 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
10509 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010510 set_properties(StringDictionary::cast(dictionary));
10511 return cell;
10512 } else {
10513 Object* value = property_dictionary()->ValueAt(entry);
10514 ASSERT(value->IsJSGlobalPropertyCell());
10515 return value;
10516 }
10517}
10518
10519
John Reck59135872010-11-02 12:39:01 -070010520MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010521 SymbolKey key(string);
10522 return LookupKey(&key, s);
10523}
10524
10525
Steve Blockd0582a62009-12-15 09:54:21 +000010526// This class is used for looking up two character strings in the symbol table.
10527// If we don't have a hit we don't want to waste much time so we unroll the
10528// string hash calculation loop here for speed. Doesn't work if the two
10529// characters form a decimal integer, since such strings have a different hash
10530// algorithm.
10531class TwoCharHashTableKey : public HashTableKey {
10532 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +000010533 TwoCharHashTableKey(uint32_t c1, uint32_t c2, uint32_t seed)
Steve Blockd0582a62009-12-15 09:54:21 +000010534 : c1_(c1), c2_(c2) {
10535 // Char 1.
Ben Murdochc7cc0282012-03-05 14:35:55 +000010536 uint32_t hash = seed;
10537 hash += c1;
10538 hash += hash << 10;
Steve Blockd0582a62009-12-15 09:54:21 +000010539 hash ^= hash >> 6;
10540 // Char 2.
10541 hash += c2;
10542 hash += hash << 10;
10543 hash ^= hash >> 6;
10544 // GetHash.
10545 hash += hash << 3;
10546 hash ^= hash >> 11;
10547 hash += hash << 15;
Ben Murdochc7cc0282012-03-05 14:35:55 +000010548 if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash;
Steve Blockd0582a62009-12-15 09:54:21 +000010549#ifdef DEBUG
Ben Murdochc7cc0282012-03-05 14:35:55 +000010550 StringHasher hasher(2, seed);
Steve Blockd0582a62009-12-15 09:54:21 +000010551 hasher.AddCharacter(c1);
10552 hasher.AddCharacter(c2);
10553 // If this assert fails then we failed to reproduce the two-character
10554 // version of the string hashing algorithm above. One reason could be
10555 // that we were passed two digits as characters, since the hash
10556 // algorithm is different in that case.
10557 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
10558#endif
10559 hash_ = hash;
10560 }
10561
10562 bool IsMatch(Object* o) {
10563 if (!o->IsString()) return false;
10564 String* other = String::cast(o);
10565 if (other->length() != 2) return false;
10566 if (other->Get(0) != c1_) return false;
10567 return other->Get(1) == c2_;
10568 }
10569
10570 uint32_t Hash() { return hash_; }
10571 uint32_t HashForObject(Object* key) {
10572 if (!key->IsString()) return 0;
10573 return String::cast(key)->Hash();
10574 }
10575
10576 Object* AsObject() {
10577 // The TwoCharHashTableKey is only used for looking in the symbol
10578 // table, not for adding to it.
10579 UNREACHABLE();
10580 return NULL;
10581 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010582
Steve Blockd0582a62009-12-15 09:54:21 +000010583 private:
10584 uint32_t c1_;
10585 uint32_t c2_;
10586 uint32_t hash_;
10587};
10588
10589
Steve Blocka7e24c12009-10-30 11:49:00 +000010590bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
10591 SymbolKey key(string);
10592 int entry = FindEntry(&key);
10593 if (entry == kNotFound) {
10594 return false;
10595 } else {
10596 String* result = String::cast(KeyAt(entry));
10597 ASSERT(StringShape(result).IsSymbol());
10598 *symbol = result;
10599 return true;
10600 }
10601}
10602
10603
Steve Blockd0582a62009-12-15 09:54:21 +000010604bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
10605 uint32_t c2,
10606 String** symbol) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010607 TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
Steve Blockd0582a62009-12-15 09:54:21 +000010608 int entry = FindEntry(&key);
10609 if (entry == kNotFound) {
10610 return false;
10611 } else {
10612 String* result = String::cast(KeyAt(entry));
10613 ASSERT(StringShape(result).IsSymbol());
10614 *symbol = result;
10615 return true;
10616 }
10617}
10618
10619
Ben Murdochc7cc0282012-03-05 14:35:55 +000010620MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str,
10621 Object** s) {
10622 Utf8SymbolKey key(str, GetHeap()->HashSeed());
Steve Blocka7e24c12009-10-30 11:49:00 +000010623 return LookupKey(&key, s);
10624}
10625
10626
Steve Block9fac8402011-05-12 15:51:54 +010010627MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
10628 Object** s) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010629 AsciiSymbolKey key(str, GetHeap()->HashSeed());
Steve Block9fac8402011-05-12 15:51:54 +010010630 return LookupKey(&key, s);
10631}
10632
10633
Ben Murdoch257744e2011-11-30 15:57:28 +000010634MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
10635 int from,
10636 int length,
10637 Object** s) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010638 SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
Ben Murdoch257744e2011-11-30 15:57:28 +000010639 return LookupKey(&key, s);
10640}
10641
10642
Steve Block9fac8402011-05-12 15:51:54 +010010643MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
10644 Object** s) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010645 TwoByteSymbolKey key(str, GetHeap()->HashSeed());
Steve Block9fac8402011-05-12 15:51:54 +010010646 return LookupKey(&key, s);
10647}
10648
John Reck59135872010-11-02 12:39:01 -070010649MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010650 int entry = FindEntry(key);
10651
10652 // Symbol already in table.
10653 if (entry != kNotFound) {
10654 *s = KeyAt(entry);
10655 return this;
10656 }
10657
10658 // Adding new symbol. Grow table if needed.
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 // Create symbol object.
John Reck59135872010-11-02 12:39:01 -070010665 Object* symbol;
10666 { MaybeObject* maybe_symbol = key->AsObject();
10667 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
10668 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010669
10670 // If the symbol table grew as part of EnsureCapacity, obj is not
10671 // the current symbol table and therefore we cannot use
10672 // SymbolTable::cast here.
10673 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
10674
10675 // Add the new symbol and return it along with the symbol table.
10676 entry = table->FindInsertionEntry(key->Hash());
10677 table->set(EntryToIndex(entry), symbol);
10678 table->ElementAdded();
10679 *s = symbol;
10680 return table;
10681}
10682
10683
10684Object* CompilationCacheTable::Lookup(String* src) {
10685 StringKey key(src);
10686 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010687 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010688 return get(EntryToIndex(entry) + 1);
10689}
10690
10691
Steve Block1e0659c2011-05-24 12:43:12 +010010692Object* CompilationCacheTable::LookupEval(String* src,
10693 Context* context,
Ben Murdoch85b71792012-04-11 18:30:58 +010010694 StrictModeFlag strict_mode) {
10695 StringSharedKey key(src, context->closure()->shared(), strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010696 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +010010697 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010698 return get(EntryToIndex(entry) + 1);
10699}
10700
10701
10702Object* CompilationCacheTable::LookupRegExp(String* src,
10703 JSRegExp::Flags flags) {
10704 RegExpKey key(src, flags);
10705 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010706 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010707 return get(EntryToIndex(entry) + 1);
10708}
10709
10710
John Reck59135872010-11-02 12:39:01 -070010711MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010712 StringKey key(src);
John Reck59135872010-11-02 12:39:01 -070010713 Object* obj;
10714 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10715 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10716 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010717
10718 CompilationCacheTable* cache =
10719 reinterpret_cast<CompilationCacheTable*>(obj);
10720 int entry = cache->FindInsertionEntry(key.Hash());
10721 cache->set(EntryToIndex(entry), src);
10722 cache->set(EntryToIndex(entry) + 1, value);
10723 cache->ElementAdded();
10724 return cache;
10725}
10726
10727
John Reck59135872010-11-02 12:39:01 -070010728MaybeObject* CompilationCacheTable::PutEval(String* src,
10729 Context* context,
Ben Murdoch85b71792012-04-11 18:30:58 +010010730 SharedFunctionInfo* value) {
Steve Block1e0659c2011-05-24 12:43:12 +010010731 StringSharedKey key(src,
10732 context->closure()->shared(),
Ben Murdoch85b71792012-04-11 18:30:58 +010010733 value->strict_mode() ? kStrictMode : kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -070010734 Object* obj;
10735 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10736 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10737 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010738
10739 CompilationCacheTable* cache =
10740 reinterpret_cast<CompilationCacheTable*>(obj);
10741 int entry = cache->FindInsertionEntry(key.Hash());
10742
John Reck59135872010-11-02 12:39:01 -070010743 Object* k;
10744 { MaybeObject* maybe_k = key.AsObject();
10745 if (!maybe_k->ToObject(&k)) return maybe_k;
10746 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010747
10748 cache->set(EntryToIndex(entry), k);
10749 cache->set(EntryToIndex(entry) + 1, value);
10750 cache->ElementAdded();
10751 return cache;
10752}
10753
10754
John Reck59135872010-11-02 12:39:01 -070010755MaybeObject* CompilationCacheTable::PutRegExp(String* src,
10756 JSRegExp::Flags flags,
10757 FixedArray* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010758 RegExpKey key(src, flags);
John Reck59135872010-11-02 12:39:01 -070010759 Object* obj;
10760 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10761 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10762 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010763
10764 CompilationCacheTable* cache =
10765 reinterpret_cast<CompilationCacheTable*>(obj);
10766 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000010767 // We store the value in the key slot, and compare the search key
10768 // to the stored value with a custon IsMatch function during lookups.
Steve Blocka7e24c12009-10-30 11:49:00 +000010769 cache->set(EntryToIndex(entry), value);
10770 cache->set(EntryToIndex(entry) + 1, value);
10771 cache->ElementAdded();
10772 return cache;
10773}
10774
10775
Ben Murdochb0fe1622011-05-05 13:52:32 +010010776void CompilationCacheTable::Remove(Object* value) {
Ben Murdoch85b71792012-04-11 18:30:58 +010010777 Object* null_value = GetHeap()->null_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010010778 for (int entry = 0, size = Capacity(); entry < size; entry++) {
10779 int entry_index = EntryToIndex(entry);
10780 int value_index = entry_index + 1;
10781 if (get(value_index) == value) {
Ben Murdoch85b71792012-04-11 18:30:58 +010010782 fast_set(this, entry_index, null_value);
10783 fast_set(this, value_index, null_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010784 ElementRemoved();
10785 }
10786 }
10787 return;
10788}
10789
10790
Steve Blocka7e24c12009-10-30 11:49:00 +000010791// SymbolsKey used for HashTable where key is array of symbols.
10792class SymbolsKey : public HashTableKey {
10793 public:
10794 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
10795
10796 bool IsMatch(Object* symbols) {
10797 FixedArray* o = FixedArray::cast(symbols);
10798 int len = symbols_->length();
10799 if (o->length() != len) return false;
10800 for (int i = 0; i < len; i++) {
10801 if (o->get(i) != symbols_->get(i)) return false;
10802 }
10803 return true;
10804 }
10805
10806 uint32_t Hash() { return HashForObject(symbols_); }
10807
10808 uint32_t HashForObject(Object* obj) {
10809 FixedArray* symbols = FixedArray::cast(obj);
10810 int len = symbols->length();
10811 uint32_t hash = 0;
10812 for (int i = 0; i < len; i++) {
10813 hash ^= String::cast(symbols->get(i))->Hash();
10814 }
10815 return hash;
10816 }
10817
10818 Object* AsObject() { return symbols_; }
10819
10820 private:
10821 FixedArray* symbols_;
10822};
10823
10824
10825Object* MapCache::Lookup(FixedArray* array) {
10826 SymbolsKey key(array);
10827 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010828 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010829 return get(EntryToIndex(entry) + 1);
10830}
10831
10832
John Reck59135872010-11-02 12:39:01 -070010833MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010834 SymbolsKey key(array);
John Reck59135872010-11-02 12:39:01 -070010835 Object* obj;
10836 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10837 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10838 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010839
10840 MapCache* cache = reinterpret_cast<MapCache*>(obj);
10841 int entry = cache->FindInsertionEntry(key.Hash());
10842 cache->set(EntryToIndex(entry), array);
10843 cache->set(EntryToIndex(entry) + 1, value);
10844 cache->ElementAdded();
10845 return cache;
10846}
10847
10848
10849template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010850MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
10851 Object* obj;
10852 { MaybeObject* maybe_obj =
10853 HashTable<Shape, Key>::Allocate(at_least_space_for);
10854 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000010855 }
John Reck59135872010-11-02 12:39:01 -070010856 // Initialize the next enumeration index.
10857 Dictionary<Shape, Key>::cast(obj)->
10858 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
Steve Blocka7e24c12009-10-30 11:49:00 +000010859 return obj;
10860}
10861
10862
10863template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010864MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Steve Block44f0eee2011-05-26 01:26:41 +010010865 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010866 int length = HashTable<Shape, Key>::NumberOfElements();
10867
10868 // Allocate and initialize iteration order array.
John Reck59135872010-11-02 12:39:01 -070010869 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +010010870 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070010871 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10872 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010873 FixedArray* iteration_order = FixedArray::cast(obj);
10874 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000010875 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010876 }
10877
10878 // Allocate array with enumeration order.
Steve Block44f0eee2011-05-26 01:26:41 +010010879 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070010880 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10881 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010882 FixedArray* enumeration_order = FixedArray::cast(obj);
10883
10884 // Fill the enumeration order array with property details.
10885 int capacity = HashTable<Shape, Key>::Capacity();
10886 int pos = 0;
10887 for (int i = 0; i < capacity; i++) {
10888 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
Leon Clarke4515c472010-02-03 11:58:03 +000010889 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010890 }
10891 }
10892
10893 // Sort the arrays wrt. enumeration order.
10894 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
10895
10896 // Overwrite the enumeration_order with the enumeration indices.
10897 for (int i = 0; i < length; i++) {
10898 int index = Smi::cast(iteration_order->get(i))->value();
10899 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +000010900 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +000010901 }
10902
10903 // Update the dictionary with new indices.
10904 capacity = HashTable<Shape, Key>::Capacity();
10905 pos = 0;
10906 for (int i = 0; i < capacity; i++) {
10907 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
10908 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
10909 PropertyDetails details = DetailsAt(i);
10910 PropertyDetails new_details =
10911 PropertyDetails(details.attributes(), details.type(), enum_index);
10912 DetailsAtPut(i, new_details);
10913 }
10914 }
10915
10916 // Set the next enumeration index.
10917 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
10918 return this;
10919}
10920
10921template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010922MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010923 // Check whether there are enough enumeration indices to add n elements.
10924 if (Shape::kIsEnumerable &&
10925 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
10926 // If not, we generate new indices for the properties.
John Reck59135872010-11-02 12:39:01 -070010927 Object* result;
10928 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
10929 if (!maybe_result->ToObject(&result)) return maybe_result;
10930 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010931 }
10932 return HashTable<Shape, Key>::EnsureCapacity(n, key);
10933}
10934
10935
Ben Murdoch85b71792012-04-11 18:30:58 +010010936void SeededNumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
10937 // Do nothing if the interval [from, to) is empty.
10938 if (from >= to) return;
10939
10940 Heap* heap = GetHeap();
10941 int removed_entries = 0;
10942 Object* sentinel = heap->null_value();
10943 int capacity = Capacity();
10944 for (int i = 0; i < capacity; i++) {
10945 Object* key = KeyAt(i);
10946 if (key->IsNumber()) {
10947 uint32_t number = static_cast<uint32_t>(key->Number());
10948 if (from <= number && number < to) {
10949 SetEntry(i, sentinel, sentinel);
10950 removed_entries++;
10951 }
10952 }
10953 }
10954
10955 // Update the number of elements.
10956 ElementsRemoved(removed_entries);
10957}
10958
10959
Steve Blocka7e24c12009-10-30 11:49:00 +000010960template<typename Shape, typename Key>
10961Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010962 JSReceiver::DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +010010963 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010964 PropertyDetails details = DetailsAt(entry);
10965 // Ignore attributes if forcing a deletion.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010966 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
Steve Block44f0eee2011-05-26 01:26:41 +010010967 return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010968 }
Ben Murdoch85b71792012-04-11 18:30:58 +010010969 SetEntry(entry, heap->null_value(), heap->null_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010970 HashTable<Shape, Key>::ElementRemoved();
Steve Block44f0eee2011-05-26 01:26:41 +010010971 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010972}
10973
10974
10975template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010976MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
10977 return HashTable<Shape, Key>::Shrink(key);
10978}
10979
10980
10981template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010982MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010983 int entry = this->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000010984
10985 // If the entry is present set the value;
10986 if (entry != Dictionary<Shape, Key>::kNotFound) {
10987 ValueAtPut(entry, value);
10988 return this;
10989 }
10990
10991 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070010992 Object* obj;
10993 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10994 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10995 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010996
John Reck59135872010-11-02 12:39:01 -070010997 Object* k;
10998 { MaybeObject* maybe_k = Shape::AsObject(key);
10999 if (!maybe_k->ToObject(&k)) return maybe_k;
11000 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011001 PropertyDetails details = PropertyDetails(NONE, NORMAL);
Ben Murdochc7cc0282012-03-05 14:35:55 +000011002
11003 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
11004 Dictionary<Shape, Key>::Hash(key));
Steve Blocka7e24c12009-10-30 11:49:00 +000011005}
11006
11007
11008template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011009MaybeObject* Dictionary<Shape, Key>::Add(Key key,
11010 Object* value,
11011 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011012 // Valdate key is absent.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011013 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000011014 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070011015 Object* obj;
11016 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11017 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11018 }
Ben Murdochc7cc0282012-03-05 14:35:55 +000011019
11020 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
11021 Dictionary<Shape, Key>::Hash(key));
Steve Blocka7e24c12009-10-30 11:49:00 +000011022}
11023
11024
11025// Add a key, value pair to the dictionary.
11026template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011027MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
11028 Object* value,
11029 PropertyDetails details,
11030 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011031 // Compute the key object.
John Reck59135872010-11-02 12:39:01 -070011032 Object* k;
11033 { MaybeObject* maybe_k = Shape::AsObject(key);
11034 if (!maybe_k->ToObject(&k)) return maybe_k;
11035 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011036
11037 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
11038 // Insert element at empty or deleted entry
11039 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
11040 // Assign an enumeration index to the property and update
11041 // SetNextEnumerationIndex.
11042 int index = NextEnumerationIndex();
11043 details = PropertyDetails(details.attributes(), details.type(), index);
11044 SetNextEnumerationIndex(index + 1);
11045 }
11046 SetEntry(entry, k, value, details);
11047 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
11048 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
11049 HashTable<Shape, Key>::ElementAdded();
11050 return this;
11051}
11052
11053
Ben Murdochc7cc0282012-03-05 14:35:55 +000011054void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011055 // If the dictionary requires slow elements an element has already
11056 // been added at a high index.
11057 if (requires_slow_elements()) return;
11058 // Check if this index is high enough that we should require slow
11059 // elements.
11060 if (key > kRequiresSlowElementsLimit) {
11061 set_requires_slow_elements();
11062 return;
11063 }
11064 // Update max key value.
11065 Object* max_index_object = get(kMaxNumberKeyIndex);
11066 if (!max_index_object->IsSmi() || max_number_key() < key) {
11067 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000011068 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000011069 }
11070}
11071
11072
Ben Murdochc7cc0282012-03-05 14:35:55 +000011073MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
11074 Object* value,
11075 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011076 UpdateMaxNumberKey(key);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011077 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +000011078 return Add(key, value, details);
11079}
11080
11081
Ben Murdochc7cc0282012-03-05 14:35:55 +000011082MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
11083 Object* value) {
11084 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
11085 return Add(key, value, PropertyDetails(NONE, NORMAL));
11086}
11087
11088
11089MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011090 UpdateMaxNumberKey(key);
11091 return AtPut(key, value);
11092}
11093
11094
Ben Murdochc7cc0282012-03-05 14:35:55 +000011095MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
11096 Object* value) {
11097 return AtPut(key, value);
11098}
11099
11100
Ben Murdochc7cc0282012-03-05 14:35:55 +000011101MaybeObject* SeededNumberDictionary::Set(uint32_t key,
11102 Object* value,
11103 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011104 int entry = FindEntry(key);
11105 if (entry == kNotFound) return AddNumberEntry(key, value, details);
11106 // Preserve enumeration index.
11107 details = PropertyDetails(details.attributes(),
11108 details.type(),
11109 DetailsAt(entry).index());
Ben Murdochc7cc0282012-03-05 14:35:55 +000011110 MaybeObject* maybe_object_key = SeededNumberDictionaryShape::AsObject(key);
John Reck59135872010-11-02 12:39:01 -070011111 Object* object_key;
11112 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
Ben Murdochf87a2032010-10-22 12:50:53 +010011113 SetEntry(entry, object_key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000011114 return this;
11115}
11116
11117
Ben Murdochc7cc0282012-03-05 14:35:55 +000011118MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
11119 Object* value) {
11120 int entry = FindEntry(key);
11121 if (entry == kNotFound) return AddNumberEntry(key, value);
11122 MaybeObject* maybe_object_key = UnseededNumberDictionaryShape::AsObject(key);
11123 Object* object_key;
11124 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
11125 SetEntry(entry, object_key, value);
11126 return this;
11127}
11128
11129
Steve Blocka7e24c12009-10-30 11:49:00 +000011130
11131template<typename Shape, typename Key>
11132int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
11133 PropertyAttributes filter) {
11134 int capacity = HashTable<Shape, Key>::Capacity();
11135 int result = 0;
11136 for (int i = 0; i < capacity; i++) {
11137 Object* k = HashTable<Shape, Key>::KeyAt(i);
11138 if (HashTable<Shape, Key>::IsKey(k)) {
11139 PropertyDetails details = DetailsAt(i);
11140 if (details.IsDeleted()) continue;
11141 PropertyAttributes attr = details.attributes();
11142 if ((attr & filter) == 0) result++;
11143 }
11144 }
11145 return result;
11146}
11147
11148
11149template<typename Shape, typename Key>
11150int Dictionary<Shape, Key>::NumberOfEnumElements() {
11151 return NumberOfElementsFilterAttributes(
11152 static_cast<PropertyAttributes>(DONT_ENUM));
11153}
11154
11155
11156template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011157void Dictionary<Shape, Key>::CopyKeysTo(
11158 FixedArray* storage,
11159 PropertyAttributes filter,
11160 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011161 ASSERT(storage->length() >= NumberOfEnumElements());
11162 int capacity = HashTable<Shape, Key>::Capacity();
11163 int index = 0;
11164 for (int i = 0; i < capacity; i++) {
11165 Object* k = HashTable<Shape, Key>::KeyAt(i);
11166 if (HashTable<Shape, Key>::IsKey(k)) {
11167 PropertyDetails details = DetailsAt(i);
11168 if (details.IsDeleted()) continue;
11169 PropertyAttributes attr = details.attributes();
11170 if ((attr & filter) == 0) storage->set(index++, k);
11171 }
11172 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011173 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11174 storage->SortPairs(storage, index);
11175 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011176 ASSERT(storage->length() >= index);
11177}
11178
11179
11180void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
11181 FixedArray* sort_array) {
11182 ASSERT(storage->length() >= NumberOfEnumElements());
11183 int capacity = Capacity();
11184 int index = 0;
11185 for (int i = 0; i < capacity; i++) {
11186 Object* k = KeyAt(i);
11187 if (IsKey(k)) {
11188 PropertyDetails details = DetailsAt(i);
11189 if (details.IsDeleted() || details.IsDontEnum()) continue;
11190 storage->set(index, k);
Leon Clarke4515c472010-02-03 11:58:03 +000011191 sort_array->set(index, Smi::FromInt(details.index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011192 index++;
11193 }
11194 }
11195 storage->SortPairs(sort_array, sort_array->length());
11196 ASSERT(storage->length() >= index);
11197}
11198
11199
11200template<typename Shape, typename Key>
Ben Murdoch6d7cb002011-08-04 19:25:22 +010011201void Dictionary<Shape, Key>::CopyKeysTo(
Ben Murdoch257744e2011-11-30 15:57:28 +000011202 FixedArray* storage,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011203 int index,
11204 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011205 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
11206 static_cast<PropertyAttributes>(NONE)));
11207 int capacity = HashTable<Shape, Key>::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000011208 for (int i = 0; i < capacity; i++) {
11209 Object* k = HashTable<Shape, Key>::KeyAt(i);
11210 if (HashTable<Shape, Key>::IsKey(k)) {
11211 PropertyDetails details = DetailsAt(i);
11212 if (details.IsDeleted()) continue;
11213 storage->set(index++, k);
11214 }
11215 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011216 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11217 storage->SortPairs(storage, index);
11218 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011219 ASSERT(storage->length() >= index);
11220}
11221
11222
11223// Backwards lookup (slow).
11224template<typename Shape, typename Key>
11225Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
11226 int capacity = HashTable<Shape, Key>::Capacity();
11227 for (int i = 0; i < capacity; i++) {
11228 Object* k = HashTable<Shape, Key>::KeyAt(i);
11229 if (Dictionary<Shape, Key>::IsKey(k)) {
11230 Object* e = ValueAt(i);
11231 if (e->IsJSGlobalPropertyCell()) {
11232 e = JSGlobalPropertyCell::cast(e)->value();
11233 }
11234 if (e == value) return k;
11235 }
11236 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010011237 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010011238 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011239}
11240
11241
John Reck59135872010-11-02 12:39:01 -070011242MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Steve Blocka7e24c12009-10-30 11:49:00 +000011243 JSObject* obj, int unused_property_fields) {
11244 // Make sure we preserve dictionary representation if there are too many
11245 // descriptors.
11246 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
11247
11248 // Figure out if it is necessary to generate new enumeration indices.
11249 int max_enumeration_index =
11250 NextEnumerationIndex() +
11251 (DescriptorArray::kMaxNumberOfDescriptors -
11252 NumberOfElements());
11253 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
John Reck59135872010-11-02 12:39:01 -070011254 Object* result;
11255 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
11256 if (!maybe_result->ToObject(&result)) return maybe_result;
11257 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011258 }
11259
11260 int instance_descriptor_length = 0;
11261 int number_of_fields = 0;
11262
Ben Murdoch8b112d22011-06-08 16:22:53 +010011263 Heap* heap = GetHeap();
11264
Steve Blocka7e24c12009-10-30 11:49:00 +000011265 // Compute the length of the instance descriptor.
11266 int capacity = Capacity();
11267 for (int i = 0; i < capacity; i++) {
11268 Object* k = KeyAt(i);
11269 if (IsKey(k)) {
11270 Object* value = ValueAt(i);
11271 PropertyType type = DetailsAt(i).type();
11272 ASSERT(type != FIELD);
11273 instance_descriptor_length++;
Leon Clarkee46be812010-01-19 14:06:41 +000011274 if (type == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +010011275 (!value->IsJSFunction() || heap->InNewSpace(value))) {
Leon Clarkee46be812010-01-19 14:06:41 +000011276 number_of_fields += 1;
11277 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011278 }
11279 }
11280
11281 // Allocate the instance descriptor.
Ben Murdoch85b71792012-04-11 18:30:58 +010011282 Object* descriptors_unchecked;
11283 { MaybeObject* maybe_descriptors_unchecked =
John Reck59135872010-11-02 12:39:01 -070011284 DescriptorArray::Allocate(instance_descriptor_length);
Ben Murdoch85b71792012-04-11 18:30:58 +010011285 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
11286 return maybe_descriptors_unchecked;
John Reck59135872010-11-02 12:39:01 -070011287 }
11288 }
Ben Murdoch85b71792012-04-11 18:30:58 +010011289 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
Steve Blocka7e24c12009-10-30 11:49:00 +000011290
11291 int inobject_props = obj->map()->inobject_properties();
11292 int number_of_allocated_fields =
11293 number_of_fields + unused_property_fields - inobject_props;
Ben Murdochf87a2032010-10-22 12:50:53 +010011294 if (number_of_allocated_fields < 0) {
11295 // There is enough inobject space for all fields (including unused).
11296 number_of_allocated_fields = 0;
11297 unused_property_fields = inobject_props - number_of_fields;
11298 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011299
11300 // Allocate the fixed array for the fields.
John Reck59135872010-11-02 12:39:01 -070011301 Object* fields;
11302 { MaybeObject* maybe_fields =
Steve Block44f0eee2011-05-26 01:26:41 +010011303 heap->AllocateFixedArray(number_of_allocated_fields);
John Reck59135872010-11-02 12:39:01 -070011304 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
11305 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011306
11307 // Fill in the instance descriptor and the fields.
11308 int next_descriptor = 0;
11309 int current_offset = 0;
11310 for (int i = 0; i < capacity; i++) {
11311 Object* k = KeyAt(i);
11312 if (IsKey(k)) {
11313 Object* value = ValueAt(i);
11314 // Ensure the key is a symbol before writing into the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070011315 Object* key;
Steve Block44f0eee2011-05-26 01:26:41 +010011316 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
John Reck59135872010-11-02 12:39:01 -070011317 if (!maybe_key->ToObject(&key)) return maybe_key;
11318 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011319 PropertyDetails details = DetailsAt(i);
11320 PropertyType type = details.type();
11321
Steve Block44f0eee2011-05-26 01:26:41 +010011322 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011323 ConstantFunctionDescriptor d(String::cast(key),
11324 JSFunction::cast(value),
11325 details.attributes(),
11326 details.index());
Ben Murdoch85b71792012-04-11 18:30:58 +010011327 descriptors->Set(next_descriptor++, &d);
Steve Blocka7e24c12009-10-30 11:49:00 +000011328 } else if (type == NORMAL) {
11329 if (current_offset < inobject_props) {
11330 obj->InObjectPropertyAtPut(current_offset,
11331 value,
11332 UPDATE_WRITE_BARRIER);
11333 } else {
11334 int offset = current_offset - inobject_props;
11335 FixedArray::cast(fields)->set(offset, value);
11336 }
11337 FieldDescriptor d(String::cast(key),
11338 current_offset++,
11339 details.attributes(),
11340 details.index());
Ben Murdoch85b71792012-04-11 18:30:58 +010011341 descriptors->Set(next_descriptor++, &d);
Steve Blocka7e24c12009-10-30 11:49:00 +000011342 } else if (type == CALLBACKS) {
11343 CallbacksDescriptor d(String::cast(key),
11344 value,
11345 details.attributes(),
11346 details.index());
Ben Murdoch85b71792012-04-11 18:30:58 +010011347 descriptors->Set(next_descriptor++, &d);
Steve Blocka7e24c12009-10-30 11:49:00 +000011348 } else {
11349 UNREACHABLE();
11350 }
11351 }
11352 }
11353 ASSERT(current_offset == number_of_fields);
11354
Ben Murdoch85b71792012-04-11 18:30:58 +010011355 descriptors->Sort();
Steve Blocka7e24c12009-10-30 11:49:00 +000011356 // Allocate new map.
John Reck59135872010-11-02 12:39:01 -070011357 Object* new_map;
11358 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
11359 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
11360 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011361
11362 // Transform the object.
11363 obj->set_map(Map::cast(new_map));
11364 obj->map()->set_instance_descriptors(descriptors);
11365 obj->map()->set_unused_property_fields(unused_property_fields);
11366
11367 obj->set_properties(FixedArray::cast(fields));
11368 ASSERT(obj->IsJSObject());
11369
11370 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
11371 // Check that it really works.
11372 ASSERT(obj->HasFastProperties());
11373
11374 return obj;
11375}
11376
11377
Ben Murdoch85b71792012-04-11 18:30:58 +010011378Object* ObjectHashTable::Lookup(JSObject* key) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011379 // If the object does not have an identity hash, it was never used as a key.
Ben Murdoch85b71792012-04-11 18:30:58 +010011380 MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::OMIT_CREATION);
11381 if (maybe_hash->IsFailure()) return GetHeap()->undefined_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011382 int entry = FindEntry(key);
11383 if (entry == kNotFound) return GetHeap()->undefined_value();
11384 return get(EntryToIndex(entry) + 1);
11385}
11386
11387
Ben Murdoch85b71792012-04-11 18:30:58 +010011388MaybeObject* ObjectHashTable::Put(JSObject* key, Object* value) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011389 // Make sure the key object has an identity hash code.
11390 int hash;
Ben Murdoch85b71792012-04-11 18:30:58 +010011391 { MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::ALLOW_CREATION);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011392 if (maybe_hash->IsFailure()) return maybe_hash;
11393 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
11394 }
11395 int entry = FindEntry(key);
11396
11397 // Check whether to perform removal operation.
11398 if (value->IsUndefined()) {
11399 if (entry == kNotFound) return this;
11400 RemoveEntry(entry);
11401 return Shrink(key);
11402 }
11403
11404 // Key is already in table, just overwrite value.
11405 if (entry != kNotFound) {
11406 set(EntryToIndex(entry) + 1, value);
11407 return this;
11408 }
11409
11410 // Check whether the hash table should be extended.
11411 Object* obj;
11412 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11413 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11414 }
11415 ObjectHashTable* table = ObjectHashTable::cast(obj);
11416 table->AddEntry(table->FindInsertionEntry(hash), key, value);
11417 return table;
11418}
11419
11420
Ben Murdoch85b71792012-04-11 18:30:58 +010011421void ObjectHashTable::AddEntry(int entry, JSObject* key, Object* value) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011422 set(EntryToIndex(entry), key);
11423 set(EntryToIndex(entry) + 1, value);
11424 ElementAdded();
11425}
11426
11427
Ben Murdoch85b71792012-04-11 18:30:58 +010011428void ObjectHashTable::RemoveEntry(int entry, Heap* heap) {
11429 set_null(heap, EntryToIndex(entry));
11430 set_null(heap, EntryToIndex(entry) + 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011431 ElementRemoved();
11432}
11433
11434
Steve Blocka7e24c12009-10-30 11:49:00 +000011435#ifdef ENABLE_DEBUGGER_SUPPORT
11436// Check if there is a break point at this code position.
11437bool DebugInfo::HasBreakPoint(int code_position) {
11438 // Get the break point info object for this code position.
11439 Object* break_point_info = GetBreakPointInfo(code_position);
11440
11441 // If there is no break point info object or no break points in the break
11442 // point info object there is no break point at this code position.
11443 if (break_point_info->IsUndefined()) return false;
11444 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
11445}
11446
11447
11448// Get the break point info object for this code position.
11449Object* DebugInfo::GetBreakPointInfo(int code_position) {
11450 // Find the index of the break point info object for this code position.
11451 int index = GetBreakPointInfoIndex(code_position);
11452
11453 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011454 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011455 return BreakPointInfo::cast(break_points()->get(index));
11456}
11457
11458
11459// Clear a break point at the specified code position.
11460void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
11461 int code_position,
11462 Handle<Object> break_point_object) {
11463 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11464 if (break_point_info->IsUndefined()) return;
11465 BreakPointInfo::ClearBreakPoint(
11466 Handle<BreakPointInfo>::cast(break_point_info),
11467 break_point_object);
11468}
11469
11470
11471void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
11472 int code_position,
11473 int source_position,
11474 int statement_position,
11475 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011476 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000011477 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11478 if (!break_point_info->IsUndefined()) {
11479 BreakPointInfo::SetBreakPoint(
11480 Handle<BreakPointInfo>::cast(break_point_info),
11481 break_point_object);
11482 return;
11483 }
11484
11485 // Adding a new break point for a code position which did not have any
11486 // break points before. Try to find a free slot.
11487 int index = kNoBreakPointInfo;
11488 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11489 if (debug_info->break_points()->get(i)->IsUndefined()) {
11490 index = i;
11491 break;
11492 }
11493 }
11494 if (index == kNoBreakPointInfo) {
11495 // No free slot - extend break point info array.
11496 Handle<FixedArray> old_break_points =
11497 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011498 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010011499 isolate->factory()->NewFixedArray(
11500 old_break_points->length() +
11501 Debug::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011502
11503 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000011504 for (int i = 0; i < old_break_points->length(); i++) {
11505 new_break_points->set(i, old_break_points->get(i));
11506 }
11507 index = old_break_points->length();
11508 }
11509 ASSERT(index != kNoBreakPointInfo);
11510
11511 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010011512 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
11513 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000011514 new_break_point_info->set_code_position(Smi::FromInt(code_position));
11515 new_break_point_info->set_source_position(Smi::FromInt(source_position));
11516 new_break_point_info->
11517 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010011518 new_break_point_info->set_break_point_objects(
11519 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011520 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
11521 debug_info->break_points()->set(index, *new_break_point_info);
11522}
11523
11524
11525// Get the break point objects for a code position.
11526Object* DebugInfo::GetBreakPointObjects(int code_position) {
11527 Object* break_point_info = GetBreakPointInfo(code_position);
11528 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011529 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011530 }
11531 return BreakPointInfo::cast(break_point_info)->break_point_objects();
11532}
11533
11534
11535// Get the total number of break points.
11536int DebugInfo::GetBreakPointCount() {
11537 if (break_points()->IsUndefined()) return 0;
11538 int count = 0;
11539 for (int i = 0; i < break_points()->length(); i++) {
11540 if (!break_points()->get(i)->IsUndefined()) {
11541 BreakPointInfo* break_point_info =
11542 BreakPointInfo::cast(break_points()->get(i));
11543 count += break_point_info->GetBreakPointCount();
11544 }
11545 }
11546 return count;
11547}
11548
11549
11550Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
11551 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011552 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010011553 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011554 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11555 if (!debug_info->break_points()->get(i)->IsUndefined()) {
11556 Handle<BreakPointInfo> break_point_info =
11557 Handle<BreakPointInfo>(BreakPointInfo::cast(
11558 debug_info->break_points()->get(i)));
11559 if (BreakPointInfo::HasBreakPointObject(break_point_info,
11560 break_point_object)) {
11561 return *break_point_info;
11562 }
11563 }
11564 }
Steve Block44f0eee2011-05-26 01:26:41 +010011565 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011566}
11567
11568
11569// Find the index of the break point info object for the specified code
11570// position.
11571int DebugInfo::GetBreakPointInfoIndex(int code_position) {
11572 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
11573 for (int i = 0; i < break_points()->length(); i++) {
11574 if (!break_points()->get(i)->IsUndefined()) {
11575 BreakPointInfo* break_point_info =
11576 BreakPointInfo::cast(break_points()->get(i));
11577 if (break_point_info->code_position()->value() == code_position) {
11578 return i;
11579 }
11580 }
11581 }
11582 return kNoBreakPointInfo;
11583}
11584
11585
11586// Remove the specified break point object.
11587void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
11588 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011589 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000011590 // If there are no break points just ignore.
11591 if (break_point_info->break_point_objects()->IsUndefined()) return;
11592 // If there is a single break point clear it if it is the same.
11593 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11594 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011595 break_point_info->set_break_point_objects(
11596 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011597 }
11598 return;
11599 }
11600 // If there are multiple break points shrink the array
11601 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
11602 Handle<FixedArray> old_array =
11603 Handle<FixedArray>(
11604 FixedArray::cast(break_point_info->break_point_objects()));
11605 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010011606 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000011607 int found_count = 0;
11608 for (int i = 0; i < old_array->length(); i++) {
11609 if (old_array->get(i) == *break_point_object) {
11610 ASSERT(found_count == 0);
11611 found_count++;
11612 } else {
11613 new_array->set(i - found_count, old_array->get(i));
11614 }
11615 }
11616 // If the break point was found in the list change it.
11617 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
11618}
11619
11620
11621// Add the specified break point object.
11622void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
11623 Handle<Object> break_point_object) {
11624 // If there was no break point objects before just set it.
11625 if (break_point_info->break_point_objects()->IsUndefined()) {
11626 break_point_info->set_break_point_objects(*break_point_object);
11627 return;
11628 }
11629 // If the break point object is the same as before just ignore.
11630 if (break_point_info->break_point_objects() == *break_point_object) return;
11631 // If there was one break point object before replace with array.
11632 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Steve Block44f0eee2011-05-26 01:26:41 +010011633 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000011634 array->set(0, break_point_info->break_point_objects());
11635 array->set(1, *break_point_object);
11636 break_point_info->set_break_point_objects(*array);
11637 return;
11638 }
11639 // If there was more than one break point before extend array.
11640 Handle<FixedArray> old_array =
11641 Handle<FixedArray>(
11642 FixedArray::cast(break_point_info->break_point_objects()));
11643 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010011644 FACTORY->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000011645 for (int i = 0; i < old_array->length(); i++) {
11646 // If the break point was there before just ignore.
11647 if (old_array->get(i) == *break_point_object) return;
11648 new_array->set(i, old_array->get(i));
11649 }
11650 // Add the new break point.
11651 new_array->set(old_array->length(), *break_point_object);
11652 break_point_info->set_break_point_objects(*new_array);
11653}
11654
11655
11656bool BreakPointInfo::HasBreakPointObject(
11657 Handle<BreakPointInfo> break_point_info,
11658 Handle<Object> break_point_object) {
11659 // No break point.
11660 if (break_point_info->break_point_objects()->IsUndefined()) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011661 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000011662 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11663 return break_point_info->break_point_objects() == *break_point_object;
11664 }
11665 // Multiple break points.
11666 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
11667 for (int i = 0; i < array->length(); i++) {
11668 if (array->get(i) == *break_point_object) {
11669 return true;
11670 }
11671 }
11672 return false;
11673}
11674
11675
11676// Get the number of break points.
11677int BreakPointInfo::GetBreakPointCount() {
11678 // No break point.
11679 if (break_point_objects()->IsUndefined()) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011680 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000011681 if (!break_point_objects()->IsFixedArray()) return 1;
11682 // Multiple break points.
11683 return FixedArray::cast(break_point_objects())->length();
11684}
Ben Murdoch85b71792012-04-11 18:30:58 +010011685#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000011686
11687
Steve Blocka7e24c12009-10-30 11:49:00 +000011688} } // namespace v8::internal