blob: 1565504c28a67b392ebf2934aa1d386ba793d8db [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010033#include "codegen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include "debug.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "deoptimizer.h"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000036#include "elements.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000037#include "execution.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010038#include "full-codegen.h"
39#include "hydrogen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000040#include "objects-inl.h"
Iain Merrick75681382010-08-19 15:07:18 +010041#include "objects-visiting.h"
Ben Murdoch592a9fc2012-03-05 11:04:45 +000042#include "objects-visiting-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000043#include "macro-assembler.h"
Ben Murdoch592a9fc2012-03-05 11:04:45 +000044#include "mark-compact.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010045#include "safepoint-table.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000046#include "string-stream.h"
Steve Blockd0582a62009-12-15 09:54:21 +000047#include "utils.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010048#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000049
50#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +010051#include "disasm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000052#include "disassembler.h"
53#endif
54
Steve Blocka7e24c12009-10-30 11:49:00 +000055namespace v8 {
56namespace internal {
57
Ben Murdoch592a9fc2012-03-05 11:04:45 +000058void PrintElementsKind(FILE* out, ElementsKind kind) {
59 switch (kind) {
60 case FAST_SMI_ONLY_ELEMENTS:
61 PrintF(out, "FAST_SMI_ONLY_ELEMENTS");
62 break;
63 case FAST_ELEMENTS:
64 PrintF(out, "FAST_ELEMENTS");
65 break;
66 case FAST_DOUBLE_ELEMENTS:
67 PrintF(out, "FAST_DOUBLE_ELEMENTS");
68 break;
69 case DICTIONARY_ELEMENTS:
70 PrintF(out, "DICTIONARY_ELEMENTS");
71 break;
72 case NON_STRICT_ARGUMENTS_ELEMENTS:
73 PrintF(out, "NON_STRICT_ARGUMENTS_ELEMENTS");
74 break;
75 case EXTERNAL_BYTE_ELEMENTS:
76 PrintF(out, "EXTERNAL_BYTE_ELEMENTS");
77 break;
78 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
79 PrintF(out, "EXTERNAL_UNSIGNED_BYTE_ELEMENTS");
80 break;
81 case EXTERNAL_SHORT_ELEMENTS:
82 PrintF(out, "EXTERNAL_SHORT_ELEMENTS");
83 break;
84 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
85 PrintF(out, "EXTERNAL_UNSIGNED_SHORT_ELEMENTS");
86 break;
87 case EXTERNAL_INT_ELEMENTS:
88 PrintF(out, "EXTERNAL_INT_ELEMENTS");
89 break;
90 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
91 PrintF(out, "EXTERNAL_UNSIGNED_INT_ELEMENTS");
92 break;
93 case EXTERNAL_FLOAT_ELEMENTS:
94 PrintF(out, "EXTERNAL_FLOAT_ELEMENTS");
95 break;
96 case EXTERNAL_DOUBLE_ELEMENTS:
97 PrintF(out, "EXTERNAL_DOUBLE_ELEMENTS");
98 break;
99 case EXTERNAL_PIXEL_ELEMENTS:
100 PrintF(out, "EXTERNAL_DOUBLE_ELEMENTS");
101 break;
102 }
103}
104
Steve Blocka7e24c12009-10-30 11:49:00 +0000105
John Reck59135872010-11-02 12:39:01 -0700106MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
107 Object* value) {
108 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100109 { MaybeObject* maybe_result =
110 constructor->GetHeap()->AllocateJSObject(constructor);
John Reck59135872010-11-02 12:39:01 -0700111 if (!maybe_result->ToObject(&result)) return maybe_result;
112 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000113 JSValue::cast(result)->set_value(value);
114 return result;
115}
116
117
John Reck59135872010-11-02 12:39:01 -0700118MaybeObject* Object::ToObject(Context* global_context) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000119 if (IsNumber()) {
120 return CreateJSValue(global_context->number_function(), this);
121 } else if (IsBoolean()) {
122 return CreateJSValue(global_context->boolean_function(), this);
123 } else if (IsString()) {
124 return CreateJSValue(global_context->string_function(), this);
125 }
126 ASSERT(IsJSObject());
127 return this;
128}
129
130
John Reck59135872010-11-02 12:39:01 -0700131MaybeObject* Object::ToObject() {
Ben Murdoch589d6972011-11-30 16:04:58 +0000132 if (IsJSReceiver()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000133 return this;
134 } else if (IsNumber()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100135 Isolate* isolate = Isolate::Current();
136 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000137 return CreateJSValue(global_context->number_function(), this);
138 } else if (IsBoolean()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100139 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
140 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000141 return CreateJSValue(global_context->boolean_function(), this);
142 } else if (IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100143 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
144 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000145 return CreateJSValue(global_context->string_function(), this);
146 }
147
148 // Throw a type error.
149 return Failure::InternalError();
150}
151
152
153Object* Object::ToBoolean() {
Steve Block44f0eee2011-05-26 01:26:41 +0100154 if (IsTrue()) return this;
155 if (IsFalse()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 if (IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100157 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000158 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100159 HeapObject* heap_object = HeapObject::cast(this);
160 if (heap_object->IsUndefined() || heap_object->IsNull()) {
161 return heap_object->GetHeap()->false_value();
Steve Block44f0eee2011-05-26 01:26:41 +0100162 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000163 // Undetectable object is false
Ben Murdoch8b112d22011-06-08 16:22:53 +0100164 if (heap_object->IsUndetectableObject()) {
165 return heap_object->GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000166 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100167 if (heap_object->IsString()) {
168 return heap_object->GetHeap()->ToBoolean(
Steve Block44f0eee2011-05-26 01:26:41 +0100169 String::cast(this)->length() != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000170 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100171 if (heap_object->IsHeapNumber()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000172 return HeapNumber::cast(this)->HeapNumberToBoolean();
173 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100174 return heap_object->GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000175}
176
177
178void Object::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000179 Object* holder = NULL;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000180 if (IsJSReceiver()) {
181 holder = this;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100182 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +0000183 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000184 if (IsNumber()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100185 holder = global_context->number_function()->instance_prototype();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000186 } else if (IsString()) {
187 holder = global_context->string_function()->instance_prototype();
188 } else if (IsBoolean()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100189 holder = global_context->boolean_function()->instance_prototype();
190 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000191 }
192 ASSERT(holder != NULL); // Cannot handle null or undefined.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000193 JSReceiver::cast(holder)->Lookup(name, result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000194}
195
196
John Reck59135872010-11-02 12:39:01 -0700197MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
198 String* name,
199 PropertyAttributes* attributes) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000200 LookupResult result(name->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000201 Lookup(name, &result);
John Reck59135872010-11-02 12:39:01 -0700202 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000203 ASSERT(*attributes <= ABSENT);
204 return value;
205}
206
207
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000208MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
209 Object* structure,
210 String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +0100211 Isolate* isolate = name->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000212 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +0000213 // data structure used to store the callbacks. Eventually foreign
Steve Blocka7e24c12009-10-30 11:49:00 +0000214 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +0000215 if (structure->IsForeign()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000216 AccessorDescriptor* callback =
Ben Murdoch257744e2011-11-30 15:57:28 +0000217 reinterpret_cast<AccessorDescriptor*>(
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000218 Foreign::cast(structure)->foreign_address());
John Reck59135872010-11-02 12:39:01 -0700219 MaybeObject* value = (callback->getter)(receiver, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +0100220 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000221 return value;
222 }
223
224 // api style callbacks.
225 if (structure->IsAccessorInfo()) {
226 AccessorInfo* data = AccessorInfo::cast(structure);
227 Object* fun_obj = data->getter();
228 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000229 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000230 JSObject* self = JSObject::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000231 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +0100232 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000233 CustomArguments args(isolate, data->data(), self, this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000234 v8::AccessorInfo info(args.end());
235 v8::Handle<v8::Value> result;
236 {
237 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +0100238 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000239 result = call_fun(v8::Utils::ToLocal(key), info);
240 }
Steve Block44f0eee2011-05-26 01:26:41 +0100241 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
242 if (result.IsEmpty()) {
243 return isolate->heap()->undefined_value();
244 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000245 return *v8::Utils::OpenHandle(*result);
246 }
247
248 // __defineGetter__ callback
249 if (structure->IsFixedArray()) {
250 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000251 if (getter->IsSpecFunction()) {
252 // TODO(rossberg): nicer would be to cast to some JSCallable here...
253 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
Steve Blocka7e24c12009-10-30 11:49:00 +0000254 }
255 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +0100256 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000257 }
258
259 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +0100260 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000261}
262
263
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000264MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
265 String* name_raw) {
266 Isolate* isolate = GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000267 HandleScope scope(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +0000268 Handle<Object> receiver(receiver_raw);
269 Handle<Object> name(name_raw);
Ben Murdoch257744e2011-11-30 15:57:28 +0000270
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000271 Handle<Object> args[] = { receiver, name };
272 Handle<Object> result = CallTrap(
273 "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +0000274 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch257744e2011-11-30 15:57:28 +0000275
276 return *result;
277}
278
279
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000280Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
281 Isolate* isolate = object->IsHeapObject()
282 ? Handle<HeapObject>::cast(object)->GetIsolate()
283 : Isolate::Current();
284 CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
285}
286
287
288MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
289 uint32_t index) {
290 String* name;
291 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
292 if (!maybe->To<String>(&name)) return maybe;
293 return GetPropertyWithHandler(receiver, name);
294}
295
296
297MaybeObject* JSProxy::SetElementWithHandler(uint32_t index,
298 Object* value,
299 StrictModeFlag strict_mode) {
300 String* name;
301 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
302 if (!maybe->To<String>(&name)) return maybe;
303 return SetPropertyWithHandler(name, value, NONE, strict_mode);
304}
305
306
307bool JSProxy::HasElementWithHandler(uint32_t index) {
308 String* name;
309 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
310 if (!maybe->To<String>(&name)) return maybe;
311 return HasPropertyWithHandler(name);
312}
313
314
John Reck59135872010-11-02 12:39:01 -0700315MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000316 JSReceiver* getter) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000317 HandleScope scope;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000318 Handle<JSReceiver> fun(getter);
Steve Blocka7e24c12009-10-30 11:49:00 +0000319 Handle<Object> self(receiver);
320#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +0100321 Debug* debug = fun->GetHeap()->isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000322 // Handle stepping into a getter if step into is active.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000323 // TODO(rossberg): should this apply to getters that are function proxies?
324 if (debug->StepInActive() && fun->IsJSFunction()) {
325 debug->HandleStepIn(
326 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000327 }
328#endif
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000329
Steve Blocka7e24c12009-10-30 11:49:00 +0000330 bool has_pending_exception;
331 Handle<Object> result =
332 Execution::Call(fun, self, 0, NULL, &has_pending_exception);
333 // Check for pending exception and return the result.
334 if (has_pending_exception) return Failure::Exception();
335 return *result;
336}
337
338
339// Only deal with CALLBACKS and INTERCEPTOR
John Reck59135872010-11-02 12:39:01 -0700340MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
Steve Blocka7e24c12009-10-30 11:49:00 +0000341 Object* receiver,
342 LookupResult* result,
343 String* name,
344 PropertyAttributes* attributes) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000345 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000346 switch (result->type()) {
347 case CALLBACKS: {
348 // Only allow API accessors.
349 Object* obj = result->GetCallbackObject();
350 if (obj->IsAccessorInfo()) {
351 AccessorInfo* info = AccessorInfo::cast(obj);
352 if (info->all_can_read()) {
353 *attributes = result->GetAttributes();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000354 return result->holder()->GetPropertyWithCallback(
355 receiver, result->GetCallbackObject(), name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000356 }
357 }
358 break;
359 }
360 case NORMAL:
361 case FIELD:
362 case CONSTANT_FUNCTION: {
363 // Search ALL_CAN_READ accessors in prototype chain.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000364 LookupResult r(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000366 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000367 return GetPropertyWithFailedAccessCheck(receiver,
368 &r,
369 name,
370 attributes);
371 }
372 break;
373 }
374 case INTERCEPTOR: {
375 // If the object has an interceptor, try real named properties.
376 // No access check in GetPropertyAttributeWithInterceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000377 LookupResult r(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000378 result->holder()->LookupRealNamedProperty(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000379 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000380 return GetPropertyWithFailedAccessCheck(receiver,
381 &r,
382 name,
383 attributes);
384 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000385 break;
386 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000387 default:
388 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000389 }
390 }
391
392 // No accessible property found.
393 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100394 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100395 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
396 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000397}
398
399
400PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
401 Object* receiver,
402 LookupResult* result,
403 String* name,
404 bool continue_search) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000405 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000406 switch (result->type()) {
407 case CALLBACKS: {
408 // Only allow API accessors.
409 Object* obj = result->GetCallbackObject();
410 if (obj->IsAccessorInfo()) {
411 AccessorInfo* info = AccessorInfo::cast(obj);
412 if (info->all_can_read()) {
413 return result->GetAttributes();
414 }
415 }
416 break;
417 }
418
419 case NORMAL:
420 case FIELD:
421 case CONSTANT_FUNCTION: {
422 if (!continue_search) break;
423 // Search ALL_CAN_READ accessors in prototype chain.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000424 LookupResult r(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000425 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000426 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000427 return GetPropertyAttributeWithFailedAccessCheck(receiver,
428 &r,
429 name,
430 continue_search);
431 }
432 break;
433 }
434
435 case INTERCEPTOR: {
436 // If the object has an interceptor, try real named properties.
437 // No access check in GetPropertyAttributeWithInterceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000438 LookupResult r(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000439 if (continue_search) {
440 result->holder()->LookupRealNamedProperty(name, &r);
441 } else {
442 result->holder()->LocalLookupRealNamedProperty(name, &r);
443 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000444 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000445 return GetPropertyAttributeWithFailedAccessCheck(receiver,
446 &r,
447 name,
448 continue_search);
449 }
450 break;
451 }
452
Andrei Popescu402d9372010-02-26 13:31:12 +0000453 default:
454 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000455 }
456 }
457
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000458 GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000459 return ABSENT;
460}
461
462
Steve Blocka7e24c12009-10-30 11:49:00 +0000463Object* JSObject::GetNormalizedProperty(LookupResult* result) {
464 ASSERT(!HasFastProperties());
465 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
466 if (IsGlobalObject()) {
467 value = JSGlobalPropertyCell::cast(value)->value();
468 }
469 ASSERT(!value->IsJSGlobalPropertyCell());
470 return value;
471}
472
473
474Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
475 ASSERT(!HasFastProperties());
476 if (IsGlobalObject()) {
477 JSGlobalPropertyCell* cell =
478 JSGlobalPropertyCell::cast(
479 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
480 cell->set_value(value);
481 } else {
482 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
483 }
484 return value;
485}
486
487
John Reck59135872010-11-02 12:39:01 -0700488MaybeObject* JSObject::SetNormalizedProperty(String* name,
489 Object* value,
490 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000491 ASSERT(!HasFastProperties());
492 int entry = property_dictionary()->FindEntry(name);
493 if (entry == StringDictionary::kNotFound) {
494 Object* store_value = value;
495 if (IsGlobalObject()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100496 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100497 MaybeObject* maybe_store_value =
498 heap->AllocateJSGlobalPropertyCell(value);
499 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000500 }
John Reck59135872010-11-02 12:39:01 -0700501 Object* dict;
502 { MaybeObject* maybe_dict =
503 property_dictionary()->Add(name, store_value, details);
504 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
505 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000506 set_properties(StringDictionary::cast(dict));
507 return value;
508 }
509 // Preserve enumeration index.
510 details = PropertyDetails(details.attributes(),
511 details.type(),
512 property_dictionary()->DetailsAt(entry).index());
513 if (IsGlobalObject()) {
514 JSGlobalPropertyCell* cell =
515 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
516 cell->set_value(value);
517 // Please note we have to update the property details.
518 property_dictionary()->DetailsAtPut(entry, details);
519 } else {
520 property_dictionary()->SetEntry(entry, name, value, details);
521 }
522 return value;
523}
524
525
John Reck59135872010-11-02 12:39:01 -0700526MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000527 ASSERT(!HasFastProperties());
528 StringDictionary* dictionary = property_dictionary();
529 int entry = dictionary->FindEntry(name);
530 if (entry != StringDictionary::kNotFound) {
531 // If we have a global object set the cell to the hole.
532 if (IsGlobalObject()) {
533 PropertyDetails details = dictionary->DetailsAt(entry);
534 if (details.IsDontDelete()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100535 if (mode != FORCE_DELETION) return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000536 // When forced to delete global properties, we have to make a
537 // map change to invalidate any ICs that think they can load
538 // from the DontDelete cell without checking if it contains
539 // the hole value.
John Reck59135872010-11-02 12:39:01 -0700540 Object* new_map;
541 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
542 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
543 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000544 set_map(Map::cast(new_map));
545 }
546 JSGlobalPropertyCell* cell =
547 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000548 cell->set_value(cell->GetHeap()->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000549 dictionary->DetailsAtPut(entry, details.AsDeleted());
550 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000551 Object* deleted = dictionary->DeleteProperty(entry, mode);
552 if (deleted == GetHeap()->true_value()) {
553 FixedArray* new_properties = NULL;
554 MaybeObject* maybe_properties = dictionary->Shrink(name);
555 if (!maybe_properties->To(&new_properties)) {
556 return maybe_properties;
557 }
558 set_properties(new_properties);
559 }
560 return deleted;
Steve Blocka7e24c12009-10-30 11:49:00 +0000561 }
562 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100563 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000564}
565
566
567bool JSObject::IsDirty() {
568 Object* cons_obj = map()->constructor();
569 if (!cons_obj->IsJSFunction())
570 return true;
571 JSFunction* fun = JSFunction::cast(cons_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100572 if (!fun->shared()->IsApiFunction())
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 return true;
574 // If the object is fully fast case and has the same map it was
575 // created with then no changes can have been made to it.
576 return map() != fun->initial_map()
577 || !HasFastElements()
578 || !HasFastProperties();
579}
580
581
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000582Handle<Object> Object::GetProperty(Handle<Object> object,
583 Handle<Object> receiver,
584 LookupResult* result,
585 Handle<String> key,
586 PropertyAttributes* attributes) {
587 Isolate* isolate = object->IsHeapObject()
588 ? Handle<HeapObject>::cast(object)->GetIsolate()
589 : Isolate::Current();
590 CALL_HEAP_FUNCTION(
591 isolate,
592 object->GetProperty(*receiver, result, *key, attributes),
593 Object);
594}
595
596
John Reck59135872010-11-02 12:39:01 -0700597MaybeObject* Object::GetProperty(Object* receiver,
598 LookupResult* result,
599 String* name,
600 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 // Make sure that the top context does not change when doing
602 // callbacks or interceptor calls.
603 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +0100604 Heap* heap = name->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000605
606 // Traverse the prototype chain from the current object (this) to
Ben Murdoch257744e2011-11-30 15:57:28 +0000607 // the holder and check for access rights. This avoids traversing the
Steve Blocka7e24c12009-10-30 11:49:00 +0000608 // objects more than once in case of interceptors, because the
609 // holder will always be the interceptor holder and the search may
610 // only continue with a current object just after the interceptor
611 // holder in the prototype chain.
Ben Murdoch257744e2011-11-30 15:57:28 +0000612 // Proxy handlers do not use the proxy's prototype, so we can skip this.
613 if (!result->IsHandler()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000614 Object* last = result->IsProperty()
615 ? result->holder()
616 : Object::cast(heap->null_value());
Ben Murdoch257744e2011-11-30 15:57:28 +0000617 ASSERT(this != this->GetPrototype());
618 for (Object* current = this; true; current = current->GetPrototype()) {
619 if (current->IsAccessCheckNeeded()) {
620 // Check if we're allowed to read from the current object. Note
621 // that even though we may not actually end up loading the named
622 // property from the current object, we still check that we have
623 // access to it.
624 JSObject* checked = JSObject::cast(current);
625 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
626 return checked->GetPropertyWithFailedAccessCheck(receiver,
627 result,
628 name,
629 attributes);
630 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000631 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000632 // Stop traversing the chain once we reach the last object in the
633 // chain; either the holder of the result or null in case of an
634 // absent property.
635 if (current == last) break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000636 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000637 }
638
639 if (!result->IsProperty()) {
640 *attributes = ABSENT;
Steve Block44f0eee2011-05-26 01:26:41 +0100641 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000642 }
643 *attributes = result->GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +0000644 Object* value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000645 switch (result->type()) {
646 case NORMAL:
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000647 value = result->holder()->GetNormalizedProperty(result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000648 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100649 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000650 case FIELD:
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000651 value = result->holder()->FastPropertyAt(result->GetFieldIndex());
Steve Blocka7e24c12009-10-30 11:49:00 +0000652 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100653 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000654 case CONSTANT_FUNCTION:
655 return result->GetConstantFunction();
656 case CALLBACKS:
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000657 return result->holder()->GetPropertyWithCallback(
658 receiver, result->GetCallbackObject(), name);
659 case HANDLER:
660 return result->proxy()->GetPropertyWithHandler(receiver, name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000661 case INTERCEPTOR: {
662 JSObject* recvr = JSObject::cast(receiver);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000663 return result->holder()->GetPropertyWithInterceptor(
664 recvr, name, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000665 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000666 case MAP_TRANSITION:
Ben Murdoch589d6972011-11-30 16:04:58 +0000667 case ELEMENTS_TRANSITION:
Ben Murdoch257744e2011-11-30 15:57:28 +0000668 case CONSTANT_TRANSITION:
669 case NULL_DESCRIPTOR:
670 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000671 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000672 UNREACHABLE();
673 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000674}
675
676
John Reck59135872010-11-02 12:39:01 -0700677MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000678 Heap* heap = IsSmi()
679 ? Isolate::Current()->heap()
680 : HeapObject::cast(this)->GetHeap();
681 Object* holder = this;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100682
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000683 // Iterate up the prototype chain until an element is found or the null
684 // prototype is encountered.
685 for (holder = this;
686 holder != heap->null_value();
687 holder = holder->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000688 if (!holder->IsJSObject()) {
689 Isolate* isolate = heap->isolate();
690 Context* global_context = isolate->context()->global_context();
691 if (holder->IsNumber()) {
692 holder = global_context->number_function()->instance_prototype();
693 } else if (holder->IsString()) {
694 holder = global_context->string_function()->instance_prototype();
695 } else if (holder->IsBoolean()) {
696 holder = global_context->boolean_function()->instance_prototype();
697 } else if (holder->IsJSProxy()) {
698 return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
699 } else {
700 // Undefined and null have no indexed properties.
701 ASSERT(holder->IsUndefined() || holder->IsNull());
702 return heap->undefined_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000703 }
704 }
705
706 // Inline the case for JSObjects. Doing so significantly improves the
707 // performance of fetching elements where checking the prototype chain is
708 // necessary.
709 JSObject* js_object = JSObject::cast(holder);
710
711 // Check access rights if needed.
712 if (js_object->IsAccessCheckNeeded()) {
713 Isolate* isolate = heap->isolate();
714 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
715 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
716 return heap->undefined_value();
717 }
718 }
719
720 if (js_object->HasIndexedInterceptor()) {
721 return js_object->GetElementWithInterceptor(receiver, index);
722 }
723
724 if (js_object->elements() != heap->empty_fixed_array()) {
725 MaybeObject* result = js_object->GetElementsAccessor()->Get(
726 js_object->elements(),
727 index,
728 js_object,
729 receiver);
730 if (result != heap->the_hole_value()) return result;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100731 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100732 }
733
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000734 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000735}
736
737
738Object* Object::GetPrototype() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100739 if (IsSmi()) {
740 Heap* heap = Isolate::Current()->heap();
741 Context* context = heap->isolate()->context()->global_context();
742 return context->number_function()->instance_prototype();
743 }
744
745 HeapObject* heap_object = HeapObject::cast(this);
746
Ben Murdoch257744e2011-11-30 15:57:28 +0000747 // The object is either a number, a string, a boolean,
748 // a real JS object, or a Harmony proxy.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000749 if (heap_object->IsJSReceiver()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000750 return heap_object->map()->prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100751 }
752 Heap* heap = heap_object->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100753 Context* context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000754
Ben Murdoch8b112d22011-06-08 16:22:53 +0100755 if (heap_object->IsHeapNumber()) {
756 return context->number_function()->instance_prototype();
757 }
758 if (heap_object->IsString()) {
759 return context->string_function()->instance_prototype();
760 }
761 if (heap_object->IsBoolean()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000762 return context->boolean_function()->instance_prototype();
763 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100764 return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000765 }
766}
767
768
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000769MaybeObject* Object::GetHash(CreationFlag flag) {
770 // The object is either a number, a string, an odd-ball,
771 // a real JS object, or a Harmony proxy.
772 if (IsNumber()) {
773 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
774 return Smi::FromInt(hash & Smi::kMaxValue);
775 }
776 if (IsString()) {
777 uint32_t hash = String::cast(this)->Hash();
778 return Smi::FromInt(hash);
779 }
780 if (IsOddball()) {
781 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
782 return Smi::FromInt(hash);
783 }
784 if (IsJSReceiver()) {
785 return JSReceiver::cast(this)->GetIdentityHash(flag);
786 }
787
788 UNREACHABLE();
789 return Smi::FromInt(0);
790}
791
792
793bool Object::SameValue(Object* other) {
794 if (other == this) return true;
795 if (!IsHeapObject() || !other->IsHeapObject()) return false;
796
797 // The object is either a number, a string, an odd-ball,
798 // a real JS object, or a Harmony proxy.
799 if (IsNumber() && other->IsNumber()) {
800 double this_value = Number();
801 double other_value = other->Number();
802 return (this_value == other_value) ||
803 (isnan(this_value) && isnan(other_value));
804 }
805 if (IsString() && other->IsString()) {
806 return String::cast(this)->Equals(String::cast(other));
807 }
808 return false;
809}
810
811
Ben Murdochb0fe1622011-05-05 13:52:32 +0100812void Object::ShortPrint(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 HeapStringAllocator allocator;
814 StringStream accumulator(&allocator);
815 ShortPrint(&accumulator);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100816 accumulator.OutputToFile(out);
Steve Blocka7e24c12009-10-30 11:49:00 +0000817}
818
819
820void Object::ShortPrint(StringStream* accumulator) {
821 if (IsSmi()) {
822 Smi::cast(this)->SmiPrint(accumulator);
823 } else if (IsFailure()) {
824 Failure::cast(this)->FailurePrint(accumulator);
825 } else {
826 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
827 }
828}
829
830
Ben Murdochb0fe1622011-05-05 13:52:32 +0100831void Smi::SmiPrint(FILE* out) {
832 PrintF(out, "%d", value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000833}
834
835
836void Smi::SmiPrint(StringStream* accumulator) {
837 accumulator->Add("%d", value());
838}
839
840
841void Failure::FailurePrint(StringStream* accumulator) {
Steve Block3ce2e202009-11-05 08:53:23 +0000842 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000843}
844
845
Ben Murdochb0fe1622011-05-05 13:52:32 +0100846void Failure::FailurePrint(FILE* out) {
847 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000848}
849
850
Steve Blocka7e24c12009-10-30 11:49:00 +0000851// Should a word be prefixed by 'a' or 'an' in order to read naturally in
852// English? Returns false for non-ASCII or words that don't start with
853// a capital letter. The a/an rule follows pronunciation in English.
854// We don't use the BBC's overcorrect "an historic occasion" though if
855// you speak a dialect you may well say "an 'istoric occasion".
856static bool AnWord(String* str) {
857 if (str->length() == 0) return false; // A nothing.
858 int c0 = str->Get(0);
859 int c1 = str->length() > 1 ? str->Get(1) : 0;
860 if (c0 == 'U') {
861 if (c1 > 'Z') {
862 return true; // An Umpire, but a UTF8String, a U.
863 }
864 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
865 return true; // An Ape, an ABCBook.
866 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
867 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
868 c0 == 'S' || c0 == 'X')) {
869 return true; // An MP3File, an M.
870 }
871 return false;
872}
873
874
John Reck59135872010-11-02 12:39:01 -0700875MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000876#ifdef DEBUG
877 // Do not attempt to flatten in debug mode when allocation is not
878 // allowed. This is to avoid an assertion failure when allocating.
879 // Flattening strings is the only case where we always allow
880 // allocation because no GC is performed if the allocation fails.
Steve Block44f0eee2011-05-26 01:26:41 +0100881 if (!HEAP->IsAllocationAllowed()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000882#endif
883
Steve Block44f0eee2011-05-26 01:26:41 +0100884 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000885 switch (StringShape(this).representation_tag()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000886 case kConsStringTag: {
887 ConsString* cs = ConsString::cast(this);
888 if (cs->second()->length() == 0) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100889 return cs->first();
Steve Blocka7e24c12009-10-30 11:49:00 +0000890 }
891 // There's little point in putting the flat string in new space if the
892 // cons string is in old space. It can never get GCed until there is
893 // an old space GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100894 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +0000895 int len = length();
896 Object* object;
897 String* result;
898 if (IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100899 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700900 if (!maybe_object->ToObject(&object)) return maybe_object;
901 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000902 result = String::cast(object);
903 String* first = cs->first();
904 int first_length = first->length();
905 char* dest = SeqAsciiString::cast(result)->GetChars();
906 WriteToFlat(first, dest, 0, first_length);
907 String* second = cs->second();
908 WriteToFlat(second,
909 dest + first_length,
910 0,
911 len - first_length);
912 } else {
John Reck59135872010-11-02 12:39:01 -0700913 { MaybeObject* maybe_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100914 heap->AllocateRawTwoByteString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700915 if (!maybe_object->ToObject(&object)) return maybe_object;
916 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000917 result = String::cast(object);
918 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
919 String* first = cs->first();
920 int first_length = first->length();
921 WriteToFlat(first, dest, 0, first_length);
922 String* second = cs->second();
923 WriteToFlat(second,
924 dest + first_length,
925 0,
926 len - first_length);
927 }
928 cs->set_first(result);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000929 cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
Leon Clarkef7060e22010-06-03 12:02:55 +0100930 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000931 }
932 default:
933 return this;
934 }
935}
936
937
938bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +0100939 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100940 // prohibited by the API.
941 ASSERT(!this->IsExternalString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000942#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000943 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000944 // Assert that the resource and the string are equivalent.
945 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100946 ScopedVector<uc16> smart_chars(this->length());
947 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
948 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000949 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100950 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000951 }
952#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100953 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000954 int size = this->Size(); // Byte size of the original string.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000955 if (size < ExternalString::kShortSize) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000956 return false;
957 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100958 bool is_ascii = this->IsAsciiRepresentation();
Steve Blocka7e24c12009-10-30 11:49:00 +0000959 bool is_symbol = this->IsSymbol();
Steve Blocka7e24c12009-10-30 11:49:00 +0000960
961 // Morph the object to an external string by adjusting the map and
962 // reinitializing the fields.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000963 if (size >= ExternalString::kSize) {
964 this->set_map(
965 is_symbol
966 ? (is_ascii ? heap->external_symbol_with_ascii_data_map()
967 : heap->external_symbol_map())
968 : (is_ascii ? heap->external_string_with_ascii_data_map()
969 : heap->external_string_map()));
970 } else {
971 this->set_map(
972 is_symbol
973 ? (is_ascii ? heap->short_external_symbol_with_ascii_data_map()
974 : heap->short_external_symbol_map())
975 : (is_ascii ? heap->short_external_string_with_ascii_data_map()
976 : heap->short_external_string_map()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000977 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000978 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
979 self->set_resource(resource);
980 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
Steve Blocka7e24c12009-10-30 11:49:00 +0000981
982 // Fill the remainder of the string with dead wood.
983 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100984 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000985 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
986 MemoryChunk::IncrementLiveBytes(this->address(), new_size - size);
987 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000988 return true;
989}
990
991
992bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
993#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000994 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000995 // Assert that the resource and the string are equivalent.
996 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100997 ScopedVector<char> smart_chars(this->length());
998 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
999 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001000 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001001 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001002 }
1003#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +01001004 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001005 int size = this->Size(); // Byte size of the original string.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001006 if (size < ExternalString::kShortSize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001007 return false;
1008 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001009 bool is_symbol = this->IsSymbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001010
1011 // Morph the object to an external string by adjusting the map and
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001012 // reinitializing the fields. Use short version if space is limited.
1013 if (size >= ExternalString::kSize) {
1014 this->set_map(is_symbol ? heap->external_ascii_symbol_map()
1015 : heap->external_ascii_string_map());
1016 } else {
1017 this->set_map(is_symbol ? heap->short_external_ascii_symbol_map()
1018 : heap->short_external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001019 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001020 ExternalAsciiString* self = ExternalAsciiString::cast(this);
1021 self->set_resource(resource);
1022 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001023
1024 // Fill the remainder of the string with dead wood.
1025 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +01001026 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001027 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
1028 MemoryChunk::IncrementLiveBytes(this->address(), new_size - size);
1029 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001030 return true;
1031}
1032
1033
1034void String::StringShortPrint(StringStream* accumulator) {
1035 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +00001036 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001037 accumulator->Add("<Very long string[%u]>", len);
1038 return;
1039 }
1040
1041 if (!LooksValid()) {
1042 accumulator->Add("<Invalid String>");
1043 return;
1044 }
1045
1046 StringInputBuffer buf(this);
1047
1048 bool truncated = false;
1049 if (len > kMaxShortPrintLength) {
1050 len = kMaxShortPrintLength;
1051 truncated = true;
1052 }
1053 bool ascii = true;
1054 for (int i = 0; i < len; i++) {
1055 int c = buf.GetNext();
1056
1057 if (c < 32 || c >= 127) {
1058 ascii = false;
1059 }
1060 }
1061 buf.Reset(this);
1062 if (ascii) {
1063 accumulator->Add("<String[%u]: ", length());
1064 for (int i = 0; i < len; i++) {
1065 accumulator->Put(buf.GetNext());
1066 }
1067 accumulator->Put('>');
1068 } else {
1069 // Backslash indicates that the string contains control
1070 // characters and that backslashes are therefore escaped.
1071 accumulator->Add("<String[%u]\\: ", length());
1072 for (int i = 0; i < len; i++) {
1073 int c = buf.GetNext();
1074 if (c == '\n') {
1075 accumulator->Add("\\n");
1076 } else if (c == '\r') {
1077 accumulator->Add("\\r");
1078 } else if (c == '\\') {
1079 accumulator->Add("\\\\");
1080 } else if (c < 32 || c > 126) {
1081 accumulator->Add("\\x%02x", c);
1082 } else {
1083 accumulator->Put(c);
1084 }
1085 }
1086 if (truncated) {
1087 accumulator->Put('.');
1088 accumulator->Put('.');
1089 accumulator->Put('.');
1090 }
1091 accumulator->Put('>');
1092 }
1093 return;
1094}
1095
1096
1097void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1098 switch (map()->instance_type()) {
1099 case JS_ARRAY_TYPE: {
1100 double length = JSArray::cast(this)->length()->Number();
1101 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
1102 break;
1103 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001104 case JS_WEAK_MAP_TYPE: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001105 accumulator->Add("<JS WeakMap>");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001106 break;
1107 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001108 case JS_REGEXP_TYPE: {
1109 accumulator->Add("<JS RegExp>");
1110 break;
1111 }
1112 case JS_FUNCTION_TYPE: {
1113 Object* fun_name = JSFunction::cast(this)->shared()->name();
1114 bool printed = false;
1115 if (fun_name->IsString()) {
1116 String* str = String::cast(fun_name);
1117 if (str->length() > 0) {
1118 accumulator->Add("<JS Function ");
1119 accumulator->Put(str);
1120 accumulator->Put('>');
1121 printed = true;
1122 }
1123 }
1124 if (!printed) {
1125 accumulator->Add("<JS Function>");
1126 }
1127 break;
1128 }
1129 // All other JSObjects are rather similar to each other (JSObject,
1130 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1131 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001132 Map* map_of_this = map();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001133 Heap* heap = GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001134 Object* constructor = map_of_this->constructor();
Steve Blocka7e24c12009-10-30 11:49:00 +00001135 bool printed = false;
1136 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001137 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001138 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1139 } else {
1140 bool global_object = IsJSGlobalProxy();
1141 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001142 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001143 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1144 } else {
1145 Object* constructor_name =
1146 JSFunction::cast(constructor)->shared()->name();
1147 if (constructor_name->IsString()) {
1148 String* str = String::cast(constructor_name);
1149 if (str->length() > 0) {
1150 bool vowel = AnWord(str);
1151 accumulator->Add("<%sa%s ",
1152 global_object ? "Global Object: " : "",
1153 vowel ? "n" : "");
1154 accumulator->Put(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00001155 printed = true;
1156 }
1157 }
1158 }
1159 }
1160 if (!printed) {
1161 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1162 }
1163 }
1164 if (IsJSValue()) {
1165 accumulator->Add(" value = ");
1166 JSValue::cast(this)->value()->ShortPrint(accumulator);
1167 }
1168 accumulator->Put('>');
1169 break;
1170 }
1171 }
1172}
1173
1174
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001175void JSObject::PrintElementsTransition(
1176 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1177 ElementsKind to_kind, FixedArrayBase* to_elements) {
1178 if (from_kind != to_kind) {
1179 PrintF(file, "elements transition [");
1180 PrintElementsKind(file, from_kind);
1181 PrintF(file, " -> ");
1182 PrintElementsKind(file, to_kind);
1183 PrintF(file, "] in ");
1184 JavaScriptFrame::PrintTop(file, false, true);
1185 PrintF(file, " for ");
1186 ShortPrint(file);
1187 PrintF(file, " from ");
1188 from_elements->ShortPrint(file);
1189 PrintF(file, " to ");
1190 to_elements->ShortPrint(file);
1191 PrintF(file, "\n");
1192 }
1193}
1194
1195
Steve Blocka7e24c12009-10-30 11:49:00 +00001196void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
Steve Block44f0eee2011-05-26 01:26:41 +01001197 Heap* heap = GetHeap();
1198 if (!heap->Contains(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001199 accumulator->Add("!!!INVALID POINTER!!!");
1200 return;
1201 }
Steve Block44f0eee2011-05-26 01:26:41 +01001202 if (!heap->Contains(map())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001203 accumulator->Add("!!!INVALID MAP!!!");
1204 return;
1205 }
1206
1207 accumulator->Add("%p ", this);
1208
1209 if (IsString()) {
1210 String::cast(this)->StringShortPrint(accumulator);
1211 return;
1212 }
1213 if (IsJSObject()) {
1214 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1215 return;
1216 }
1217 switch (map()->instance_type()) {
1218 case MAP_TYPE:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001219 accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
Steve Blocka7e24c12009-10-30 11:49:00 +00001220 break;
1221 case FIXED_ARRAY_TYPE:
1222 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1223 break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001224 case FIXED_DOUBLE_ARRAY_TYPE:
1225 accumulator->Add("<FixedDoubleArray[%u]>",
1226 FixedDoubleArray::cast(this)->length());
1227 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001228 case BYTE_ARRAY_TYPE:
1229 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1230 break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001231 case FREE_SPACE_TYPE:
1232 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1233 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001234 case EXTERNAL_PIXEL_ARRAY_TYPE:
1235 accumulator->Add("<ExternalPixelArray[%u]>",
1236 ExternalPixelArray::cast(this)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00001237 break;
Steve Block3ce2e202009-11-05 08:53:23 +00001238 case EXTERNAL_BYTE_ARRAY_TYPE:
1239 accumulator->Add("<ExternalByteArray[%u]>",
1240 ExternalByteArray::cast(this)->length());
1241 break;
1242 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1243 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1244 ExternalUnsignedByteArray::cast(this)->length());
1245 break;
1246 case EXTERNAL_SHORT_ARRAY_TYPE:
1247 accumulator->Add("<ExternalShortArray[%u]>",
1248 ExternalShortArray::cast(this)->length());
1249 break;
1250 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1251 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1252 ExternalUnsignedShortArray::cast(this)->length());
1253 break;
1254 case EXTERNAL_INT_ARRAY_TYPE:
1255 accumulator->Add("<ExternalIntArray[%u]>",
1256 ExternalIntArray::cast(this)->length());
1257 break;
1258 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1259 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1260 ExternalUnsignedIntArray::cast(this)->length());
1261 break;
1262 case EXTERNAL_FLOAT_ARRAY_TYPE:
1263 accumulator->Add("<ExternalFloatArray[%u]>",
1264 ExternalFloatArray::cast(this)->length());
1265 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001266 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1267 accumulator->Add("<ExternalDoubleArray[%u]>",
1268 ExternalDoubleArray::cast(this)->length());
1269 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001270 case SHARED_FUNCTION_INFO_TYPE:
1271 accumulator->Add("<SharedFunctionInfo>");
1272 break;
Steve Block1e0659c2011-05-24 12:43:12 +01001273 case JS_MESSAGE_OBJECT_TYPE:
1274 accumulator->Add("<JSMessageObject>");
1275 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001276#define MAKE_STRUCT_CASE(NAME, Name, name) \
1277 case NAME##_TYPE: \
1278 accumulator->Put('<'); \
1279 accumulator->Add(#Name); \
1280 accumulator->Put('>'); \
1281 break;
1282 STRUCT_LIST(MAKE_STRUCT_CASE)
1283#undef MAKE_STRUCT_CASE
1284 case CODE_TYPE:
1285 accumulator->Add("<Code>");
1286 break;
1287 case ODDBALL_TYPE: {
1288 if (IsUndefined())
1289 accumulator->Add("<undefined>");
1290 else if (IsTheHole())
1291 accumulator->Add("<the hole>");
1292 else if (IsNull())
1293 accumulator->Add("<null>");
1294 else if (IsTrue())
1295 accumulator->Add("<true>");
1296 else if (IsFalse())
1297 accumulator->Add("<false>");
1298 else
1299 accumulator->Add("<Odd Oddball>");
1300 break;
1301 }
1302 case HEAP_NUMBER_TYPE:
1303 accumulator->Add("<Number: ");
1304 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1305 accumulator->Put('>');
1306 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00001307 case JS_PROXY_TYPE:
1308 accumulator->Add("<JSProxy>");
1309 break;
1310 case JS_FUNCTION_PROXY_TYPE:
1311 accumulator->Add("<JSFunctionProxy>");
1312 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001313 case FOREIGN_TYPE:
1314 accumulator->Add("<Foreign>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001315 break;
1316 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1317 accumulator->Add("Cell for ");
1318 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1319 break;
1320 default:
1321 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1322 break;
1323 }
1324}
1325
1326
Steve Blocka7e24c12009-10-30 11:49:00 +00001327void HeapObject::Iterate(ObjectVisitor* v) {
1328 // Handle header
1329 IteratePointer(v, kMapOffset);
1330 // Handle object body
1331 Map* m = map();
1332 IterateBody(m->instance_type(), SizeFromMap(m), v);
1333}
1334
1335
1336void HeapObject::IterateBody(InstanceType type, int object_size,
1337 ObjectVisitor* v) {
1338 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1339 // During GC, the map pointer field is encoded.
1340 if (type < FIRST_NONSTRING_TYPE) {
1341 switch (type & kStringRepresentationMask) {
1342 case kSeqStringTag:
1343 break;
1344 case kConsStringTag:
Iain Merrick75681382010-08-19 15:07:18 +01001345 ConsString::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001346 break;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001347 case kSlicedStringTag:
1348 SlicedString::BodyDescriptor::IterateBody(this, v);
1349 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001350 case kExternalStringTag:
1351 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1352 reinterpret_cast<ExternalAsciiString*>(this)->
1353 ExternalAsciiStringIterateBody(v);
1354 } else {
1355 reinterpret_cast<ExternalTwoByteString*>(this)->
1356 ExternalTwoByteStringIterateBody(v);
1357 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001358 break;
1359 }
1360 return;
1361 }
1362
1363 switch (type) {
1364 case FIXED_ARRAY_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001365 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001366 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001367 case FIXED_DOUBLE_ARRAY_TYPE:
1368 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001369 case JS_OBJECT_TYPE:
1370 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1371 case JS_VALUE_TYPE:
1372 case JS_ARRAY_TYPE:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001373 case JS_SET_TYPE:
1374 case JS_MAP_TYPE:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001375 case JS_WEAK_MAP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001376 case JS_REGEXP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001377 case JS_GLOBAL_PROXY_TYPE:
1378 case JS_GLOBAL_OBJECT_TYPE:
1379 case JS_BUILTINS_OBJECT_TYPE:
Steve Block1e0659c2011-05-24 12:43:12 +01001380 case JS_MESSAGE_OBJECT_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001381 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001382 break;
Steve Block791712a2010-08-27 10:21:07 +01001383 case JS_FUNCTION_TYPE:
1384 reinterpret_cast<JSFunction*>(this)
1385 ->JSFunctionIterateBody(object_size, v);
1386 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001387 case ODDBALL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001388 Oddball::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001389 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001390 case JS_PROXY_TYPE:
1391 JSProxy::BodyDescriptor::IterateBody(this, v);
1392 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00001393 case JS_FUNCTION_PROXY_TYPE:
1394 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1395 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001396 case FOREIGN_TYPE:
1397 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001398 break;
1399 case MAP_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001400 Map::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001401 break;
1402 case CODE_TYPE:
1403 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1404 break;
1405 case JS_GLOBAL_PROPERTY_CELL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001406 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001407 break;
1408 case HEAP_NUMBER_TYPE:
1409 case FILLER_TYPE:
1410 case BYTE_ARRAY_TYPE:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001411 case FREE_SPACE_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01001412 case EXTERNAL_PIXEL_ARRAY_TYPE:
Steve Block3ce2e202009-11-05 08:53:23 +00001413 case EXTERNAL_BYTE_ARRAY_TYPE:
1414 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1415 case EXTERNAL_SHORT_ARRAY_TYPE:
1416 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1417 case EXTERNAL_INT_ARRAY_TYPE:
1418 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1419 case EXTERNAL_FLOAT_ARRAY_TYPE:
Ben Murdoch257744e2011-11-30 15:57:28 +00001420 case EXTERNAL_DOUBLE_ARRAY_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001421 break;
Iain Merrick75681382010-08-19 15:07:18 +01001422 case SHARED_FUNCTION_INFO_TYPE:
1423 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001424 break;
Iain Merrick75681382010-08-19 15:07:18 +01001425
Steve Blocka7e24c12009-10-30 11:49:00 +00001426#define MAKE_STRUCT_CASE(NAME, Name, name) \
1427 case NAME##_TYPE:
1428 STRUCT_LIST(MAKE_STRUCT_CASE)
1429#undef MAKE_STRUCT_CASE
Iain Merrick75681382010-08-19 15:07:18 +01001430 StructBodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001431 break;
1432 default:
1433 PrintF("Unknown type: %d\n", type);
1434 UNREACHABLE();
1435 }
1436}
1437
1438
Steve Blocka7e24c12009-10-30 11:49:00 +00001439Object* HeapNumber::HeapNumberToBoolean() {
1440 // NaN, +0, and -0 should return the false object
Iain Merrick75681382010-08-19 15:07:18 +01001441#if __BYTE_ORDER == __LITTLE_ENDIAN
1442 union IeeeDoubleLittleEndianArchType u;
1443#elif __BYTE_ORDER == __BIG_ENDIAN
1444 union IeeeDoubleBigEndianArchType u;
1445#endif
1446 u.d = value();
1447 if (u.bits.exp == 2047) {
1448 // Detect NaN for IEEE double precision floating point.
1449 if ((u.bits.man_low | u.bits.man_high) != 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001450 return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001451 }
Iain Merrick75681382010-08-19 15:07:18 +01001452 if (u.bits.exp == 0) {
1453 // Detect +0, and -0 for IEEE double precision floating point.
1454 if ((u.bits.man_low | u.bits.man_high) == 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001455 return GetHeap()->false_value();
Iain Merrick75681382010-08-19 15:07:18 +01001456 }
Steve Block44f0eee2011-05-26 01:26:41 +01001457 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001458}
1459
1460
Ben Murdochb0fe1622011-05-05 13:52:32 +01001461void HeapNumber::HeapNumberPrint(FILE* out) {
1462 PrintF(out, "%.16g", Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00001463}
1464
1465
1466void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1467 // The Windows version of vsnprintf can allocate when printing a %g string
1468 // into a buffer that may not be big enough. We don't want random memory
1469 // allocation when producing post-crash stack traces, so we print into a
1470 // buffer that is plenty big enough for any floating point number, then
1471 // print that using vsnprintf (which may truncate but never allocate if
1472 // there is no more space in the buffer).
1473 EmbeddedVector<char, 100> buffer;
1474 OS::SNPrintF(buffer, "%.16g", Number());
1475 accumulator->Add("%s", buffer.start());
1476}
1477
1478
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001479String* JSReceiver::class_name() {
1480 if (IsJSFunction() && IsJSFunctionProxy()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001481 return GetHeap()->function_class_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001482 }
1483 if (map()->constructor()->IsJSFunction()) {
1484 JSFunction* constructor = JSFunction::cast(map()->constructor());
1485 return String::cast(constructor->shared()->instance_class_name());
1486 }
1487 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001488 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001489}
1490
1491
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001492String* JSReceiver::constructor_name() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001493 if (map()->constructor()->IsJSFunction()) {
1494 JSFunction* constructor = JSFunction::cast(map()->constructor());
1495 String* name = String::cast(constructor->shared()->name());
Ben Murdochf87a2032010-10-22 12:50:53 +01001496 if (name->length() > 0) return name;
1497 String* inferred_name = constructor->shared()->inferred_name();
1498 if (inferred_name->length() > 0) return inferred_name;
1499 Object* proto = GetPrototype();
1500 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001501 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001502 // TODO(rossberg): what about proxies?
Steve Blocka7e24c12009-10-30 11:49:00 +00001503 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001504 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001505}
1506
1507
John Reck59135872010-11-02 12:39:01 -07001508MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1509 String* name,
1510 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001511 int index = new_map->PropertyIndexFor(name);
1512 if (map()->unused_property_fields() == 0) {
1513 ASSERT(map()->unused_property_fields() == 0);
1514 int new_unused = new_map->unused_property_fields();
John Reck59135872010-11-02 12:39:01 -07001515 Object* values;
1516 { MaybeObject* maybe_values =
1517 properties()->CopySize(properties()->length() + new_unused + 1);
1518 if (!maybe_values->ToObject(&values)) return maybe_values;
1519 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001520 set_properties(FixedArray::cast(values));
1521 }
1522 set_map(new_map);
1523 return FastPropertyAtPut(index, value);
1524}
1525
1526
Ben Murdoch8b112d22011-06-08 16:22:53 +01001527static bool IsIdentifier(UnicodeCache* cache,
1528 unibrow::CharacterStream* buffer) {
1529 // Checks whether the buffer contains an identifier (no escape).
1530 if (!buffer->has_more()) return false;
1531 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1532 return false;
1533 }
1534 while (buffer->has_more()) {
1535 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1536 return false;
1537 }
1538 }
1539 return true;
1540}
1541
1542
John Reck59135872010-11-02 12:39:01 -07001543MaybeObject* JSObject::AddFastProperty(String* name,
1544 Object* value,
1545 PropertyAttributes attributes) {
Steve Block1e0659c2011-05-24 12:43:12 +01001546 ASSERT(!IsJSGlobalProxy());
1547
Steve Blocka7e24c12009-10-30 11:49:00 +00001548 // Normalize the object if the name is an actual string (not the
1549 // hidden symbols) and is not a real identifier.
Steve Block44f0eee2011-05-26 01:26:41 +01001550 Isolate* isolate = GetHeap()->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00001551 StringInputBuffer buffer(name);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001552 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
Steve Block44f0eee2011-05-26 01:26:41 +01001553 && name != isolate->heap()->hidden_symbol()) {
John Reck59135872010-11-02 12:39:01 -07001554 Object* obj;
1555 { MaybeObject* maybe_obj =
1556 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1557 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1558 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001559 return AddSlowProperty(name, value, attributes);
1560 }
1561
1562 DescriptorArray* old_descriptors = map()->instance_descriptors();
1563 // Compute the new index for new field.
1564 int index = map()->NextFreePropertyIndex();
1565
1566 // Allocate new instance descriptors with (name, index) added
1567 FieldDescriptor new_field(name, index, attributes);
John Reck59135872010-11-02 12:39:01 -07001568 Object* new_descriptors;
1569 { MaybeObject* maybe_new_descriptors =
1570 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1571 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1572 return maybe_new_descriptors;
1573 }
1574 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001575
Steve Block44f0eee2011-05-26 01:26:41 +01001576 // Only allow map transition if the object isn't the global object and there
1577 // is not a transition for the name, or there's a transition for the name but
1578 // it's unrelated to properties.
1579 int descriptor_index = old_descriptors->Search(name);
1580
Ben Murdoch589d6972011-11-30 16:04:58 +00001581 // Element transitions are stored in the descriptor for property "", which is
1582 // not a identifier and should have forced a switch to slow properties above.
Steve Block44f0eee2011-05-26 01:26:41 +01001583 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
Ben Murdoch589d6972011-11-30 16:04:58 +00001584 old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
Steve Block44f0eee2011-05-26 01:26:41 +01001585 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
Ben Murdoch589d6972011-11-30 16:04:58 +00001586 old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
Steve Blocka7e24c12009-10-30 11:49:00 +00001587 bool allow_map_transition =
Steve Block44f0eee2011-05-26 01:26:41 +01001588 can_insert_transition &&
1589 (isolate->context()->global_context()->object_function()->map() != map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001590
1591 ASSERT(index < map()->inobject_properties() ||
1592 (index - map()->inobject_properties()) < properties()->length() ||
1593 map()->unused_property_fields() == 0);
1594 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001595 Object* r;
1596 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1597 if (!maybe_r->ToObject(&r)) return maybe_r;
1598 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001599 Map* new_map = Map::cast(r);
1600 if (allow_map_transition) {
1601 // Allocate new instance descriptors for the old map with map transition.
1602 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
John Reck59135872010-11-02 12:39:01 -07001603 Object* r;
1604 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1605 if (!maybe_r->ToObject(&r)) return maybe_r;
1606 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001607 old_descriptors = DescriptorArray::cast(r);
1608 }
1609
1610 if (map()->unused_property_fields() == 0) {
Steve Block8defd9f2010-07-08 12:39:36 +01001611 if (properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001612 Object* obj;
1613 { MaybeObject* maybe_obj =
1614 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1615 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1616 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001617 return AddSlowProperty(name, value, attributes);
1618 }
1619 // Make room for the new value
John Reck59135872010-11-02 12:39:01 -07001620 Object* values;
1621 { MaybeObject* maybe_values =
1622 properties()->CopySize(properties()->length() + kFieldsAdded);
1623 if (!maybe_values->ToObject(&values)) return maybe_values;
1624 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001625 set_properties(FixedArray::cast(values));
1626 new_map->set_unused_property_fields(kFieldsAdded - 1);
1627 } else {
1628 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1629 }
1630 // We have now allocated all the necessary objects.
1631 // All the changes can be applied at once, so they are atomic.
1632 map()->set_instance_descriptors(old_descriptors);
1633 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1634 set_map(new_map);
1635 return FastPropertyAtPut(index, value);
1636}
1637
1638
John Reck59135872010-11-02 12:39:01 -07001639MaybeObject* JSObject::AddConstantFunctionProperty(
1640 String* name,
1641 JSFunction* function,
1642 PropertyAttributes attributes) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001643 ASSERT(!GetHeap()->InNewSpace(function));
Leon Clarkee46be812010-01-19 14:06:41 +00001644
Steve Blocka7e24c12009-10-30 11:49:00 +00001645 // Allocate new instance descriptors with (name, function) added
1646 ConstantFunctionDescriptor d(name, function, attributes);
John Reck59135872010-11-02 12:39:01 -07001647 Object* new_descriptors;
1648 { MaybeObject* maybe_new_descriptors =
1649 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1650 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1651 return maybe_new_descriptors;
1652 }
1653 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001654
1655 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001656 Object* new_map;
1657 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1658 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1659 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001660
1661 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1662 Map::cast(new_map)->set_instance_descriptors(descriptors);
1663 Map* old_map = map();
1664 set_map(Map::cast(new_map));
1665
1666 // If the old map is the global object map (from new Object()),
1667 // then transitions are not added to it, so we are done.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001668 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01001669 if (old_map == heap->isolate()->context()->global_context()->
1670 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001671 return function;
1672 }
1673
1674 // Do not add CONSTANT_TRANSITIONS to global objects
1675 if (IsGlobalObject()) {
1676 return function;
1677 }
1678
1679 // Add a CONSTANT_TRANSITION descriptor to the old map,
1680 // so future assignments to this property on other objects
1681 // of the same type will create a normal field, not a constant function.
1682 // Don't do this for special properties, with non-trival attributes.
1683 if (attributes != NONE) {
1684 return function;
1685 }
Iain Merrick75681382010-08-19 15:07:18 +01001686 ConstTransitionDescriptor mark(name, Map::cast(new_map));
John Reck59135872010-11-02 12:39:01 -07001687 { MaybeObject* maybe_new_descriptors =
1688 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1689 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1690 // We have accomplished the main goal, so return success.
1691 return function;
1692 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001693 }
1694 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1695
1696 return function;
1697}
1698
1699
1700// Add property in slow mode
John Reck59135872010-11-02 12:39:01 -07001701MaybeObject* JSObject::AddSlowProperty(String* name,
1702 Object* value,
1703 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001704 ASSERT(!HasFastProperties());
1705 StringDictionary* dict = property_dictionary();
1706 Object* store_value = value;
1707 if (IsGlobalObject()) {
1708 // In case name is an orphaned property reuse the cell.
1709 int entry = dict->FindEntry(name);
1710 if (entry != StringDictionary::kNotFound) {
1711 store_value = dict->ValueAt(entry);
1712 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1713 // Assign an enumeration index to the property and update
1714 // SetNextEnumerationIndex.
1715 int index = dict->NextEnumerationIndex();
1716 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1717 dict->SetNextEnumerationIndex(index + 1);
1718 dict->SetEntry(entry, name, store_value, details);
1719 return value;
1720 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001721 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07001722 { MaybeObject* maybe_store_value =
Steve Block44f0eee2011-05-26 01:26:41 +01001723 heap->AllocateJSGlobalPropertyCell(value);
John Reck59135872010-11-02 12:39:01 -07001724 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1725 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001726 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1727 }
1728 PropertyDetails details = PropertyDetails(attributes, NORMAL);
John Reck59135872010-11-02 12:39:01 -07001729 Object* result;
1730 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1731 if (!maybe_result->ToObject(&result)) return maybe_result;
1732 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001733 if (dict != result) set_properties(StringDictionary::cast(result));
1734 return value;
1735}
1736
1737
John Reck59135872010-11-02 12:39:01 -07001738MaybeObject* JSObject::AddProperty(String* name,
1739 Object* value,
Steve Block44f0eee2011-05-26 01:26:41 +01001740 PropertyAttributes attributes,
1741 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001742 ASSERT(!IsJSGlobalProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001743 Map* map_of_this = map();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001744 Heap* heap = GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001745 if (!map_of_this->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001746 if (strict_mode == kNonStrictMode) {
1747 return heap->undefined_value();
1748 } else {
1749 Handle<Object> args[1] = {Handle<String>(name)};
1750 return heap->isolate()->Throw(
1751 *FACTORY->NewTypeError("object_not_extensible",
1752 HandleVector(args, 1)));
1753 }
Steve Block8defd9f2010-07-08 12:39:36 +01001754 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001755 if (HasFastProperties()) {
1756 // Ensure the descriptor array does not get too big.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001757 if (map_of_this->instance_descriptors()->number_of_descriptors() <
Steve Blocka7e24c12009-10-30 11:49:00 +00001758 DescriptorArray::kMaxNumberOfDescriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01001759 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001760 return AddConstantFunctionProperty(name,
1761 JSFunction::cast(value),
1762 attributes);
1763 } else {
1764 return AddFastProperty(name, value, attributes);
1765 }
1766 } else {
1767 // Normalize the object to prevent very large instance descriptors.
1768 // This eliminates unwanted N^2 allocation and lookup behavior.
John Reck59135872010-11-02 12:39:01 -07001769 Object* obj;
1770 { MaybeObject* maybe_obj =
1771 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1772 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1773 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001774 }
1775 }
1776 return AddSlowProperty(name, value, attributes);
1777}
1778
1779
John Reck59135872010-11-02 12:39:01 -07001780MaybeObject* JSObject::SetPropertyPostInterceptor(
1781 String* name,
1782 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001783 PropertyAttributes attributes,
1784 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001785 // Check local property, ignore interceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001786 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001787 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001788 if (result.IsFound()) {
1789 // An existing property, a map transition or a null descriptor was
1790 // found. Use set property to handle all these cases.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001791 return SetProperty(&result, name, value, attributes, strict_mode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001792 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001793 bool found = false;
1794 MaybeObject* result_object;
1795 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
1796 value,
1797 attributes,
1798 &found,
1799 strict_mode);
1800 if (found) return result_object;
Andrei Popescu402d9372010-02-26 13:31:12 +00001801 // Add a new real property.
Steve Block44f0eee2011-05-26 01:26:41 +01001802 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001803}
1804
1805
John Reck59135872010-11-02 12:39:01 -07001806MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1807 Object* value,
1808 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001809 StringDictionary* dictionary = property_dictionary();
1810 int old_index = dictionary->FindEntry(name);
1811 int new_enumeration_index = 0; // 0 means "Use the next available index."
1812 if (old_index != -1) {
1813 // All calls to ReplaceSlowProperty have had all transitions removed.
1814 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1815 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1816 }
1817
1818 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1819 return SetNormalizedProperty(name, value, new_details);
1820}
1821
Steve Blockd0582a62009-12-15 09:54:21 +00001822
John Reck59135872010-11-02 12:39:01 -07001823MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
Steve Blocka7e24c12009-10-30 11:49:00 +00001824 String* name,
1825 Object* new_value,
1826 PropertyAttributes attributes) {
1827 Map* old_map = map();
John Reck59135872010-11-02 12:39:01 -07001828 Object* result;
1829 { MaybeObject* maybe_result =
1830 ConvertDescriptorToField(name, new_value, attributes);
1831 if (!maybe_result->ToObject(&result)) return maybe_result;
1832 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001833 // If we get to this point we have succeeded - do not return failure
1834 // after this point. Later stuff is optional.
1835 if (!HasFastProperties()) {
1836 return result;
1837 }
1838 // Do not add transitions to the map of "new Object()".
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001839 if (map() == GetIsolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01001840 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001841 return result;
1842 }
1843
1844 MapTransitionDescriptor transition(name,
1845 map(),
1846 attributes);
John Reck59135872010-11-02 12:39:01 -07001847 Object* new_descriptors;
1848 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1849 CopyInsert(&transition, KEEP_TRANSITIONS);
1850 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1851 return result; // Yes, return _result_.
1852 }
1853 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001854 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1855 return result;
1856}
1857
1858
John Reck59135872010-11-02 12:39:01 -07001859MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1860 Object* new_value,
1861 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001862 if (map()->unused_property_fields() == 0 &&
Steve Block8defd9f2010-07-08 12:39:36 +01001863 properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001864 Object* obj;
1865 { MaybeObject* maybe_obj =
1866 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1867 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1868 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001869 return ReplaceSlowProperty(name, new_value, attributes);
1870 }
1871
1872 int index = map()->NextFreePropertyIndex();
1873 FieldDescriptor new_field(name, index, attributes);
1874 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
John Reck59135872010-11-02 12:39:01 -07001875 Object* descriptors_unchecked;
1876 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1877 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1878 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1879 return maybe_descriptors_unchecked;
1880 }
1881 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001882 DescriptorArray* new_descriptors =
1883 DescriptorArray::cast(descriptors_unchecked);
1884
1885 // Make a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001886 Object* new_map_unchecked;
1887 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1888 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1889 return maybe_new_map_unchecked;
1890 }
1891 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001892 Map* new_map = Map::cast(new_map_unchecked);
1893 new_map->set_instance_descriptors(new_descriptors);
1894
1895 // Make new properties array if necessary.
1896 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1897 int new_unused_property_fields = map()->unused_property_fields() - 1;
1898 if (map()->unused_property_fields() == 0) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001899 new_unused_property_fields = kFieldsAdded - 1;
John Reck59135872010-11-02 12:39:01 -07001900 Object* new_properties_object;
1901 { MaybeObject* maybe_new_properties_object =
1902 properties()->CopySize(properties()->length() + kFieldsAdded);
1903 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1904 return maybe_new_properties_object;
1905 }
1906 }
1907 new_properties = FixedArray::cast(new_properties_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001908 }
1909
1910 // Update pointers to commit changes.
1911 // Object points to the new map.
1912 new_map->set_unused_property_fields(new_unused_property_fields);
1913 set_map(new_map);
1914 if (new_properties) {
1915 set_properties(FixedArray::cast(new_properties));
1916 }
1917 return FastPropertyAtPut(index, new_value);
1918}
1919
1920
1921
John Reck59135872010-11-02 12:39:01 -07001922MaybeObject* JSObject::SetPropertyWithInterceptor(
1923 String* name,
1924 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001925 PropertyAttributes attributes,
1926 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001927 Isolate* isolate = GetIsolate();
1928 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001929 Handle<JSObject> this_handle(this);
1930 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001931 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001932 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1933 if (!interceptor->setter()->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001934 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1935 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001936 v8::AccessorInfo info(args.end());
1937 v8::NamedPropertySetter setter =
1938 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1939 v8::Handle<v8::Value> result;
1940 {
1941 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001942 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001943 Handle<Object> value_unhole(value->IsTheHole() ?
Steve Block44f0eee2011-05-26 01:26:41 +01001944 isolate->heap()->undefined_value() :
1945 value,
1946 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001947 result = setter(v8::Utils::ToLocal(name_handle),
1948 v8::Utils::ToLocal(value_unhole),
1949 info);
1950 }
Steve Block44f0eee2011-05-26 01:26:41 +01001951 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001952 if (!result.IsEmpty()) return *value_handle;
1953 }
John Reck59135872010-11-02 12:39:01 -07001954 MaybeObject* raw_result =
1955 this_handle->SetPropertyPostInterceptor(*name_handle,
1956 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001957 attributes,
1958 strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001959 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001960 return raw_result;
1961}
1962
1963
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001964MaybeObject* JSReceiver::SetProperty(String* name,
1965 Object* value,
1966 PropertyAttributes attributes,
1967 StrictModeFlag strict_mode) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001968 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001969 LocalLookup(name, &result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001970 return SetProperty(&result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001971}
1972
1973
John Reck59135872010-11-02 12:39:01 -07001974MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1975 String* name,
1976 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001977 JSObject* holder,
1978 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001979 Isolate* isolate = GetIsolate();
1980 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001981
1982 // We should never get here to initialize a const with the hole
1983 // value since a const declaration would conflict with the setter.
1984 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01001985 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001986
1987 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00001988 // data structure used to store the callbacks. Eventually foreign
Steve Blocka7e24c12009-10-30 11:49:00 +00001989 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00001990 if (structure->IsForeign()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001991 AccessorDescriptor* callback =
Ben Murdoch257744e2011-11-30 15:57:28 +00001992 reinterpret_cast<AccessorDescriptor*>(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001993 Foreign::cast(structure)->foreign_address());
John Reck59135872010-11-02 12:39:01 -07001994 MaybeObject* obj = (callback->setter)(this, value, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +01001995 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001996 if (obj->IsFailure()) return obj;
1997 return *value_handle;
1998 }
1999
2000 if (structure->IsAccessorInfo()) {
2001 // api style callbacks
2002 AccessorInfo* data = AccessorInfo::cast(structure);
2003 Object* call_obj = data->setter();
2004 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
2005 if (call_fun == NULL) return value;
2006 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002007 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
2008 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Steve Blocka7e24c12009-10-30 11:49:00 +00002009 v8::AccessorInfo info(args.end());
2010 {
2011 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002012 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002013 call_fun(v8::Utils::ToLocal(key),
2014 v8::Utils::ToLocal(value_handle),
2015 info);
2016 }
Steve Block44f0eee2011-05-26 01:26:41 +01002017 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002018 return *value_handle;
2019 }
2020
2021 if (structure->IsFixedArray()) {
2022 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002023 if (setter->IsSpecFunction()) {
2024 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2025 return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002026 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002027 if (strict_mode == kNonStrictMode) {
2028 return value;
2029 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002030 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002031 Handle<Object> holder_handle(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002032 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01002033 return isolate->Throw(
2034 *isolate->factory()->NewTypeError("no_setter_in_callback",
2035 HandleVector(args, 2)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002036 }
2037 }
2038
2039 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +01002040 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00002041}
2042
2043
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002044MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
2045 Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01002046 Isolate* isolate = GetIsolate();
2047 Handle<Object> value_handle(value, isolate);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002048 Handle<JSReceiver> fun(setter, isolate);
2049 Handle<JSReceiver> self(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002050#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01002051 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00002052 // Handle stepping into a setter if step into is active.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002053 // TODO(rossberg): should this apply to getters that are function proxies?
2054 if (debug->StepInActive() && fun->IsJSFunction()) {
2055 debug->HandleStepIn(
2056 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00002057 }
2058#endif
2059 bool has_pending_exception;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002060 Handle<Object> argv[] = { value_handle };
2061 Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +00002062 // Check for pending exception and return the result.
2063 if (has_pending_exception) return Failure::Exception();
2064 return *value_handle;
2065}
2066
2067
2068void JSObject::LookupCallbackSetterInPrototypes(String* name,
2069 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01002070 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002071 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002072 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002073 pt = pt->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002074 if (pt->IsJSProxy()) {
2075 return result->HandlerResult(JSProxy::cast(pt));
2076 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002077 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002078 if (result->IsProperty()) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01002079 if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
2080 // Found non-callback or read-only callback, stop looking.
2081 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002082 }
2083 }
2084 result->NotFound();
2085}
2086
2087
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002088MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
2089 uint32_t index,
2090 Object* value,
2091 bool* found,
2092 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002093 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002094 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002095 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002096 pt = pt->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002097 if (pt->IsJSProxy()) {
2098 String* name;
2099 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
2100 if (!maybe->To<String>(&name)) {
2101 *found = true; // Force abort
2102 return maybe;
2103 }
2104 return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
2105 name, value, NONE, strict_mode, found);
2106 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002107 if (!JSObject::cast(pt)->HasDictionaryElements()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002108 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00002109 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002110 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +00002111 int entry = dictionary->FindEntry(index);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002112 if (entry != NumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002113 PropertyDetails details = dictionary->DetailsAt(entry);
2114 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01002115 *found = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002116 return SetElementWithCallback(dictionary->ValueAt(entry),
2117 index,
2118 value,
2119 JSObject::cast(pt),
2120 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002121 }
2122 }
2123 }
Steve Block1e0659c2011-05-24 12:43:12 +01002124 *found = false;
Steve Block44f0eee2011-05-26 01:26:41 +01002125 return heap->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002126}
2127
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002128MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
2129 String* name,
2130 Object* value,
2131 PropertyAttributes attributes,
2132 bool* found,
2133 StrictModeFlag strict_mode) {
2134 Heap* heap = GetHeap();
2135 // We could not find a local property so let's check whether there is an
2136 // accessor that wants to handle the property.
2137 LookupResult accessor_result(heap->isolate());
2138 LookupCallbackSetterInPrototypes(name, &accessor_result);
2139 if (accessor_result.IsFound()) {
2140 *found = true;
2141 if (accessor_result.type() == CALLBACKS) {
2142 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2143 name,
2144 value,
2145 accessor_result.holder(),
2146 strict_mode);
2147 } else if (accessor_result.type() == HANDLER) {
2148 // There is a proxy in the prototype chain. Invoke its
2149 // getPropertyDescriptor trap.
2150 bool found = false;
2151 // SetPropertyWithHandlerIfDefiningSetter can cause GC,
2152 // make sure to use the handlified references after calling
2153 // the function.
2154 Handle<JSObject> self(this);
2155 Handle<String> hname(name);
2156 Handle<Object> hvalue(value);
2157 MaybeObject* result =
2158 accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
2159 name, value, attributes, strict_mode, &found);
2160 if (found) return result;
2161 // The proxy does not define the property as an accessor.
2162 // Consequently, it has no effect on setting the receiver.
2163 return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
2164 }
2165 }
2166 *found = false;
2167 return heap->the_hole_value();
2168}
2169
Steve Blocka7e24c12009-10-30 11:49:00 +00002170
2171void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
2172 DescriptorArray* descriptors = map()->instance_descriptors();
Iain Merrick75681382010-08-19 15:07:18 +01002173 int number = descriptors->SearchWithCache(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00002174 if (number != DescriptorArray::kNotFound) {
2175 result->DescriptorResult(this, descriptors->GetDetails(number), number);
2176 } else {
2177 result->NotFound();
2178 }
2179}
2180
2181
Ben Murdochb0fe1622011-05-05 13:52:32 +01002182void Map::LookupInDescriptors(JSObject* holder,
2183 String* name,
2184 LookupResult* result) {
2185 DescriptorArray* descriptors = instance_descriptors();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002186 DescriptorLookupCache* cache =
2187 GetHeap()->isolate()->descriptor_lookup_cache();
Steve Block44f0eee2011-05-26 01:26:41 +01002188 int number = cache->Lookup(descriptors, name);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002189 if (number == DescriptorLookupCache::kAbsent) {
2190 number = descriptors->Search(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002191 cache->Update(descriptors, name, number);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002192 }
2193 if (number != DescriptorArray::kNotFound) {
2194 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
2195 } else {
2196 result->NotFound();
2197 }
2198}
2199
2200
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002201static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2202 ASSERT(!map.is_null());
2203 for (int i = 0; i < maps->length(); ++i) {
2204 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2205 }
2206 return false;
2207}
Steve Block44f0eee2011-05-26 01:26:41 +01002208
Steve Block44f0eee2011-05-26 01:26:41 +01002209
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002210template <class T>
2211static Handle<T> MaybeNull(T* p) {
2212 if (p == NULL) return Handle<T>::null();
2213 return Handle<T>(p);
2214}
2215
2216
2217Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
2218 ElementsKind elms_kind = elements_kind();
2219 if (elms_kind == FAST_DOUBLE_ELEMENTS) {
2220 bool dummy = true;
2221 Handle<Map> fast_map =
2222 MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
2223 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2224 return fast_map;
Steve Block44f0eee2011-05-26 01:26:41 +01002225 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002226 return Handle<Map>::null();
2227 }
2228 if (elms_kind == FAST_SMI_ONLY_ELEMENTS) {
2229 bool dummy = true;
2230 Handle<Map> double_map =
2231 MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy));
2232 // In the current implementation, if the DOUBLE map doesn't exist, the
2233 // FAST map can't exist either.
2234 if (double_map.is_null()) return Handle<Map>::null();
2235 Handle<Map> fast_map =
2236 MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2237 &dummy));
2238 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2239 return fast_map;
2240 }
2241 if (ContainsMap(candidates, double_map)) return double_map;
2242 }
2243 return Handle<Map>::null();
2244}
Steve Block44f0eee2011-05-26 01:26:41 +01002245
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002246static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
2247 ElementsKind elements_kind) {
2248 if (descriptor_contents->IsMap()) {
2249 Map* map = Map::cast(descriptor_contents);
2250 if (map->elements_kind() == elements_kind) {
2251 return map;
2252 }
2253 return NULL;
2254 }
2255
2256 FixedArray* map_array = FixedArray::cast(descriptor_contents);
2257 for (int i = 0; i < map_array->length(); ++i) {
2258 Object* current = map_array->get(i);
2259 // Skip undefined slots, they are sentinels for reclaimed maps.
2260 if (!current->IsUndefined()) {
2261 Map* current_map = Map::cast(map_array->get(i));
2262 if (current_map->elements_kind() == elements_kind) {
2263 return current_map;
Steve Block44f0eee2011-05-26 01:26:41 +01002264 }
2265 }
2266 }
2267
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002268 return NULL;
2269}
2270
2271
2272static MaybeObject* AddElementsTransitionMapToDescriptor(
2273 Object* descriptor_contents,
2274 Map* new_map) {
2275 // Nothing was in the descriptor for an ELEMENTS_TRANSITION,
2276 // simply add the map.
2277 if (descriptor_contents == NULL) {
2278 return new_map;
2279 }
2280
2281 // There was already a map in the descriptor, create a 2-element FixedArray
2282 // to contain the existing map plus the new one.
2283 FixedArray* new_array;
2284 Heap* heap = new_map->GetHeap();
2285 if (descriptor_contents->IsMap()) {
2286 // Must tenure, DescriptorArray expects no new-space objects.
2287 MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED);
2288 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2289 return maybe_new_array;
2290 }
2291 new_array->set(0, descriptor_contents);
2292 new_array->set(1, new_map);
2293 return new_array;
2294 }
2295
2296 // The descriptor already contained a list of maps for different ElementKinds
2297 // of ELEMENTS_TRANSITION, first check the existing array for an undefined
2298 // slot, and if that's not available, create a FixedArray to hold the existing
2299 // maps plus the new one and fill it in.
2300 FixedArray* array = FixedArray::cast(descriptor_contents);
2301 for (int i = 0; i < array->length(); ++i) {
2302 if (array->get(i)->IsUndefined()) {
2303 array->set(i, new_map);
2304 return array;
2305 }
2306 }
2307
2308 // Must tenure, DescriptorArray expects no new-space objects.
2309 MaybeObject* maybe_new_array =
2310 heap->AllocateFixedArray(array->length() + 1, TENURED);
2311 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2312 return maybe_new_array;
2313 }
2314 int i = 0;
2315 while (i < array->length()) {
2316 new_array->set(i, array->get(i));
2317 ++i;
2318 }
2319 new_array->set(i, new_map);
2320 return new_array;
2321}
2322
2323
2324String* Map::elements_transition_sentinel_name() {
2325 return GetHeap()->empty_symbol();
2326}
2327
2328
2329Object* Map::GetDescriptorContents(String* sentinel_name,
2330 bool* safe_to_add_transition) {
2331 // Get the cached index for the descriptors lookup, or find and cache it.
2332 DescriptorArray* descriptors = instance_descriptors();
2333 DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache();
2334 int index = cache->Lookup(descriptors, sentinel_name);
2335 if (index == DescriptorLookupCache::kAbsent) {
2336 index = descriptors->Search(sentinel_name);
2337 cache->Update(descriptors, sentinel_name, index);
2338 }
2339 // If the transition already exists, return its descriptor.
2340 if (index != DescriptorArray::kNotFound) {
2341 PropertyDetails details(descriptors->GetDetails(index));
2342 if (details.type() == ELEMENTS_TRANSITION) {
2343 return descriptors->GetValue(index);
2344 } else {
2345 *safe_to_add_transition = false;
2346 }
2347 }
2348 return NULL;
2349}
2350
2351
2352Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
2353 bool* safe_to_add_transition) {
2354 // Special case: indirect SMI->FAST transition (cf. comment in
2355 // AddElementsTransition()).
2356 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2357 elements_kind == FAST_ELEMENTS) {
2358 Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
2359 safe_to_add_transition);
2360 if (double_map == NULL) return double_map;
2361 return double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2362 safe_to_add_transition);
2363 }
2364 Object* descriptor_contents = GetDescriptorContents(
2365 elements_transition_sentinel_name(), safe_to_add_transition);
2366 if (descriptor_contents != NULL) {
2367 Map* maybe_transition_map =
2368 GetElementsTransitionMapFromDescriptor(descriptor_contents,
2369 elements_kind);
2370 ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
2371 return maybe_transition_map;
2372 }
2373 return NULL;
2374}
2375
2376
2377MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
2378 Map* transitioned_map) {
2379 // The map transition graph should be a tree, therefore the transition
2380 // from SMI to FAST elements is not done directly, but by going through
2381 // DOUBLE elements first.
2382 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2383 elements_kind == FAST_ELEMENTS) {
2384 bool safe_to_add = true;
2385 Map* double_map = this->LookupElementsTransitionMap(
2386 FAST_DOUBLE_ELEMENTS, &safe_to_add);
2387 // This method is only called when safe_to_add_transition has been found
2388 // to be true earlier.
2389 ASSERT(safe_to_add);
2390
2391 if (double_map == NULL) {
2392 MaybeObject* maybe_map = this->CopyDropTransitions();
2393 if (!maybe_map->To(&double_map)) return maybe_map;
2394 double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
2395 MaybeObject* maybe_double_transition = this->AddElementsTransition(
2396 FAST_DOUBLE_ELEMENTS, double_map);
2397 if (maybe_double_transition->IsFailure()) return maybe_double_transition;
2398 }
2399 return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map);
2400 }
2401
2402 bool safe_to_add_transition = true;
2403 Object* descriptor_contents = GetDescriptorContents(
2404 elements_transition_sentinel_name(), &safe_to_add_transition);
2405 // This method is only called when safe_to_add_transition has been found
2406 // to be true earlier.
2407 ASSERT(safe_to_add_transition);
2408 MaybeObject* maybe_new_contents =
2409 AddElementsTransitionMapToDescriptor(descriptor_contents,
2410 transitioned_map);
2411 Object* new_contents;
2412 if (!maybe_new_contents->ToObject(&new_contents)) {
2413 return maybe_new_contents;
2414 }
2415
2416 ElementsTransitionDescriptor desc(elements_transition_sentinel_name(),
2417 new_contents);
2418 Object* new_descriptors;
2419 MaybeObject* maybe_new_descriptors =
2420 instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS);
2421 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2422 return maybe_new_descriptors;
2423 }
2424 set_instance_descriptors(DescriptorArray::cast(new_descriptors));
2425 return this;
2426}
2427
2428
2429Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
2430 ElementsKind to_kind) {
2431 Isolate* isolate = object->GetIsolate();
2432 CALL_HEAP_FUNCTION(isolate,
2433 object->GetElementsTransitionMap(to_kind),
2434 Map);
2435}
2436
2437
2438MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind to_kind) {
2439 Map* current_map = map();
2440 ElementsKind from_kind = current_map->elements_kind();
2441
2442 if (from_kind == to_kind) return current_map;
2443
2444 // Only objects with FastProperties can have DescriptorArrays and can track
2445 // element-related maps. Also don't add descriptors to maps that are shared.
2446 bool safe_to_add_transition = HasFastProperties() &&
2447 !current_map->IsUndefined() &&
2448 !current_map->is_shared();
2449
2450 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
2451 // with elements that switch back and forth between dictionary and fast
2452 // element mode.
2453 if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
2454 safe_to_add_transition = false;
2455 }
2456
2457 if (safe_to_add_transition) {
2458 // It's only safe to manipulate the descriptor array if it would be
2459 // safe to add a transition.
2460 Map* maybe_transition_map = current_map->LookupElementsTransitionMap(
2461 to_kind, &safe_to_add_transition);
2462 if (maybe_transition_map != NULL) {
2463 return maybe_transition_map;
2464 }
2465 }
2466
2467 Map* new_map = NULL;
2468
Ben Murdoch589d6972011-11-30 16:04:58 +00002469 // No transition to an existing map for the given ElementsKind. Make a new
2470 // one.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002471 { MaybeObject* maybe_map = current_map->CopyDropTransitions();
2472 if (!maybe_map->To(&new_map)) return maybe_map;
Steve Block44f0eee2011-05-26 01:26:41 +01002473 }
Steve Block44f0eee2011-05-26 01:26:41 +01002474
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002475 new_map->set_elements_kind(to_kind);
Steve Block44f0eee2011-05-26 01:26:41 +01002476
2477 // Only remember the map transition if the object's map is NOT equal to the
2478 // global object_function's map and there is not an already existing
Ben Murdoch589d6972011-11-30 16:04:58 +00002479 // non-matching element transition.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002480 bool allow_map_transition = safe_to_add_transition &&
Steve Block44f0eee2011-05-26 01:26:41 +01002481 (GetIsolate()->context()->global_context()->object_function()->map() !=
2482 map());
2483 if (allow_map_transition) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002484 MaybeObject* maybe_transition =
2485 current_map->AddElementsTransition(to_kind, new_map);
2486 if (maybe_transition->IsFailure()) return maybe_transition;
Steve Block44f0eee2011-05-26 01:26:41 +01002487 }
Steve Block44f0eee2011-05-26 01:26:41 +01002488 return new_map;
2489}
2490
2491
Steve Blocka7e24c12009-10-30 11:49:00 +00002492void JSObject::LocalLookupRealNamedProperty(String* name,
2493 LookupResult* result) {
2494 if (IsJSGlobalProxy()) {
2495 Object* proto = GetPrototype();
2496 if (proto->IsNull()) return result->NotFound();
2497 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002498 // A GlobalProxy's prototype should always be a proper JSObject.
Steve Blocka7e24c12009-10-30 11:49:00 +00002499 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2500 }
2501
2502 if (HasFastProperties()) {
2503 LookupInDescriptor(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002504 if (result->IsFound()) {
2505 // A property, a map transition or a null descriptor was found.
2506 // We return all of these result types because
2507 // LocalLookupRealNamedProperty is used when setting properties
2508 // where map transitions and null descriptors are handled.
Steve Blocka7e24c12009-10-30 11:49:00 +00002509 ASSERT(result->holder() == this && result->type() != NORMAL);
2510 // Disallow caching for uninitialized constants. These can only
2511 // occur as fields.
2512 if (result->IsReadOnly() && result->type() == FIELD &&
2513 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2514 result->DisallowCaching();
2515 }
2516 return;
2517 }
2518 } else {
2519 int entry = property_dictionary()->FindEntry(name);
2520 if (entry != StringDictionary::kNotFound) {
2521 Object* value = property_dictionary()->ValueAt(entry);
2522 if (IsGlobalObject()) {
2523 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2524 if (d.IsDeleted()) {
2525 result->NotFound();
2526 return;
2527 }
2528 value = JSGlobalPropertyCell::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002529 }
2530 // Make sure to disallow caching for uninitialized constants
2531 // found in the dictionary-mode objects.
2532 if (value->IsTheHole()) result->DisallowCaching();
2533 result->DictionaryResult(this, entry);
2534 return;
2535 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002536 }
2537 result->NotFound();
2538}
2539
2540
2541void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2542 LocalLookupRealNamedProperty(name, result);
2543 if (result->IsProperty()) return;
2544
2545 LookupRealNamedPropertyInPrototypes(name, result);
2546}
2547
2548
2549void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2550 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01002551 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002552 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002553 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002554 pt = JSObject::cast(pt)->GetPrototype()) {
2555 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002556 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002557 }
2558 result->NotFound();
2559}
2560
2561
2562// We only need to deal with CALLBACKS and INTERCEPTORS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002563MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2564 LookupResult* result,
2565 String* name,
2566 Object* value,
2567 bool check_prototype,
2568 StrictModeFlag strict_mode) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002569 if (check_prototype && !result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002570 LookupCallbackSetterInPrototypes(name, result);
2571 }
2572
2573 if (result->IsProperty()) {
2574 if (!result->IsReadOnly()) {
2575 switch (result->type()) {
2576 case CALLBACKS: {
2577 Object* obj = result->GetCallbackObject();
2578 if (obj->IsAccessorInfo()) {
2579 AccessorInfo* info = AccessorInfo::cast(obj);
2580 if (info->all_can_write()) {
2581 return SetPropertyWithCallback(result->GetCallbackObject(),
2582 name,
2583 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002584 result->holder(),
2585 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002586 }
2587 }
2588 break;
2589 }
2590 case INTERCEPTOR: {
2591 // Try lookup real named properties. Note that only property can be
2592 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002593 LookupResult r(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002594 LookupRealNamedProperty(name, &r);
2595 if (r.IsProperty()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002596 return SetPropertyWithFailedAccessCheck(&r,
2597 name,
2598 value,
2599 check_prototype,
2600 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002601 }
2602 break;
2603 }
2604 default: {
2605 break;
2606 }
2607 }
2608 }
2609 }
2610
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002611 Isolate* isolate = GetIsolate();
2612 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002613 Handle<Object> value_handle(value);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002614 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
Iain Merrick75681382010-08-19 15:07:18 +01002615 return *value_handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00002616}
2617
2618
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002619MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2620 String* key,
2621 Object* value,
2622 PropertyAttributes attributes,
2623 StrictModeFlag strict_mode) {
2624 if (result->IsFound() && result->type() == HANDLER) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002625 return result->proxy()->SetPropertyWithHandler(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002626 key, value, attributes, strict_mode);
2627 } else {
2628 return JSObject::cast(this)->SetPropertyForResult(
2629 result, key, value, attributes, strict_mode);
2630 }
2631}
2632
2633
2634bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2635 Isolate* isolate = GetIsolate();
2636 HandleScope scope(isolate);
2637 Handle<Object> receiver(this);
2638 Handle<Object> name(name_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002639
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002640 Handle<Object> args[] = { name };
2641 Handle<Object> result = CallTrap(
2642 "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002643 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002644
2645 return result->ToBoolean()->IsTrue();
2646}
2647
2648
2649MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2650 String* name_raw,
2651 Object* value_raw,
2652 PropertyAttributes attributes,
2653 StrictModeFlag strict_mode) {
2654 Isolate* isolate = GetIsolate();
2655 HandleScope scope(isolate);
2656 Handle<Object> receiver(this);
2657 Handle<Object> name(name_raw);
2658 Handle<Object> value(value_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002659
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002660 Handle<Object> args[] = { receiver, name, value };
2661 CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002662 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002663
2664 return *value;
2665}
2666
2667
2668MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
2669 String* name_raw,
2670 Object* value_raw,
2671 PropertyAttributes attributes,
2672 StrictModeFlag strict_mode,
2673 bool* found) {
2674 *found = true; // except where defined otherwise...
2675 Isolate* isolate = GetHeap()->isolate();
2676 Handle<JSProxy> proxy(this);
2677 Handle<Object> handler(this->handler()); // Trap might morph proxy.
2678 Handle<String> name(name_raw);
2679 Handle<Object> value(value_raw);
2680 Handle<Object> args[] = { name };
2681 Handle<Object> result = proxy->CallTrap(
2682 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
2683 if (isolate->has_pending_exception()) return Failure::Exception();
2684
2685 if (!result->IsUndefined()) {
2686 // The proxy handler cares about this property.
2687 // Check whether it is virtualized as an accessor.
2688 // Emulate [[GetProperty]] semantics for proxies.
2689 bool has_pending_exception;
2690 Handle<Object> argv[] = { result };
2691 Handle<Object> desc =
2692 Execution::Call(isolate->to_complete_property_descriptor(), result,
2693 ARRAY_SIZE(argv), argv, &has_pending_exception);
2694 if (has_pending_exception) return Failure::Exception();
2695
2696 Handle<String> conf_name =
2697 isolate->factory()->LookupAsciiSymbol("configurable_");
2698 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
2699 ASSERT(!isolate->has_pending_exception());
2700 if (configurable->IsFalse()) {
2701 Handle<String> trap =
2702 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2703 Handle<Object> args[] = { handler, trap, name };
2704 Handle<Object> error = isolate->factory()->NewTypeError(
2705 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2706 return isolate->Throw(*error);
2707 }
2708 ASSERT(configurable->IsTrue());
2709
2710 // Check for AccessorDescriptor.
2711 Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
2712 Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
2713 ASSERT(!isolate->has_pending_exception());
2714 if (!setter->IsUndefined()) {
2715 // We have a setter -- invoke it.
2716 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2717 return proxy->SetPropertyWithDefinedSetter(
2718 JSReceiver::cast(*setter), *value);
2719 } else {
2720 Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
2721 Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
2722 ASSERT(!isolate->has_pending_exception());
2723 if (!getter->IsUndefined()) {
2724 // We have a getter but no setter -- the property may not be
2725 // written. In strict mode, throw an error.
2726 if (strict_mode == kNonStrictMode) return *value;
2727 Handle<Object> args[] = { name, proxy };
2728 Handle<Object> error = isolate->factory()->NewTypeError(
2729 "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
2730 return isolate->Throw(*error);
2731 }
2732 }
2733 // Fall-through.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002734 }
2735
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002736 // The proxy does not define the property as an accessor.
2737 *found = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002738 return *value;
2739}
2740
2741
2742MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2743 String* name_raw, DeleteMode mode) {
2744 Isolate* isolate = GetIsolate();
2745 HandleScope scope(isolate);
2746 Handle<Object> receiver(this);
2747 Handle<Object> name(name_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002748
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002749 Handle<Object> args[] = { name };
2750 Handle<Object> result = CallTrap(
2751 "delete", Handle<Object>(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002752 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002753
2754 Object* bool_result = result->ToBoolean();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002755 if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
2756 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2757 Handle<Object> args[] = { Handle<Object>(handler()), trap_name };
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002758 Handle<Object> error = isolate->factory()->NewTypeError(
2759 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2760 isolate->Throw(*error);
2761 return Failure::Exception();
2762 }
2763 return bool_result;
2764}
2765
2766
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002767MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
2768 uint32_t index,
2769 DeleteMode mode) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002770 Isolate* isolate = GetIsolate();
2771 HandleScope scope(isolate);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002772 Handle<String> name = isolate->factory()->Uint32ToString(index);
2773 return JSProxy::DeletePropertyWithHandler(*name, mode);
2774}
2775
2776
2777MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2778 JSReceiver* receiver_raw,
2779 String* name_raw) {
2780 Isolate* isolate = GetIsolate();
2781 HandleScope scope(isolate);
2782 Handle<JSProxy> proxy(this);
2783 Handle<Object> handler(this->handler()); // Trap might morph proxy.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002784 Handle<JSReceiver> receiver(receiver_raw);
2785 Handle<Object> name(name_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002786
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002787 Handle<Object> args[] = { name };
2788 Handle<Object> result = CallTrap(
2789 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002790 if (isolate->has_pending_exception()) return NONE;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002791
2792 if (result->IsUndefined()) return ABSENT;
2793
2794 bool has_pending_exception;
2795 Handle<Object> argv[] = { result };
2796 Handle<Object> desc =
2797 Execution::Call(isolate->to_complete_property_descriptor(), result,
2798 ARRAY_SIZE(argv), argv, &has_pending_exception);
2799 if (has_pending_exception) return NONE;
2800
2801 // Convert result to PropertyAttributes.
2802 Handle<String> enum_n = isolate->factory()->LookupAsciiSymbol("enumerable");
2803 Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_n));
2804 if (isolate->has_pending_exception()) return NONE;
2805 Handle<String> conf_n = isolate->factory()->LookupAsciiSymbol("configurable");
2806 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_n));
2807 if (isolate->has_pending_exception()) return NONE;
2808 Handle<String> writ_n = isolate->factory()->LookupAsciiSymbol("writable");
2809 Handle<Object> writable(v8::internal::GetProperty(desc, writ_n));
2810 if (isolate->has_pending_exception()) return NONE;
2811
2812 if (configurable->IsFalse()) {
2813 Handle<String> trap =
2814 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2815 Handle<Object> args[] = { handler, trap, name };
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002816 Handle<Object> error = isolate->factory()->NewTypeError(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002817 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002818 isolate->Throw(*error);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002819 return NONE;
2820 }
2821
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002822 int attributes = NONE;
2823 if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM;
2824 if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE;
2825 if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY;
2826 return static_cast<PropertyAttributes>(attributes);
2827}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002828
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002829
2830MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
2831 JSReceiver* receiver,
2832 uint32_t index) {
2833 Isolate* isolate = GetIsolate();
2834 HandleScope scope(isolate);
2835 Handle<String> name = isolate->factory()->Uint32ToString(index);
2836 return GetPropertyAttributeWithHandler(receiver, *name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002837}
2838
2839
2840void JSProxy::Fix() {
2841 Isolate* isolate = GetIsolate();
2842 HandleScope scope(isolate);
2843 Handle<JSProxy> self(this);
2844
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002845 // Save identity hash.
2846 MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
2847
Ben Murdoch589d6972011-11-30 16:04:58 +00002848 if (IsJSFunctionProxy()) {
2849 isolate->factory()->BecomeJSFunction(self);
2850 // Code will be set on the JavaScript side.
2851 } else {
2852 isolate->factory()->BecomeJSObject(self);
2853 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002854 ASSERT(self->IsJSObject());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002855
2856 // Inherit identity, if it was present.
2857 Object* hash;
2858 if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
2859 Handle<JSObject> new_self(JSObject::cast(*self));
2860 isolate->factory()->SetIdentityHash(new_self, hash);
2861 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002862}
2863
2864
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002865MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
2866 Handle<Object> derived,
2867 int argc,
2868 Handle<Object> argv[]) {
2869 Isolate* isolate = GetIsolate();
2870 Handle<Object> handler(this->handler());
2871
2872 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol(name);
2873 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2874 if (isolate->has_pending_exception()) return trap;
2875
2876 if (trap->IsUndefined()) {
2877 if (derived.is_null()) {
2878 Handle<Object> args[] = { handler, trap_name };
2879 Handle<Object> error = isolate->factory()->NewTypeError(
2880 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2881 isolate->Throw(*error);
2882 return Handle<Object>();
2883 }
2884 trap = Handle<Object>(derived);
2885 }
2886
2887 bool threw;
2888 return Execution::Call(trap, handler, argc, argv, &threw);
2889}
2890
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002891
2892MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
2893 String* name,
2894 Object* value,
2895 PropertyAttributes attributes,
2896 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002897 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002898 // Make sure that the top context does not change when doing callbacks or
2899 // interceptor calls.
2900 AssertNoContextChange ncc;
2901
Steve Blockd0582a62009-12-15 09:54:21 +00002902 // Optimization for 2-byte strings often used as keys in a decompression
2903 // dictionary. We make these short keys into symbols to avoid constantly
2904 // reallocating them.
2905 if (!name->IsSymbol() && name->length() <= 2) {
John Reck59135872010-11-02 12:39:01 -07002906 Object* symbol_version;
Steve Block44f0eee2011-05-26 01:26:41 +01002907 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
John Reck59135872010-11-02 12:39:01 -07002908 if (maybe_symbol_version->ToObject(&symbol_version)) {
2909 name = String::cast(symbol_version);
2910 }
2911 }
Steve Blockd0582a62009-12-15 09:54:21 +00002912 }
2913
Steve Blocka7e24c12009-10-30 11:49:00 +00002914 // Check access rights if needed.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002915 if (IsAccessCheckNeeded()) {
2916 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
2917 return SetPropertyWithFailedAccessCheck(
2918 result, name, value, true, strict_mode);
2919 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002920 }
2921
2922 if (IsJSGlobalProxy()) {
2923 Object* proto = GetPrototype();
2924 if (proto->IsNull()) return value;
2925 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002926 return JSObject::cast(proto)->SetPropertyForResult(
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002927 result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002928 }
2929
2930 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002931 bool found = false;
2932 MaybeObject* result_object;
2933 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
2934 value,
2935 attributes,
2936 &found,
2937 strict_mode);
2938 if (found) return result_object;
Steve Blocka7e24c12009-10-30 11:49:00 +00002939 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002940
2941 // At this point, no GC should have happened, as this would invalidate
2942 // 'result', which we cannot handlify!
2943
Andrei Popescu402d9372010-02-26 13:31:12 +00002944 if (!result->IsFound()) {
2945 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002946 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002947 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002948 if (result->IsReadOnly() && result->IsProperty()) {
2949 if (strict_mode == kStrictMode) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002950 Handle<JSObject> self(this);
2951 Handle<String> hname(name);
2952 Handle<Object> args[] = { hname, self };
Steve Block44f0eee2011-05-26 01:26:41 +01002953 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002954 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002955 } else {
2956 return value;
2957 }
2958 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002959 // This is a real property that is not read-only, or it is a
2960 // transition or null descriptor and there are no setters in the prototypes.
2961 switch (result->type()) {
2962 case NORMAL:
2963 return SetNormalizedProperty(result, value);
2964 case FIELD:
2965 return FastPropertyAtPut(result->GetFieldIndex(), value);
2966 case MAP_TRANSITION:
2967 if (attributes == result->GetAttributes()) {
2968 // Only use map transition if the attributes match.
2969 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2970 name,
2971 value);
2972 }
2973 return ConvertDescriptorToField(name, value, attributes);
2974 case CONSTANT_FUNCTION:
2975 // Only replace the function if necessary.
2976 if (value == result->GetConstantFunction()) return value;
2977 // Preserve the attributes of this existing property.
2978 attributes = result->GetAttributes();
2979 return ConvertDescriptorToField(name, value, attributes);
2980 case CALLBACKS:
2981 return SetPropertyWithCallback(result->GetCallbackObject(),
2982 name,
2983 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002984 result->holder(),
2985 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002986 case INTERCEPTOR:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002987 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
Iain Merrick75681382010-08-19 15:07:18 +01002988 case CONSTANT_TRANSITION: {
2989 // If the same constant function is being added we can simply
2990 // transition to the target map.
2991 Map* target_map = result->GetTransitionMap();
2992 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2993 int number = target_descriptors->SearchWithCache(name);
2994 ASSERT(number != DescriptorArray::kNotFound);
2995 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2996 JSFunction* function =
2997 JSFunction::cast(target_descriptors->GetValue(number));
Steve Block44f0eee2011-05-26 01:26:41 +01002998 ASSERT(!HEAP->InNewSpace(function));
Iain Merrick75681382010-08-19 15:07:18 +01002999 if (value == function) {
3000 set_map(target_map);
3001 return value;
3002 }
3003 // Otherwise, replace with a MAP_TRANSITION to a new map with a
3004 // FIELD, even if the value is a constant function.
Steve Blocka7e24c12009-10-30 11:49:00 +00003005 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Iain Merrick75681382010-08-19 15:07:18 +01003006 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003007 case NULL_DESCRIPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00003008 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00003009 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003010 case HANDLER:
Steve Blocka7e24c12009-10-30 11:49:00 +00003011 UNREACHABLE();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003012 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00003013 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003014 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +00003015 return value;
3016}
3017
3018
3019// Set a real local property, even if it is READ_ONLY. If the property is not
3020// present, add it with attributes NONE. This code is an exact clone of
3021// SetProperty, with the check for IsReadOnly and the check for a
3022// callback setter removed. The two lines looking up the LookupResult
3023// result are also added. If one of the functions is changed, the other
3024// should be.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003025// Note that this method cannot be used to set the prototype of a function
3026// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
3027// doesn't handle function prototypes correctly.
Ben Murdoch086aeea2011-05-13 15:57:08 +01003028MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00003029 String* name,
3030 Object* value,
3031 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01003032
Steve Blocka7e24c12009-10-30 11:49:00 +00003033 // Make sure that the top context does not change when doing callbacks or
3034 // interceptor calls.
3035 AssertNoContextChange ncc;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003036 Isolate* isolate = GetIsolate();
3037 LookupResult result(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00003038 LocalLookup(name, &result);
Steve Blocka7e24c12009-10-30 11:49:00 +00003039 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003040 if (IsAccessCheckNeeded()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003041 if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003042 return SetPropertyWithFailedAccessCheck(&result,
3043 name,
3044 value,
3045 false,
3046 kNonStrictMode);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003047 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003048 }
3049
3050 if (IsJSGlobalProxy()) {
3051 Object* proto = GetPrototype();
3052 if (proto->IsNull()) return value;
3053 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch086aeea2011-05-13 15:57:08 +01003054 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00003055 name,
3056 value,
3057 attributes);
3058 }
3059
3060 // Check for accessor in prototype chain removed here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00003061 if (!result.IsFound()) {
3062 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01003063 return AddProperty(name, value, attributes, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003064 }
Steve Block6ded16b2010-05-10 14:33:55 +01003065
Andrei Popescu402d9372010-02-26 13:31:12 +00003066 PropertyDetails details = PropertyDetails(attributes, NORMAL);
3067
Steve Blocka7e24c12009-10-30 11:49:00 +00003068 // Check of IsReadOnly removed from here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00003069 switch (result.type()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003070 case NORMAL:
Andrei Popescu402d9372010-02-26 13:31:12 +00003071 return SetNormalizedProperty(name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00003072 case FIELD:
Andrei Popescu402d9372010-02-26 13:31:12 +00003073 return FastPropertyAtPut(result.GetFieldIndex(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00003074 case MAP_TRANSITION:
Andrei Popescu402d9372010-02-26 13:31:12 +00003075 if (attributes == result.GetAttributes()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003076 // Only use map transition if the attributes match.
Andrei Popescu402d9372010-02-26 13:31:12 +00003077 return AddFastPropertyUsingMap(result.GetTransitionMap(),
Steve Blocka7e24c12009-10-30 11:49:00 +00003078 name,
3079 value);
3080 }
3081 return ConvertDescriptorToField(name, value, attributes);
3082 case CONSTANT_FUNCTION:
3083 // Only replace the function if necessary.
Andrei Popescu402d9372010-02-26 13:31:12 +00003084 if (value == result.GetConstantFunction()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00003085 // Preserve the attributes of this existing property.
Andrei Popescu402d9372010-02-26 13:31:12 +00003086 attributes = result.GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +00003087 return ConvertDescriptorToField(name, value, attributes);
3088 case CALLBACKS:
3089 case INTERCEPTOR:
3090 // Override callback in clone
3091 return ConvertDescriptorToField(name, value, attributes);
3092 case CONSTANT_TRANSITION:
3093 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
3094 // if the value is a function.
3095 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
3096 case NULL_DESCRIPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00003097 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00003098 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003099 case HANDLER:
Steve Blocka7e24c12009-10-30 11:49:00 +00003100 UNREACHABLE();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003101 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00003102 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003103 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +00003104 return value;
3105}
3106
3107
3108PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
3109 JSObject* receiver,
3110 String* name,
3111 bool continue_search) {
3112 // Check local property, ignore interceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003113 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003114 LocalLookupRealNamedProperty(name, &result);
3115 if (result.IsProperty()) return result.GetAttributes();
3116
3117 if (continue_search) {
3118 // Continue searching via the prototype chain.
3119 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003120 if (!pt->IsNull()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003121 return JSObject::cast(pt)->
3122 GetPropertyAttributeWithReceiver(receiver, name);
3123 }
3124 }
3125 return ABSENT;
3126}
3127
3128
3129PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
3130 JSObject* receiver,
3131 String* name,
3132 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +01003133 Isolate* isolate = GetIsolate();
3134
Steve Blocka7e24c12009-10-30 11:49:00 +00003135 // Make sure that the top context does not change when doing
3136 // callbacks or interceptor calls.
3137 AssertNoContextChange ncc;
3138
Steve Block44f0eee2011-05-26 01:26:41 +01003139 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003140 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3141 Handle<JSObject> receiver_handle(receiver);
3142 Handle<JSObject> holder_handle(this);
3143 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01003144 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003145 v8::AccessorInfo info(args.end());
3146 if (!interceptor->query()->IsUndefined()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003147 v8::NamedPropertyQuery query =
3148 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01003149 LOG(isolate,
3150 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003151 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003152 {
3153 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003154 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003155 result = query(v8::Utils::ToLocal(name_handle), info);
3156 }
3157 if (!result.IsEmpty()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003158 ASSERT(result->IsInt32());
3159 return static_cast<PropertyAttributes>(result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00003160 }
3161 } else if (!interceptor->getter()->IsUndefined()) {
3162 v8::NamedPropertyGetter getter =
3163 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01003164 LOG(isolate,
3165 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
Steve Blocka7e24c12009-10-30 11:49:00 +00003166 v8::Handle<v8::Value> result;
3167 {
3168 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003169 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003170 result = getter(v8::Utils::ToLocal(name_handle), info);
3171 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003172 if (!result.IsEmpty()) return DONT_ENUM;
Steve Blocka7e24c12009-10-30 11:49:00 +00003173 }
3174 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
3175 *name_handle,
3176 continue_search);
3177}
3178
3179
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003180PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
3181 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00003182 String* key) {
3183 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003184 if (IsJSObject() && key->AsArrayIndex(&index)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003185 return JSObject::cast(this)->HasElementWithReceiver(receiver, index)
3186 ? NONE : ABSENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00003187 }
3188 // Named property.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003189 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003190 Lookup(key, &result);
3191 return GetPropertyAttribute(receiver, &result, key, true);
3192}
3193
3194
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003195PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
3196 LookupResult* result,
3197 String* name,
3198 bool continue_search) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003199 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003200 if (IsAccessCheckNeeded()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003201 JSObject* this_obj = JSObject::cast(this);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003202 Heap* heap = GetHeap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003203 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
3204 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
3205 receiver, result, name, continue_search);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003206 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003207 }
Andrei Popescu402d9372010-02-26 13:31:12 +00003208 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003209 switch (result->type()) {
3210 case NORMAL: // fall through
3211 case FIELD:
3212 case CONSTANT_FUNCTION:
3213 case CALLBACKS:
3214 return result->GetAttributes();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003215 case HANDLER: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003216 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler(
3217 receiver, name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003218 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003219 case INTERCEPTOR:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003220 return result->holder()->GetPropertyAttributeWithInterceptor(
3221 JSObject::cast(receiver), name, continue_search);
Steve Blocka7e24c12009-10-30 11:49:00 +00003222 default:
3223 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00003224 }
3225 }
3226 return ABSENT;
3227}
3228
3229
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003230PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003231 // Check whether the name is an array index.
3232 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003233 if (IsJSObject() && name->AsArrayIndex(&index)) {
3234 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
Steve Blocka7e24c12009-10-30 11:49:00 +00003235 return ABSENT;
3236 }
3237 // Named property.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003238 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003239 LocalLookup(name, &result);
3240 return GetPropertyAttribute(this, &result, name, false);
3241}
3242
3243
John Reck59135872010-11-02 12:39:01 -07003244MaybeObject* NormalizedMapCache::Get(JSObject* obj,
3245 PropertyNormalizationMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003246 Isolate* isolate = obj->GetIsolate();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003247 Map* fast = obj->map();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003248 int index = fast->Hash() % kEntries;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003249 Object* result = get(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003250 if (result->IsMap() &&
3251 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003252#ifdef DEBUG
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003253 if (FLAG_verify_heap) {
3254 Map::cast(result)->SharedMapVerify();
3255 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003256 if (FLAG_enable_slow_asserts) {
3257 // The cached map should match newly created normalized map bit-by-bit.
John Reck59135872010-11-02 12:39:01 -07003258 Object* fresh;
3259 { MaybeObject* maybe_fresh =
3260 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3261 if (maybe_fresh->ToObject(&fresh)) {
3262 ASSERT(memcmp(Map::cast(fresh)->address(),
3263 Map::cast(result)->address(),
3264 Map::kSize) == 0);
3265 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003266 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003267 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003268#endif
3269 return result;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003270 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003271
John Reck59135872010-11-02 12:39:01 -07003272 { MaybeObject* maybe_result =
3273 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3274 if (!maybe_result->ToObject(&result)) return maybe_result;
3275 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003276 set(index, result);
Steve Block44f0eee2011-05-26 01:26:41 +01003277 isolate->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003278
3279 return result;
3280}
3281
3282
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003283void NormalizedMapCache::Clear() {
3284 int entries = length();
3285 for (int i = 0; i != entries; i++) {
3286 set_undefined(i);
3287 }
3288}
3289
3290
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003291void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
3292 Handle<String> name,
3293 Handle<Code> code) {
3294 Isolate* isolate = object->GetIsolate();
3295 CALL_HEAP_FUNCTION_VOID(isolate,
3296 object->UpdateMapCodeCache(*name, *code));
3297}
3298
3299
John Reck59135872010-11-02 12:39:01 -07003300MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003301 if (map()->is_shared()) {
3302 // Fast case maps are never marked as shared.
3303 ASSERT(!HasFastProperties());
3304 // Replace the map with an identical copy that can be safely modified.
John Reck59135872010-11-02 12:39:01 -07003305 Object* obj;
3306 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
3307 UNIQUE_NORMALIZED_MAP);
3308 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3309 }
Steve Block44f0eee2011-05-26 01:26:41 +01003310 GetIsolate()->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003311
3312 set_map(Map::cast(obj));
3313 }
3314 return map()->UpdateCodeCache(name, code);
3315}
3316
3317
John Reck59135872010-11-02 12:39:01 -07003318MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
3319 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003320 if (!HasFastProperties()) return this;
3321
3322 // The global object is always normalized.
3323 ASSERT(!IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01003324 // JSGlobalProxy must never be normalized
3325 ASSERT(!IsJSGlobalProxy());
3326
Ben Murdoch8b112d22011-06-08 16:22:53 +01003327 Map* map_of_this = map();
Steve Block44f0eee2011-05-26 01:26:41 +01003328
Steve Blocka7e24c12009-10-30 11:49:00 +00003329 // Allocate new content.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003330 int property_count = map_of_this->NumberOfDescribedProperties();
Steve Blocka7e24c12009-10-30 11:49:00 +00003331 if (expected_additional_properties > 0) {
3332 property_count += expected_additional_properties;
3333 } else {
3334 property_count += 2; // Make space for two more properties.
3335 }
John Reck59135872010-11-02 12:39:01 -07003336 Object* obj;
3337 { MaybeObject* maybe_obj =
3338 StringDictionary::Allocate(property_count);
3339 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3340 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003341 StringDictionary* dictionary = StringDictionary::cast(obj);
3342
Ben Murdoch8b112d22011-06-08 16:22:53 +01003343 DescriptorArray* descs = map_of_this->instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00003344 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01003345 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00003346 switch (details.type()) {
3347 case CONSTANT_FUNCTION: {
3348 PropertyDetails d =
3349 PropertyDetails(details.attributes(), NORMAL, details.index());
3350 Object* value = descs->GetConstantFunction(i);
John Reck59135872010-11-02 12:39:01 -07003351 Object* result;
3352 { MaybeObject* maybe_result =
3353 dictionary->Add(descs->GetKey(i), value, d);
3354 if (!maybe_result->ToObject(&result)) return maybe_result;
3355 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003356 dictionary = StringDictionary::cast(result);
3357 break;
3358 }
3359 case FIELD: {
3360 PropertyDetails d =
3361 PropertyDetails(details.attributes(), NORMAL, details.index());
3362 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
John Reck59135872010-11-02 12:39:01 -07003363 Object* result;
3364 { MaybeObject* maybe_result =
3365 dictionary->Add(descs->GetKey(i), value, d);
3366 if (!maybe_result->ToObject(&result)) return maybe_result;
3367 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003368 dictionary = StringDictionary::cast(result);
3369 break;
3370 }
3371 case CALLBACKS: {
3372 PropertyDetails d =
3373 PropertyDetails(details.attributes(), CALLBACKS, details.index());
3374 Object* value = descs->GetCallbacksObject(i);
John Reck59135872010-11-02 12:39:01 -07003375 Object* result;
3376 { MaybeObject* maybe_result =
3377 dictionary->Add(descs->GetKey(i), value, d);
3378 if (!maybe_result->ToObject(&result)) return maybe_result;
3379 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003380 dictionary = StringDictionary::cast(result);
3381 break;
3382 }
3383 case MAP_TRANSITION:
3384 case CONSTANT_TRANSITION:
3385 case NULL_DESCRIPTOR:
3386 case INTERCEPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00003387 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00003388 break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003389 case HANDLER:
3390 case NORMAL:
Steve Blocka7e24c12009-10-30 11:49:00 +00003391 UNREACHABLE();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003392 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00003393 }
3394 }
3395
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003396 Heap* current_heap = GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01003397
Steve Blocka7e24c12009-10-30 11:49:00 +00003398 // Copy the next enumeration index from instance descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003399 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00003400 dictionary->SetNextEnumerationIndex(index);
3401
Ben Murdoch8b112d22011-06-08 16:22:53 +01003402 { MaybeObject* maybe_obj =
3403 current_heap->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01003404 normalized_map_cache()->Get(this, mode);
John Reck59135872010-11-02 12:39:01 -07003405 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3406 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003407 Map* new_map = Map::cast(obj);
3408
Steve Blocka7e24c12009-10-30 11:49:00 +00003409 // We have now successfully allocated all the necessary objects.
3410 // Changes can now be made with the guarantee that all of them take effect.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003411
3412 // Resize the object in the heap if necessary.
3413 int new_instance_size = new_map->instance_size();
Ben Murdoch8b112d22011-06-08 16:22:53 +01003414 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003415 ASSERT(instance_size_delta >= 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003416 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
3417 instance_size_delta);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003418 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
3419 MemoryChunk::IncrementLiveBytes(this->address(), -instance_size_delta);
3420 }
3421
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003422
Steve Blocka7e24c12009-10-30 11:49:00 +00003423 set_map(new_map);
Ben Murdoch257744e2011-11-30 15:57:28 +00003424 new_map->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00003425
3426 set_properties(dictionary);
3427
Ben Murdoch8b112d22011-06-08 16:22:53 +01003428 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00003429
3430#ifdef DEBUG
3431 if (FLAG_trace_normalization) {
3432 PrintF("Object properties have been normalized:\n");
3433 Print();
3434 }
3435#endif
3436 return this;
3437}
3438
3439
John Reck59135872010-11-02 12:39:01 -07003440MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003441 if (HasFastProperties()) return this;
3442 ASSERT(!IsGlobalObject());
3443 return property_dictionary()->
3444 TransformPropertiesToFastFor(this, unused_property_fields);
3445}
3446
3447
John Reck59135872010-11-02 12:39:01 -07003448MaybeObject* JSObject::NormalizeElements() {
Steve Block44f0eee2011-05-26 01:26:41 +01003449 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01003450
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003451 // Find the backing store.
3452 FixedArrayBase* array = FixedArrayBase::cast(elements());
3453 Map* old_map = array->map();
3454 bool is_arguments =
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003455 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003456 if (is_arguments) {
3457 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
John Reck59135872010-11-02 12:39:01 -07003458 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003459 if (array->IsDictionary()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00003460
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003461 ASSERT(HasFastElements() ||
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003462 HasFastSmiOnlyElements() ||
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003463 HasFastDoubleElements() ||
3464 HasFastArgumentsElements());
3465 // Compute the effective length and allocate a new backing store.
3466 int length = IsJSArray()
3467 ? Smi::cast(JSArray::cast(this)->length())->value()
3468 : array->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003469 int old_capacity = 0;
3470 int used_elements = 0;
3471 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003472 NumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003473 { Object* object;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003474 MaybeObject* maybe = NumberDictionary::Allocate(used_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003475 if (!maybe->ToObject(&object)) return maybe;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003476 dictionary = NumberDictionary::cast(object);
John Reck59135872010-11-02 12:39:01 -07003477 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003478
3479 // Copy the elements to the new backing store.
3480 bool has_double_elements = array->IsFixedDoubleArray();
Steve Blocka7e24c12009-10-30 11:49:00 +00003481 for (int i = 0; i < length; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003482 Object* value = NULL;
3483 if (has_double_elements) {
3484 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
3485 if (double_array->is_the_hole(i)) {
3486 value = GetIsolate()->heap()->the_hole_value();
3487 } else {
3488 // Objects must be allocated in the old object space, since the
3489 // overall number of HeapNumbers needed for the conversion might
3490 // exceed the capacity of new space, and we would fail repeatedly
3491 // trying to convert the FixedDoubleArray.
3492 MaybeObject* maybe_value_object =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003493 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003494 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
John Reck59135872010-11-02 12:39:01 -07003495 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003496 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003497 ASSERT(old_map->has_fast_elements() ||
3498 old_map->has_fast_smi_only_elements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003499 value = FixedArray::cast(array)->get(i);
3500 }
3501 PropertyDetails details = PropertyDetails(NONE, NORMAL);
3502 if (!value->IsTheHole()) {
3503 Object* result;
3504 MaybeObject* maybe_result =
3505 dictionary->AddNumberEntry(i, value, details);
3506 if (!maybe_result->ToObject(&result)) return maybe_result;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003507 dictionary = NumberDictionary::cast(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00003508 }
3509 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003510
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003511 // Switch to using the dictionary as the backing storage for elements.
3512 if (is_arguments) {
3513 FixedArray::cast(elements())->set(1, dictionary);
3514 } else {
3515 // Set the new map first to satify the elements type assert in
3516 // set_elements().
3517 Object* new_map;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003518 MaybeObject* maybe = GetElementsTransitionMap(DICTIONARY_ELEMENTS);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003519 if (!maybe->ToObject(&new_map)) return maybe;
3520 set_map(Map::cast(new_map));
3521 set_elements(dictionary);
3522 }
3523
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003524 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
3525 Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00003526
3527#ifdef DEBUG
3528 if (FLAG_trace_normalization) {
3529 PrintF("Object elements have been normalized:\n");
3530 Print();
3531 }
3532#endif
3533
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003534 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
3535 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00003536}
3537
3538
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003539Smi* JSReceiver::GenerateIdentityHash() {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003540 Isolate* isolate = GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003541
3542 int hash_value;
3543 int attempts = 0;
3544 do {
3545 // Generate a random 32-bit hash value but limit range to fit
3546 // within a smi.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003547 hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003548 attempts++;
3549 } while (hash_value == 0 && attempts < 30);
3550 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
3551
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003552 return Smi::FromInt(hash_value);
3553}
3554
3555
3556MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
3557 MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3558 hash);
3559 if (maybe->IsFailure()) return maybe;
3560 return this;
3561}
3562
3563
3564MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
3565 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
3566 if (stored_value->IsSmi()) return stored_value;
3567
3568 // Do not generate permanent identity hash code if not requested.
3569 if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
3570
3571 Smi* hash = GenerateIdentityHash();
3572 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3573 hash);
3574 if (result->IsFailure()) return result;
3575 if (result->ToObjectUnchecked()->IsUndefined()) {
3576 // Trying to get hash of detached proxy.
3577 return Smi::FromInt(0);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003578 }
3579 return hash;
3580}
3581
3582
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003583MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
3584 Object* hash = this->hash();
3585 if (!hash->IsSmi() && flag == ALLOW_CREATION) {
3586 hash = GenerateIdentityHash();
3587 set_hash(hash);
3588 }
3589 return hash;
3590}
3591
3592
3593Object* JSObject::GetHiddenProperty(String* key) {
3594 if (IsJSGlobalProxy()) {
3595 // For a proxy, use the prototype as target object.
3596 Object* proxy_parent = GetPrototype();
3597 // If the proxy is detached, return undefined.
3598 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3599 ASSERT(proxy_parent->IsJSGlobalObject());
3600 return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
3601 }
3602 ASSERT(!IsJSGlobalProxy());
3603 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3604 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3605 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
3606 return GetHeap()->undefined_value();
3607 }
3608 StringDictionary* dictionary =
3609 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3610 int entry = dictionary->FindEntry(key);
3611 if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
3612 return dictionary->ValueAt(entry);
3613}
3614
3615
3616MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
3617 if (IsJSGlobalProxy()) {
3618 // For a proxy, use the prototype as target object.
3619 Object* proxy_parent = GetPrototype();
3620 // If the proxy is detached, return undefined.
3621 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3622 ASSERT(proxy_parent->IsJSGlobalObject());
3623 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
3624 }
3625 ASSERT(!IsJSGlobalProxy());
3626 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
3627 StringDictionary* dictionary;
3628 if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
3629
3630 // If it was found, check if the key is already in the dictionary.
3631 int entry = dictionary->FindEntry(key);
3632 if (entry != StringDictionary::kNotFound) {
3633 // If key was found, just update the value.
3634 dictionary->ValueAtPut(entry, value);
3635 return this;
3636 }
3637 // Key was not already in the dictionary, so add the entry.
3638 MaybeObject* insert_result = dictionary->Add(key,
3639 value,
3640 PropertyDetails(NONE, NORMAL));
3641 StringDictionary* new_dict;
3642 if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
3643 if (new_dict != dictionary) {
3644 // If adding the key expanded the dictionary (i.e., Add returned a new
3645 // dictionary), store it back to the object.
3646 MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
3647 if (store_result->IsFailure()) return store_result;
3648 }
3649 // Return this to mark success.
3650 return this;
3651}
3652
3653
3654void JSObject::DeleteHiddenProperty(String* key) {
3655 if (IsJSGlobalProxy()) {
3656 // For a proxy, use the prototype as target object.
3657 Object* proxy_parent = GetPrototype();
3658 // If the proxy is detached, return immediately.
3659 if (proxy_parent->IsNull()) return;
3660 ASSERT(proxy_parent->IsJSGlobalObject());
3661 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
3662 return;
3663 }
3664 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3665 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3666 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
3667 StringDictionary* dictionary =
3668 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3669 int entry = dictionary->FindEntry(key);
3670 if (entry == StringDictionary::kNotFound) {
3671 // Key wasn't in dictionary. Deletion is a success.
3672 return;
3673 }
3674 // Key was in the dictionary. Remove it.
3675 dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
3676}
3677
3678
3679bool JSObject::HasHiddenProperties() {
3680 return GetPropertyAttributePostInterceptor(this,
3681 GetHeap()->hidden_symbol(),
3682 false) != ABSENT;
3683}
3684
3685
3686MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
3687 ASSERT(!IsJSGlobalProxy());
3688 if (HasFastProperties()) {
3689 // If the object has fast properties, check whether the first slot
3690 // in the descriptor array matches the hidden symbol. Since the
3691 // hidden symbols hash code is zero (and no other string has hash
3692 // code zero) it will always occupy the first entry if present.
3693 DescriptorArray* descriptors = this->map()->instance_descriptors();
3694 if ((descriptors->number_of_descriptors() > 0) &&
3695 (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) &&
3696 descriptors->IsProperty(0)) {
3697 ASSERT(descriptors->GetType(0) == FIELD);
3698 Object* hidden_store =
3699 this->FastPropertyAt(descriptors->GetFieldIndex(0));
3700 return StringDictionary::cast(hidden_store);
3701 }
3702 } else {
3703 PropertyAttributes attributes;
3704 // You can't install a getter on a property indexed by the hidden symbol,
3705 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
3706 // object.
3707 Object* lookup =
3708 GetLocalPropertyPostInterceptor(this,
3709 GetHeap()->hidden_symbol(),
3710 &attributes)->ToObjectUnchecked();
3711 if (!lookup->IsUndefined()) {
3712 return StringDictionary::cast(lookup);
3713 }
3714 }
3715 if (!create_if_absent) return GetHeap()->undefined_value();
3716 const int kInitialSize = 5;
3717 MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
3718 StringDictionary* dictionary;
3719 if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
3720 MaybeObject* store_result =
3721 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3722 dictionary,
3723 DONT_ENUM,
3724 kNonStrictMode);
3725 if (store_result->IsFailure()) return store_result;
3726 return dictionary;
3727}
3728
3729
3730MaybeObject* JSObject::SetHiddenPropertiesDictionary(
3731 StringDictionary* dictionary) {
3732 ASSERT(!IsJSGlobalProxy());
3733 ASSERT(HasHiddenProperties());
3734 if (HasFastProperties()) {
3735 // If the object has fast properties, check whether the first slot
3736 // in the descriptor array matches the hidden symbol. Since the
3737 // hidden symbols hash code is zero (and no other string has hash
3738 // code zero) it will always occupy the first entry if present.
3739 DescriptorArray* descriptors = this->map()->instance_descriptors();
3740 if ((descriptors->number_of_descriptors() > 0) &&
3741 (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) &&
3742 descriptors->IsProperty(0)) {
3743 ASSERT(descriptors->GetType(0) == FIELD);
3744 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
3745 return this;
3746 }
3747 }
3748 MaybeObject* store_result =
3749 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3750 dictionary,
3751 DONT_ENUM,
3752 kNonStrictMode);
3753 if (store_result->IsFailure()) return store_result;
3754 return this;
3755}
3756
3757
John Reck59135872010-11-02 12:39:01 -07003758MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3759 DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003760 // Check local property, ignore interceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003761 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003762 LocalLookupRealNamedProperty(name, &result);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003763 if (!result.IsProperty()) return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003764
3765 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003766 Object* obj;
3767 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3768 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3769 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003770
3771 return DeleteNormalizedProperty(name, mode);
3772}
3773
3774
John Reck59135872010-11-02 12:39:01 -07003775MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +01003776 Isolate* isolate = GetIsolate();
3777 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003778 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3779 Handle<String> name_handle(name);
3780 Handle<JSObject> this_handle(this);
3781 if (!interceptor->deleter()->IsUndefined()) {
3782 v8::NamedPropertyDeleter deleter =
3783 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
Steve Block44f0eee2011-05-26 01:26:41 +01003784 LOG(isolate,
3785 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3786 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003787 v8::AccessorInfo info(args.end());
3788 v8::Handle<v8::Boolean> result;
3789 {
3790 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003791 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003792 result = deleter(v8::Utils::ToLocal(name_handle), info);
3793 }
Steve Block44f0eee2011-05-26 01:26:41 +01003794 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003795 if (!result.IsEmpty()) {
3796 ASSERT(result->IsBoolean());
3797 return *v8::Utils::OpenHandle(*result);
3798 }
3799 }
John Reck59135872010-11-02 12:39:01 -07003800 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00003801 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003802 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003803 return raw_result;
3804}
3805
3806
John Reck59135872010-11-02 12:39:01 -07003807MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01003808 Isolate* isolate = GetIsolate();
3809 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003810 // Make sure that the top context does not change when doing
3811 // callbacks or interceptor calls.
3812 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01003813 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003814 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Steve Block44f0eee2011-05-26 01:26:41 +01003815 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003816 v8::IndexedPropertyDeleter deleter =
3817 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3818 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01003819 LOG(isolate,
3820 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3821 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003822 v8::AccessorInfo info(args.end());
3823 v8::Handle<v8::Boolean> result;
3824 {
3825 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003826 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003827 result = deleter(index, info);
3828 }
Steve Block44f0eee2011-05-26 01:26:41 +01003829 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003830 if (!result.IsEmpty()) {
3831 ASSERT(result->IsBoolean());
3832 return *v8::Utils::OpenHandle(*result);
3833 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003834 MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3835 *this_handle,
3836 index,
3837 NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003838 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003839 return raw_result;
3840}
3841
3842
John Reck59135872010-11-02 12:39:01 -07003843MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003844 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003845 // Check access rights if needed.
3846 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003847 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3848 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3849 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003850 }
3851
3852 if (IsJSGlobalProxy()) {
3853 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003854 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003855 ASSERT(proto->IsJSGlobalObject());
3856 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
3857 }
3858
3859 if (HasIndexedInterceptor()) {
3860 // Skip interceptor if forcing deletion.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003861 if (mode != FORCE_DELETION) {
3862 return DeleteElementWithInterceptor(index);
3863 }
3864 mode = JSReceiver::FORCE_DELETION;
Steve Blocka7e24c12009-10-30 11:49:00 +00003865 }
3866
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003867 return GetElementsAccessor()->Delete(this, index, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003868}
3869
3870
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003871MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3872 if (IsJSProxy()) {
3873 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003874 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003875 return JSObject::cast(this)->DeleteProperty(name, mode);
3876}
3877
3878
3879MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
3880 if (IsJSProxy()) {
3881 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
3882 }
3883 return JSObject::cast(this)->DeleteElement(index, mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003884}
3885
3886
John Reck59135872010-11-02 12:39:01 -07003887MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003888 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003889 // ECMA-262, 3rd, 8.6.2.5
3890 ASSERT(name->IsString());
3891
3892 // Check access rights if needed.
3893 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003894 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3895 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3896 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003897 }
3898
3899 if (IsJSGlobalProxy()) {
3900 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003901 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003902 ASSERT(proto->IsJSGlobalObject());
3903 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
3904 }
3905
3906 uint32_t index = 0;
3907 if (name->AsArrayIndex(&index)) {
3908 return DeleteElement(index, mode);
3909 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003910 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003911 LocalLookup(name, &result);
Steve Block44f0eee2011-05-26 01:26:41 +01003912 if (!result.IsProperty()) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003913 // Ignore attributes if forcing a deletion.
3914 if (result.IsDontDelete() && mode != FORCE_DELETION) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003915 if (mode == STRICT_DELETION) {
3916 // Deleting a non-configurable property in strict mode.
Steve Block44f0eee2011-05-26 01:26:41 +01003917 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003918 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01003919 return isolate->Throw(*isolate->factory()->NewTypeError(
3920 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003921 }
Steve Block44f0eee2011-05-26 01:26:41 +01003922 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003923 }
3924 // Check for interceptor.
3925 if (result.type() == INTERCEPTOR) {
3926 // Skip interceptor if forcing a deletion.
3927 if (mode == FORCE_DELETION) {
3928 return DeletePropertyPostInterceptor(name, mode);
3929 }
3930 return DeletePropertyWithInterceptor(name);
3931 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003932 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003933 Object* obj;
3934 { MaybeObject* maybe_obj =
3935 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3936 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3937 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003938 // Make sure the properties are normalized before removing the entry.
3939 return DeleteNormalizedProperty(name, mode);
3940 }
3941}
3942
3943
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003944bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
3945 ElementsKind kind,
3946 Object* object) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003947 ASSERT(kind == FAST_ELEMENTS ||
3948 kind == DICTIONARY_ELEMENTS);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003949 if (kind == FAST_ELEMENTS) {
3950 int length = IsJSArray()
3951 ? Smi::cast(JSArray::cast(this)->length())->value()
3952 : elements->length();
3953 for (int i = 0; i < length; ++i) {
3954 Object* element = elements->get(i);
3955 if (!element->IsTheHole() && element == object) return true;
3956 }
3957 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003958 Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003959 if (!key->IsUndefined()) return true;
3960 }
3961 return false;
3962}
3963
3964
Steve Blocka7e24c12009-10-30 11:49:00 +00003965// Check whether this object references another object.
3966bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01003967 Map* map_of_this = map();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003968 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003969 AssertNoAllocation no_alloc;
3970
3971 // Is the object the constructor for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01003972 if (map_of_this->constructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003973 return true;
3974 }
3975
3976 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01003977 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003978 return true;
3979 }
3980
3981 // Check if the object is among the named properties.
3982 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01003983 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003984 return true;
3985 }
3986
3987 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003988 ElementsKind kind = GetElementsKind();
3989 switch (kind) {
Steve Block44f0eee2011-05-26 01:26:41 +01003990 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003991 case EXTERNAL_BYTE_ELEMENTS:
3992 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3993 case EXTERNAL_SHORT_ELEMENTS:
3994 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3995 case EXTERNAL_INT_ELEMENTS:
3996 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3997 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003998 case EXTERNAL_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003999 case FAST_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00004000 // Raw pixels and external arrays do not reference other
4001 // objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00004002 break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004003 case FAST_SMI_ONLY_ELEMENTS:
4004 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004005 case FAST_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00004006 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004007 FixedArray* elements = FixedArray::cast(this->elements());
4008 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00004009 break;
4010 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004011 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4012 FixedArray* parameter_map = FixedArray::cast(elements());
4013 // Check the mapped parameters.
4014 int length = parameter_map->length();
4015 for (int i = 2; i < length; ++i) {
4016 Object* value = parameter_map->get(i);
4017 if (!value->IsTheHole() && value == obj) return true;
4018 }
4019 // Check the arguments.
4020 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4021 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
4022 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00004023 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004024 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004025 }
4026
Steve Block6ded16b2010-05-10 14:33:55 +01004027 // For functions check the context.
4028 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004029 // Get the constructor function for arguments array.
4030 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +01004031 heap->isolate()->context()->global_context()->
4032 arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +00004033 JSFunction* arguments_function =
4034 JSFunction::cast(arguments_boilerplate->map()->constructor());
4035
4036 // Get the context and don't check if it is the global context.
4037 JSFunction* f = JSFunction::cast(this);
4038 Context* context = f->context();
4039 if (context->IsGlobalContext()) {
4040 return false;
4041 }
4042
4043 // Check the non-special context slots.
4044 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
4045 // Only check JS objects.
4046 if (context->get(i)->IsJSObject()) {
4047 JSObject* ctxobj = JSObject::cast(context->get(i));
4048 // If it is an arguments array check the content.
4049 if (ctxobj->map()->constructor() == arguments_function) {
4050 if (ctxobj->ReferencesObject(obj)) {
4051 return true;
4052 }
4053 } else if (ctxobj == obj) {
4054 return true;
4055 }
4056 }
4057 }
4058
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004059 // Check the context extension (if any) if it can have references.
4060 if (context->has_extension() && !context->IsCatchContext()) {
4061 return JSObject::cast(context->extension())->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00004062 }
4063 }
4064
4065 // No references to object.
4066 return false;
4067}
4068
4069
John Reck59135872010-11-02 12:39:01 -07004070MaybeObject* JSObject::PreventExtensions() {
Steve Block44f0eee2011-05-26 01:26:41 +01004071 Isolate* isolate = GetIsolate();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004072 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004073 !isolate->MayNamedAccess(this,
4074 isolate->heap()->undefined_value(),
4075 v8::ACCESS_KEYS)) {
4076 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
4077 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004078 }
4079
Steve Block1e0659c2011-05-24 12:43:12 +01004080 if (IsJSGlobalProxy()) {
4081 Object* proto = GetPrototype();
4082 if (proto->IsNull()) return this;
4083 ASSERT(proto->IsJSGlobalObject());
4084 return JSObject::cast(proto)->PreventExtensions();
4085 }
4086
Ben Murdoch257744e2011-11-30 15:57:28 +00004087 // It's not possible to seal objects with external array elements
4088 if (HasExternalArrayElements()) {
4089 HandleScope scope(isolate);
4090 Handle<Object> object(this);
4091 Handle<Object> error =
4092 isolate->factory()->NewTypeError(
4093 "cant_prevent_ext_external_array_elements",
4094 HandleVector(&object, 1));
4095 return isolate->Throw(*error);
4096 }
4097
Steve Block8defd9f2010-07-08 12:39:36 +01004098 // If there are fast elements we normalize.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004099 NumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004100 { MaybeObject* maybe = NormalizeElements();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004101 if (!maybe->To<NumberDictionary>(&dictionary)) return maybe;
Steve Block8defd9f2010-07-08 12:39:36 +01004102 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004103 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Block8defd9f2010-07-08 12:39:36 +01004104 // Make sure that we never go back to fast case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004105 dictionary->set_requires_slow_elements();
Steve Block8defd9f2010-07-08 12:39:36 +01004106
4107 // Do a map transition, other objects with this map may still
4108 // be extensible.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004109 Map* new_map;
4110 { MaybeObject* maybe = map()->CopyDropTransitions();
4111 if (!maybe->To<Map>(&new_map)) return maybe;
John Reck59135872010-11-02 12:39:01 -07004112 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004113 new_map->set_is_extensible(false);
4114 set_map(new_map);
Steve Block8defd9f2010-07-08 12:39:36 +01004115 ASSERT(!map()->is_extensible());
4116 return new_map;
4117}
4118
4119
Steve Blocka7e24c12009-10-30 11:49:00 +00004120// Tests for the fast common case for property enumeration:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004121// - This object and all prototypes has an enum cache (which means that
4122// it is no proxy, has no interceptors and needs no access checks).
Steve Blockd0582a62009-12-15 09:54:21 +00004123// - This object has no elements.
4124// - No prototype has enumerable properties/elements.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004125bool JSReceiver::IsSimpleEnum() {
Steve Block44f0eee2011-05-26 01:26:41 +01004126 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004127 for (Object* o = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004128 o != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004129 o = JSObject::cast(o)->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004130 if (!o->IsJSObject()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004131 JSObject* curr = JSObject::cast(o);
Steve Blocka7e24c12009-10-30 11:49:00 +00004132 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00004133 ASSERT(!curr->HasNamedInterceptor());
4134 ASSERT(!curr->HasIndexedInterceptor());
4135 ASSERT(!curr->IsAccessCheckNeeded());
Steve Blocka7e24c12009-10-30 11:49:00 +00004136 if (curr->NumberOfEnumElements() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004137 if (curr != this) {
4138 FixedArray* curr_fixed_array =
4139 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
Steve Blockd0582a62009-12-15 09:54:21 +00004140 if (curr_fixed_array->length() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004141 }
4142 }
4143 return true;
4144}
4145
4146
4147int Map::NumberOfDescribedProperties() {
4148 int result = 0;
4149 DescriptorArray* descs = instance_descriptors();
4150 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4151 if (descs->IsProperty(i)) result++;
4152 }
4153 return result;
4154}
4155
4156
4157int Map::PropertyIndexFor(String* name) {
4158 DescriptorArray* descs = instance_descriptors();
4159 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4160 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
4161 return descs->GetFieldIndex(i);
4162 }
4163 }
4164 return -1;
4165}
4166
4167
4168int Map::NextFreePropertyIndex() {
4169 int max_index = -1;
4170 DescriptorArray* descs = instance_descriptors();
4171 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4172 if (descs->GetType(i) == FIELD) {
4173 int current_index = descs->GetFieldIndex(i);
4174 if (current_index > max_index) max_index = current_index;
4175 }
4176 }
4177 return max_index + 1;
4178}
4179
4180
4181AccessorDescriptor* Map::FindAccessor(String* name) {
4182 DescriptorArray* descs = instance_descriptors();
4183 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4184 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
4185 return descs->GetCallbacks(i);
4186 }
4187 }
4188 return NULL;
4189}
4190
4191
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004192void JSReceiver::LocalLookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004193 ASSERT(name->IsString());
4194
Steve Block44f0eee2011-05-26 01:26:41 +01004195 Heap* heap = GetHeap();
4196
Steve Blocka7e24c12009-10-30 11:49:00 +00004197 if (IsJSGlobalProxy()) {
4198 Object* proto = GetPrototype();
4199 if (proto->IsNull()) return result->NotFound();
4200 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004201 return JSReceiver::cast(proto)->LocalLookup(name, result);
4202 }
4203
4204 if (IsJSProxy()) {
4205 result->HandlerResult(JSProxy::cast(this));
4206 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004207 }
4208
4209 // Do not use inline caching if the object is a non-global object
4210 // that requires access checks.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004211 if (IsAccessCheckNeeded()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004212 result->DisallowCaching();
4213 }
4214
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004215 JSObject* js_object = JSObject::cast(this);
4216
Steve Blocka7e24c12009-10-30 11:49:00 +00004217 // Check __proto__ before interceptor.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004218 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004219 result->ConstantResult(js_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00004220 return;
4221 }
4222
4223 // Check for lookup interceptor except when bootstrapping.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004224 if (js_object->HasNamedInterceptor() &&
4225 !heap->isolate()->bootstrapper()->IsActive()) {
4226 result->InterceptorResult(js_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00004227 return;
4228 }
4229
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004230 js_object->LocalLookupRealNamedProperty(name, result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004231}
4232
4233
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004234void JSReceiver::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004235 // Ecma-262 3rd 8.6.2.4
Steve Block44f0eee2011-05-26 01:26:41 +01004236 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004237 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004238 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004239 current = JSObject::cast(current)->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004240 JSReceiver::cast(current)->LocalLookup(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00004241 if (result->IsProperty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004242 }
4243 result->NotFound();
4244}
4245
4246
4247// Search object and it's prototype chain for callback properties.
4248void JSObject::LookupCallback(String* name, LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01004249 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004250 for (Object* current = this;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004251 current != heap->null_value() && current->IsJSObject();
Steve Blocka7e24c12009-10-30 11:49:00 +00004252 current = JSObject::cast(current)->GetPrototype()) {
4253 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00004254 if (result->IsProperty() && result->type() == CALLBACKS) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004255 }
4256 result->NotFound();
4257}
4258
4259
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004260// Search for a getter or setter in an elements dictionary and update its
4261// attributes. Returns either undefined if the element is read-only, or the
4262// getter/setter pair (fixed array) if there is an existing one, or the hole
4263// value if the element does not exist or is a normal non-getter/setter data
4264// element.
4265static Object* UpdateGetterSetterInDictionary(NumberDictionary* dictionary,
4266 uint32_t index,
4267 PropertyAttributes attributes,
4268 Heap* heap) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004269 int entry = dictionary->FindEntry(index);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004270 if (entry != NumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004271 Object* result = dictionary->ValueAt(entry);
4272 PropertyDetails details = dictionary->DetailsAt(entry);
4273 if (details.IsReadOnly()) return heap->undefined_value();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004274 if (details.type() == CALLBACKS && result->IsFixedArray()) {
4275 if (details.attributes() != attributes) {
4276 dictionary->DetailsAtPut(entry,
4277 PropertyDetails(attributes, CALLBACKS, index));
4278 }
4279 return result;
4280 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004281 }
4282 return heap->the_hole_value();
4283}
4284
4285
John Reck59135872010-11-02 12:39:01 -07004286MaybeObject* JSObject::DefineGetterSetter(String* name,
4287 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01004288 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004289 // Make sure that the top context does not change when doing callbacks or
4290 // interceptor calls.
4291 AssertNoContextChange ncc;
4292
Steve Blocka7e24c12009-10-30 11:49:00 +00004293 // Try to flatten before operating on the string.
Steve Block6ded16b2010-05-10 14:33:55 +01004294 name->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00004295
Leon Clarkef7060e22010-06-03 12:02:55 +01004296 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004297 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004298 }
4299
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004300 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00004301 bool is_element = name->AsArrayIndex(&index);
Steve Blocka7e24c12009-10-30 11:49:00 +00004302
4303 if (is_element) {
4304 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004305 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00004306 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004307 case FAST_DOUBLE_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00004308 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004309 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00004310 case EXTERNAL_BYTE_ELEMENTS:
4311 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4312 case EXTERNAL_SHORT_ELEMENTS:
4313 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4314 case EXTERNAL_INT_ELEMENTS:
4315 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4316 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00004317 case EXTERNAL_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00004318 // Ignore getters and setters on pixel and external array
4319 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01004320 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004321 case DICTIONARY_ELEMENTS: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004322 Object* probe = UpdateGetterSetterInDictionary(element_dictionary(),
4323 index,
4324 attributes,
4325 heap);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004326 if (!probe->IsTheHole()) return probe;
4327 // Otherwise allow to override it.
4328 break;
4329 }
4330 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4331 // Ascertain whether we have read-only properties or an existing
4332 // getter/setter pair in an arguments elements dictionary backing
4333 // store.
4334 FixedArray* parameter_map = FixedArray::cast(elements());
4335 uint32_t length = parameter_map->length();
4336 Object* probe =
4337 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
4338 if (probe == NULL || probe->IsTheHole()) {
4339 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4340 if (arguments->IsDictionary()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004341 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
4342 probe = UpdateGetterSetterInDictionary(dictionary,
4343 index,
4344 attributes,
4345 heap);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004346 if (!probe->IsTheHole()) return probe;
Steve Blocka7e24c12009-10-30 11:49:00 +00004347 }
4348 }
4349 break;
4350 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004351 }
4352 } else {
4353 // Lookup the name.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004354 LookupResult result(heap->isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004355 LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00004356 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004357 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004358 if (result.type() == CALLBACKS) {
4359 Object* obj = result.GetCallbackObject();
Leon Clarkef7060e22010-06-03 12:02:55 +01004360 // Need to preserve old getters/setters.
Leon Clarked91b9f72010-01-27 17:25:45 +00004361 if (obj->IsFixedArray()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004362 // Use set to update attributes.
4363 return SetPropertyCallback(name, obj, attributes);
Leon Clarked91b9f72010-01-27 17:25:45 +00004364 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004365 }
4366 }
4367 }
4368
4369 // Allocate the fixed array to hold getter and setter.
John Reck59135872010-11-02 12:39:01 -07004370 Object* structure;
Steve Block44f0eee2011-05-26 01:26:41 +01004371 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
John Reck59135872010-11-02 12:39:01 -07004372 if (!maybe_structure->ToObject(&structure)) return maybe_structure;
4373 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004374
4375 if (is_element) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004376 return SetElementCallback(index, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00004377 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01004378 return SetPropertyCallback(name, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00004379 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004380}
4381
4382
4383bool JSObject::CanSetCallback(String* name) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004384 ASSERT(!IsAccessCheckNeeded() ||
4385 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
Leon Clarkef7060e22010-06-03 12:02:55 +01004386
4387 // Check if there is an API defined callback object which prohibits
4388 // callback overwriting in this object or it's prototype chain.
4389 // This mechanism is needed for instance in a browser setting, where
4390 // certain accessors such as window.location should not be allowed
4391 // to be overwritten because allowing overwriting could potentially
4392 // cause security problems.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004393 LookupResult callback_result(GetIsolate());
Leon Clarkef7060e22010-06-03 12:02:55 +01004394 LookupCallback(name, &callback_result);
4395 if (callback_result.IsProperty()) {
4396 Object* obj = callback_result.GetCallbackObject();
4397 if (obj->IsAccessorInfo() &&
4398 AccessorInfo::cast(obj)->prohibits_overwriting()) {
4399 return false;
4400 }
4401 }
4402
4403 return true;
4404}
4405
4406
John Reck59135872010-11-02 12:39:01 -07004407MaybeObject* JSObject::SetElementCallback(uint32_t index,
4408 Object* structure,
4409 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004410 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4411
4412 // Normalize elements to make this operation simple.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004413 NumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004414 { Object* result;
4415 MaybeObject* maybe = NormalizeElements();
4416 if (!maybe->ToObject(&result)) return maybe;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004417 dictionary = NumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07004418 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004419 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Leon Clarkef7060e22010-06-03 12:02:55 +01004420
4421 // Update the dictionary with the new CALLBACKS property.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004422 { Object* result;
4423 MaybeObject* maybe = dictionary->Set(index, structure, details);
4424 if (!maybe->ToObject(&result)) return maybe;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004425 dictionary = NumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07004426 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004427
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004428 dictionary->set_requires_slow_elements();
4429 // Update the dictionary backing store on the object.
4430 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
4431 // Also delete any parameter alias.
4432 //
4433 // TODO(kmillikin): when deleting the last parameter alias we could
4434 // switch to a direct backing store without the parameter map. This
4435 // would allow GC of the context.
4436 FixedArray* parameter_map = FixedArray::cast(elements());
4437 uint32_t length = parameter_map->length();
4438 if (index < length - 2) {
4439 parameter_map->set(index + 2, GetHeap()->the_hole_value());
4440 }
4441 parameter_map->set(1, dictionary);
4442 } else {
4443 set_elements(dictionary);
4444 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004445
4446 return structure;
4447}
4448
4449
John Reck59135872010-11-02 12:39:01 -07004450MaybeObject* JSObject::SetPropertyCallback(String* name,
4451 Object* structure,
4452 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004453 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4454
4455 bool convert_back_to_fast = HasFastProperties() &&
4456 (map()->instance_descriptors()->number_of_descriptors()
4457 < DescriptorArray::kMaxNumberOfDescriptors);
4458
4459 // Normalize object to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07004460 Object* ok;
4461 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
4462 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4463 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004464
4465 // For the global object allocate a new map to invalidate the global inline
4466 // caches which have a global property cell reference directly in the code.
4467 if (IsGlobalObject()) {
John Reck59135872010-11-02 12:39:01 -07004468 Object* new_map;
4469 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
4470 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4471 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004472 set_map(Map::cast(new_map));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004473 // When running crankshaft, changing the map is not enough. We
4474 // need to deoptimize all functions that rely on this global
4475 // object.
4476 Deoptimizer::DeoptimizeGlobalObject(this);
Leon Clarkef7060e22010-06-03 12:02:55 +01004477 }
4478
4479 // Update the dictionary with the new CALLBACKS property.
John Reck59135872010-11-02 12:39:01 -07004480 Object* result;
4481 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
4482 if (!maybe_result->ToObject(&result)) return maybe_result;
4483 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004484
4485 if (convert_back_to_fast) {
John Reck59135872010-11-02 12:39:01 -07004486 { MaybeObject* maybe_ok = TransformToFastProperties(0);
4487 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4488 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004489 }
4490 return result;
4491}
4492
John Reck59135872010-11-02 12:39:01 -07004493MaybeObject* JSObject::DefineAccessor(String* name,
4494 bool is_getter,
Ben Murdochb0fe1622011-05-05 13:52:32 +01004495 Object* fun,
John Reck59135872010-11-02 12:39:01 -07004496 PropertyAttributes attributes) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004497 ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01004498 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00004499 // Check access rights if needed.
4500 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004501 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4502 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4503 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004504 }
4505
4506 if (IsJSGlobalProxy()) {
4507 Object* proto = GetPrototype();
4508 if (proto->IsNull()) return this;
4509 ASSERT(proto->IsJSGlobalObject());
4510 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
4511 fun, attributes);
4512 }
4513
John Reck59135872010-11-02 12:39:01 -07004514 Object* array;
4515 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
4516 if (!maybe_array->ToObject(&array)) return maybe_array;
4517 }
4518 if (array->IsUndefined()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00004519 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
4520 return this;
4521}
4522
4523
John Reck59135872010-11-02 12:39:01 -07004524MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Steve Block44f0eee2011-05-26 01:26:41 +01004525 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01004526 String* name = String::cast(info->name());
4527 // Check access rights if needed.
4528 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004529 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4530 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4531 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004532 }
4533
4534 if (IsJSGlobalProxy()) {
4535 Object* proto = GetPrototype();
4536 if (proto->IsNull()) return this;
4537 ASSERT(proto->IsJSGlobalObject());
4538 return JSObject::cast(proto)->DefineAccessor(info);
4539 }
4540
4541 // Make sure that the top context does not change when doing callbacks or
4542 // interceptor calls.
4543 AssertNoContextChange ncc;
4544
4545 // Try to flatten before operating on the string.
4546 name->TryFlatten();
4547
4548 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004549 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004550 }
4551
4552 uint32_t index = 0;
4553 bool is_element = name->AsArrayIndex(&index);
4554
4555 if (is_element) {
Steve Block44f0eee2011-05-26 01:26:41 +01004556 if (IsJSArray()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004557
4558 // Accessors overwrite previous callbacks (cf. with getters/setters).
4559 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004560 case FAST_SMI_ONLY_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004561 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004562 case FAST_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004563 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004564 case EXTERNAL_PIXEL_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004565 case EXTERNAL_BYTE_ELEMENTS:
4566 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4567 case EXTERNAL_SHORT_ELEMENTS:
4568 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4569 case EXTERNAL_INT_ELEMENTS:
4570 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4571 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00004572 case EXTERNAL_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004573 // Ignore getters and setters on pixel and external array
4574 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01004575 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004576 case DICTIONARY_ELEMENTS:
4577 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004578 case NON_STRICT_ARGUMENTS_ELEMENTS:
4579 UNIMPLEMENTED();
Leon Clarkef7060e22010-06-03 12:02:55 +01004580 break;
4581 }
4582
John Reck59135872010-11-02 12:39:01 -07004583 Object* ok;
4584 { MaybeObject* maybe_ok =
4585 SetElementCallback(index, info, info->property_attributes());
4586 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4587 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004588 } else {
4589 // Lookup the name.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004590 LookupResult result(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01004591 LocalLookup(name, &result);
4592 // ES5 forbids turning a property into an accessor if it's not
4593 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
4594 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
Steve Block44f0eee2011-05-26 01:26:41 +01004595 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004596 }
John Reck59135872010-11-02 12:39:01 -07004597 Object* ok;
4598 { MaybeObject* maybe_ok =
4599 SetPropertyCallback(name, info, info->property_attributes());
4600 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4601 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004602 }
4603
4604 return this;
4605}
4606
4607
Steve Blocka7e24c12009-10-30 11:49:00 +00004608Object* JSObject::LookupAccessor(String* name, bool is_getter) {
Steve Block44f0eee2011-05-26 01:26:41 +01004609 Heap* heap = GetHeap();
4610
Steve Blocka7e24c12009-10-30 11:49:00 +00004611 // Make sure that the top context does not change when doing callbacks or
4612 // interceptor calls.
4613 AssertNoContextChange ncc;
4614
4615 // Check access rights if needed.
4616 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004617 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
4618 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4619 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004620 }
4621
4622 // Make the lookup and include prototypes.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004623 // Introducing constants below makes static constants usage purely static
4624 // and avoids linker errors in debug build using gcc.
4625 const int getter_index = kGetterIndex;
4626 const int setter_index = kSetterIndex;
4627 int accessor_index = is_getter ? getter_index : setter_index;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004628 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00004629 if (name->AsArrayIndex(&index)) {
4630 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004631 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004632 obj = JSObject::cast(obj)->GetPrototype()) {
4633 JSObject* js_object = JSObject::cast(obj);
4634 if (js_object->HasDictionaryElements()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004635 NumberDictionary* dictionary = js_object->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +00004636 int entry = dictionary->FindEntry(index);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004637 if (entry != NumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004638 Object* element = dictionary->ValueAt(entry);
4639 PropertyDetails details = dictionary->DetailsAt(entry);
4640 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004641 if (element->IsFixedArray()) {
4642 return FixedArray::cast(element)->get(accessor_index);
4643 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004644 }
4645 }
4646 }
4647 }
4648 } else {
4649 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004650 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004651 obj = JSObject::cast(obj)->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004652 LookupResult result(heap->isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004653 JSObject::cast(obj)->LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00004654 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004655 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004656 if (result.type() == CALLBACKS) {
4657 Object* obj = result.GetCallbackObject();
4658 if (obj->IsFixedArray()) {
4659 return FixedArray::cast(obj)->get(accessor_index);
4660 }
4661 }
4662 }
4663 }
4664 }
Steve Block44f0eee2011-05-26 01:26:41 +01004665 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004666}
4667
4668
4669Object* JSObject::SlowReverseLookup(Object* value) {
4670 if (HasFastProperties()) {
4671 DescriptorArray* descs = map()->instance_descriptors();
4672 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4673 if (descs->GetType(i) == FIELD) {
4674 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
4675 return descs->GetKey(i);
4676 }
4677 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
4678 if (descs->GetConstantFunction(i) == value) {
4679 return descs->GetKey(i);
4680 }
4681 }
4682 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01004683 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004684 } else {
4685 return property_dictionary()->SlowReverseLookup(value);
4686 }
4687}
4688
4689
John Reck59135872010-11-02 12:39:01 -07004690MaybeObject* Map::CopyDropDescriptors() {
Steve Block44f0eee2011-05-26 01:26:41 +01004691 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07004692 Object* result;
4693 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004694 heap->AllocateMap(instance_type(), instance_size());
John Reck59135872010-11-02 12:39:01 -07004695 if (!maybe_result->ToObject(&result)) return maybe_result;
4696 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004697 Map::cast(result)->set_prototype(prototype());
4698 Map::cast(result)->set_constructor(constructor());
4699 // Don't copy descriptors, so map transitions always remain a forest.
4700 // If we retained the same descriptors we would have two maps
4701 // pointing to the same transition which is bad because the garbage
4702 // collector relies on being able to reverse pointers from transitions
4703 // to maps. If properties need to be retained use CopyDropTransitions.
Ben Murdoch257744e2011-11-30 15:57:28 +00004704 Map::cast(result)->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00004705 // Please note instance_type and instance_size are set when allocated.
4706 Map::cast(result)->set_inobject_properties(inobject_properties());
4707 Map::cast(result)->set_unused_property_fields(unused_property_fields());
4708
4709 // If the map has pre-allocated properties always start out with a descriptor
4710 // array describing these properties.
4711 if (pre_allocated_property_fields() > 0) {
4712 ASSERT(constructor()->IsJSFunction());
4713 JSFunction* ctor = JSFunction::cast(constructor());
John Reck59135872010-11-02 12:39:01 -07004714 Object* descriptors;
4715 { MaybeObject* maybe_descriptors =
4716 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4717 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4718 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004719 Map::cast(result)->set_instance_descriptors(
4720 DescriptorArray::cast(descriptors));
4721 Map::cast(result)->set_pre_allocated_property_fields(
4722 pre_allocated_property_fields());
4723 }
4724 Map::cast(result)->set_bit_field(bit_field());
4725 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004726 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004727 Map::cast(result)->set_is_shared(false);
Steve Block44f0eee2011-05-26 01:26:41 +01004728 Map::cast(result)->ClearCodeCache(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00004729 return result;
4730}
4731
4732
John Reck59135872010-11-02 12:39:01 -07004733MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4734 NormalizedMapSharingMode sharing) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004735 int new_instance_size = instance_size();
4736 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4737 new_instance_size -= inobject_properties() * kPointerSize;
4738 }
4739
John Reck59135872010-11-02 12:39:01 -07004740 Object* result;
4741 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004742 GetHeap()->AllocateMap(instance_type(), new_instance_size);
John Reck59135872010-11-02 12:39:01 -07004743 if (!maybe_result->ToObject(&result)) return maybe_result;
4744 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004745
4746 if (mode != CLEAR_INOBJECT_PROPERTIES) {
4747 Map::cast(result)->set_inobject_properties(inobject_properties());
4748 }
4749
4750 Map::cast(result)->set_prototype(prototype());
4751 Map::cast(result)->set_constructor(constructor());
4752
4753 Map::cast(result)->set_bit_field(bit_field());
4754 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004755 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004756
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004757 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4758
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004759#ifdef DEBUG
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004760 if (FLAG_verify_heap && Map::cast(result)->is_shared()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004761 Map::cast(result)->SharedMapVerify();
4762 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004763#endif
4764
4765 return result;
4766}
4767
4768
John Reck59135872010-11-02 12:39:01 -07004769MaybeObject* Map::CopyDropTransitions() {
4770 Object* new_map;
4771 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4772 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4773 }
4774 Object* descriptors;
4775 { MaybeObject* maybe_descriptors =
4776 instance_descriptors()->RemoveTransitions();
4777 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4778 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004779 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
Steve Block8defd9f2010-07-08 12:39:36 +01004780 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00004781}
4782
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004783void Map::UpdateCodeCache(Handle<Map> map,
4784 Handle<String> name,
4785 Handle<Code> code) {
4786 Isolate* isolate = map->GetIsolate();
4787 CALL_HEAP_FUNCTION_VOID(isolate,
4788 map->UpdateCodeCache(*name, *code));
4789}
Steve Blocka7e24c12009-10-30 11:49:00 +00004790
John Reck59135872010-11-02 12:39:01 -07004791MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004792 // Allocate the code cache if not present.
4793 if (code_cache()->IsFixedArray()) {
John Reck59135872010-11-02 12:39:01 -07004794 Object* result;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004795 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
John Reck59135872010-11-02 12:39:01 -07004796 if (!maybe_result->ToObject(&result)) return maybe_result;
4797 }
Steve Block6ded16b2010-05-10 14:33:55 +01004798 set_code_cache(result);
4799 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004800
Steve Block6ded16b2010-05-10 14:33:55 +01004801 // Update the code cache.
4802 return CodeCache::cast(code_cache())->Update(name, code);
4803}
4804
4805
4806Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4807 // Do a lookup if a code cache exists.
4808 if (!code_cache()->IsFixedArray()) {
4809 return CodeCache::cast(code_cache())->Lookup(name, flags);
4810 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004811 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004812 }
4813}
4814
4815
4816int Map::IndexInCodeCache(Object* name, Code* code) {
4817 // Get the internal index if a code cache exists.
4818 if (!code_cache()->IsFixedArray()) {
4819 return CodeCache::cast(code_cache())->GetIndex(name, code);
4820 }
4821 return -1;
4822}
4823
4824
4825void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4826 // No GC is supposed to happen between a call to IndexInCodeCache and
4827 // RemoveFromCodeCache so the code cache must be there.
4828 ASSERT(!code_cache()->IsFixedArray());
4829 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4830}
4831
4832
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004833void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
Steve Block053d10c2011-06-13 19:13:29 +01004834 // Traverse the transition tree without using a stack. We do this by
4835 // reversing the pointers in the maps and descriptor arrays.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004836 Map* current = this;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004837 Map* meta_map = GetHeap()->meta_map();
Steve Block053d10c2011-06-13 19:13:29 +01004838 Object** map_or_index_field = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01004839 while (current != meta_map) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004840 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00004841 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
Steve Block053d10c2011-06-13 19:13:29 +01004842 if (!d->IsEmpty()) {
4843 FixedArray* contents = reinterpret_cast<FixedArray*>(
4844 d->get(DescriptorArray::kContentArrayIndex));
4845 map_or_index_field = RawField(contents, HeapObject::kMapOffset);
4846 Object* map_or_index = *map_or_index_field;
4847 bool map_done = true; // Controls a nested continue statement.
4848 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
4849 i < contents->length();
4850 i += 2) {
4851 PropertyDetails details(Smi::cast(contents->get(i + 1)));
4852 if (details.IsTransition()) {
4853 // Found a map in the transition array. We record our progress in
4854 // the transition array by recording the current map in the map field
4855 // of the next map and recording the index in the transition array in
4856 // the map field of the array.
4857 Map* next = Map::cast(contents->get(i));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004858 next->set_map_unsafe(current);
Steve Block053d10c2011-06-13 19:13:29 +01004859 *map_or_index_field = Smi::FromInt(i + 2);
4860 current = next;
4861 map_done = false;
4862 break;
4863 }
4864 }
4865 if (!map_done) continue;
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01004866 } else {
4867 map_or_index_field = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004868 }
Steve Block053d10c2011-06-13 19:13:29 +01004869 // That was the regular transitions, now for the prototype transitions.
4870 FixedArray* prototype_transitions =
4871 current->unchecked_prototype_transitions();
4872 Object** proto_map_or_index_field =
4873 RawField(prototype_transitions, HeapObject::kMapOffset);
4874 Object* map_or_index = *proto_map_or_index_field;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004875 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
Steve Block053d10c2011-06-13 19:13:29 +01004876 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
4877 if (i < prototype_transitions->length()) {
4878 // Found a map in the prototype transition array. Record progress in
4879 // an analogous way to the regular transitions array above.
4880 Object* perhaps_map = prototype_transitions->get(i);
4881 if (perhaps_map->IsMap()) {
4882 Map* next = Map::cast(perhaps_map);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004883 next->set_map_unsafe(current);
Steve Block053d10c2011-06-13 19:13:29 +01004884 *proto_map_or_index_field =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004885 Smi::FromInt(i + kProtoTransitionElementsPerEntry);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004886 current = next;
Steve Block053d10c2011-06-13 19:13:29 +01004887 continue;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004888 }
4889 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004890 *proto_map_or_index_field = GetHeap()->fixed_array_map();
Steve Block053d10c2011-06-13 19:13:29 +01004891 if (map_or_index_field != NULL) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004892 *map_or_index_field = GetHeap()->fixed_array_map();
Steve Block053d10c2011-06-13 19:13:29 +01004893 }
4894
4895 // The callback expects a map to have a real map as its map, so we save
4896 // the map field, which is being used to track the traversal and put the
4897 // correct map (the meta_map) in place while we do the callback.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004898 Map* prev = current->map();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004899 current->set_map_unsafe(meta_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004900 callback(current, data);
4901 current = prev;
4902 }
4903}
4904
4905
John Reck59135872010-11-02 12:39:01 -07004906MaybeObject* CodeCache::Update(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004907 // The number of monomorphic stubs for normal load/store/call IC's can grow to
4908 // a large number and therefore they need to go into a hash table. They are
4909 // used to load global properties from cells.
4910 if (code->type() == NORMAL) {
4911 // Make sure that a hash table is allocated for the normal load code cache.
4912 if (normal_type_cache()->IsUndefined()) {
John Reck59135872010-11-02 12:39:01 -07004913 Object* result;
4914 { MaybeObject* maybe_result =
4915 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
4916 if (!maybe_result->ToObject(&result)) return maybe_result;
4917 }
Steve Block6ded16b2010-05-10 14:33:55 +01004918 set_normal_type_cache(result);
4919 }
4920 return UpdateNormalTypeCache(name, code);
4921 } else {
4922 ASSERT(default_cache()->IsFixedArray());
4923 return UpdateDefaultCache(name, code);
4924 }
4925}
4926
4927
John Reck59135872010-11-02 12:39:01 -07004928MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004929 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00004930 // flags. This allows call constant stubs to overwrite call field
4931 // stubs, etc.
4932 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
4933
4934 // First check whether we can update existing code cache without
4935 // extending it.
Steve Block6ded16b2010-05-10 14:33:55 +01004936 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004937 int length = cache->length();
4938 int deleted_index = -1;
Steve Block6ded16b2010-05-10 14:33:55 +01004939 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004940 Object* key = cache->get(i);
4941 if (key->IsNull()) {
4942 if (deleted_index < 0) deleted_index = i;
4943 continue;
4944 }
4945 if (key->IsUndefined()) {
4946 if (deleted_index >= 0) i = deleted_index;
Steve Block6ded16b2010-05-10 14:33:55 +01004947 cache->set(i + kCodeCacheEntryNameOffset, name);
4948 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004949 return this;
4950 }
4951 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01004952 Code::Flags found =
4953 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
Steve Blocka7e24c12009-10-30 11:49:00 +00004954 if (Code::RemoveTypeFromFlags(found) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01004955 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004956 return this;
4957 }
4958 }
4959 }
4960
4961 // Reached the end of the code cache. If there were deleted
4962 // elements, reuse the space for the first of them.
4963 if (deleted_index >= 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01004964 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
4965 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004966 return this;
4967 }
4968
Steve Block6ded16b2010-05-10 14:33:55 +01004969 // Extend the code cache with some new entries (at least one). Must be a
4970 // multiple of the entry size.
4971 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
4972 new_length = new_length - new_length % kCodeCacheEntrySize;
4973 ASSERT((new_length % kCodeCacheEntrySize) == 0);
John Reck59135872010-11-02 12:39:01 -07004974 Object* result;
4975 { MaybeObject* maybe_result = cache->CopySize(new_length);
4976 if (!maybe_result->ToObject(&result)) return maybe_result;
4977 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004978
4979 // Add the (name, code) pair to the new cache.
4980 cache = FixedArray::cast(result);
Steve Block6ded16b2010-05-10 14:33:55 +01004981 cache->set(length + kCodeCacheEntryNameOffset, name);
4982 cache->set(length + kCodeCacheEntryCodeOffset, code);
4983 set_default_cache(cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00004984 return this;
4985}
4986
4987
John Reck59135872010-11-02 12:39:01 -07004988MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004989 // Adding a new entry can cause a new cache to be allocated.
4990 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
John Reck59135872010-11-02 12:39:01 -07004991 Object* new_cache;
4992 { MaybeObject* maybe_new_cache = cache->Put(name, code);
4993 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4994 }
Steve Block6ded16b2010-05-10 14:33:55 +01004995 set_normal_type_cache(new_cache);
4996 return this;
4997}
4998
4999
5000Object* CodeCache::Lookup(String* name, Code::Flags flags) {
5001 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
5002 return LookupNormalTypeCache(name, flags);
5003 } else {
5004 return LookupDefaultCache(name, flags);
5005 }
5006}
5007
5008
5009Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
5010 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005011 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01005012 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
5013 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00005014 // Skip deleted elements.
5015 if (key->IsNull()) continue;
5016 if (key->IsUndefined()) return key;
5017 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01005018 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
5019 if (code->flags() == flags) {
5020 return code;
5021 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005022 }
5023 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01005024 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00005025}
5026
5027
Steve Block6ded16b2010-05-10 14:33:55 +01005028Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
5029 if (!normal_type_cache()->IsUndefined()) {
5030 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5031 return cache->Lookup(name, flags);
5032 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005033 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005034 }
5035}
5036
5037
5038int CodeCache::GetIndex(Object* name, Code* code) {
5039 if (code->type() == NORMAL) {
5040 if (normal_type_cache()->IsUndefined()) return -1;
5041 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5042 return cache->GetIndex(String::cast(name), code->flags());
5043 }
5044
5045 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005046 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01005047 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
5048 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00005049 }
5050 return -1;
5051}
5052
5053
Steve Block6ded16b2010-05-10 14:33:55 +01005054void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
5055 if (code->type() == NORMAL) {
5056 ASSERT(!normal_type_cache()->IsUndefined());
5057 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5058 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
5059 cache->RemoveByIndex(index);
5060 } else {
5061 FixedArray* array = default_cache();
5062 ASSERT(array->length() >= index && array->get(index)->IsCode());
5063 // Use null instead of undefined for deleted elements to distinguish
5064 // deleted elements from unused elements. This distinction is used
5065 // when looking up in the cache and when updating the cache.
5066 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
5067 array->set_null(index - 1); // Name.
5068 array->set_null(index); // Code.
5069 }
5070}
5071
5072
5073// The key in the code cache hash table consists of the property name and the
5074// code object. The actual match is on the name and the code flags. If a key
5075// is created using the flags and not a code object it can only be used for
5076// lookup not to create a new entry.
5077class CodeCacheHashTableKey : public HashTableKey {
5078 public:
5079 CodeCacheHashTableKey(String* name, Code::Flags flags)
5080 : name_(name), flags_(flags), code_(NULL) { }
5081
5082 CodeCacheHashTableKey(String* name, Code* code)
5083 : name_(name),
5084 flags_(code->flags()),
5085 code_(code) { }
5086
5087
5088 bool IsMatch(Object* other) {
5089 if (!other->IsFixedArray()) return false;
5090 FixedArray* pair = FixedArray::cast(other);
5091 String* name = String::cast(pair->get(0));
5092 Code::Flags flags = Code::cast(pair->get(1))->flags();
5093 if (flags != flags_) {
5094 return false;
5095 }
5096 return name_->Equals(name);
5097 }
5098
5099 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
5100 return name->Hash() ^ flags;
5101 }
5102
5103 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
5104
5105 uint32_t HashForObject(Object* obj) {
5106 FixedArray* pair = FixedArray::cast(obj);
5107 String* name = String::cast(pair->get(0));
5108 Code* code = Code::cast(pair->get(1));
5109 return NameFlagsHashHelper(name, code->flags());
5110 }
5111
John Reck59135872010-11-02 12:39:01 -07005112 MUST_USE_RESULT MaybeObject* AsObject() {
Steve Block6ded16b2010-05-10 14:33:55 +01005113 ASSERT(code_ != NULL);
John Reck59135872010-11-02 12:39:01 -07005114 Object* obj;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005115 { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07005116 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5117 }
Steve Block6ded16b2010-05-10 14:33:55 +01005118 FixedArray* pair = FixedArray::cast(obj);
5119 pair->set(0, name_);
5120 pair->set(1, code_);
5121 return pair;
5122 }
5123
5124 private:
5125 String* name_;
5126 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005127 // TODO(jkummerow): We should be able to get by without this.
Steve Block6ded16b2010-05-10 14:33:55 +01005128 Code* code_;
5129};
5130
5131
5132Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
5133 CodeCacheHashTableKey key(name, flags);
5134 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01005135 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005136 return get(EntryToIndex(entry) + 1);
5137}
5138
5139
John Reck59135872010-11-02 12:39:01 -07005140MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01005141 CodeCacheHashTableKey key(name, code);
John Reck59135872010-11-02 12:39:01 -07005142 Object* obj;
5143 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5144 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5145 }
Steve Block6ded16b2010-05-10 14:33:55 +01005146
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005147 // Don't use |this|, as the table might have grown.
Steve Block6ded16b2010-05-10 14:33:55 +01005148 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
5149
5150 int entry = cache->FindInsertionEntry(key.Hash());
John Reck59135872010-11-02 12:39:01 -07005151 Object* k;
5152 { MaybeObject* maybe_k = key.AsObject();
5153 if (!maybe_k->ToObject(&k)) return maybe_k;
5154 }
Steve Block6ded16b2010-05-10 14:33:55 +01005155
5156 cache->set(EntryToIndex(entry), k);
5157 cache->set(EntryToIndex(entry) + 1, code);
5158 cache->ElementAdded();
5159 return cache;
5160}
5161
5162
5163int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
5164 CodeCacheHashTableKey key(name, flags);
5165 int entry = FindEntry(&key);
5166 return (entry == kNotFound) ? -1 : entry;
5167}
5168
5169
5170void CodeCacheHashTable::RemoveByIndex(int index) {
5171 ASSERT(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01005172 Heap* heap = GetHeap();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005173 set(EntryToIndex(index), heap->the_hole_value());
5174 set(EntryToIndex(index) + 1, heap->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01005175 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00005176}
5177
5178
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005179void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
5180 MapHandleList* maps,
5181 Code::Flags flags,
5182 Handle<Code> code) {
5183 Isolate* isolate = cache->GetIsolate();
5184 CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
5185}
5186
5187
5188MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005189 Code::Flags flags,
5190 Code* code) {
5191 // Initialize cache if necessary.
5192 if (cache()->IsUndefined()) {
5193 Object* result;
5194 { MaybeObject* maybe_result =
5195 PolymorphicCodeCacheHashTable::Allocate(
5196 PolymorphicCodeCacheHashTable::kInitialSize);
5197 if (!maybe_result->ToObject(&result)) return maybe_result;
5198 }
5199 set_cache(result);
5200 } else {
5201 // This entry shouldn't be contained in the cache yet.
5202 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
5203 ->Lookup(maps, flags)->IsUndefined());
5204 }
5205 PolymorphicCodeCacheHashTable* hash_table =
5206 PolymorphicCodeCacheHashTable::cast(cache());
5207 Object* new_cache;
5208 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
5209 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5210 }
5211 set_cache(new_cache);
5212 return this;
5213}
5214
5215
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005216Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
5217 Code::Flags flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005218 if (!cache()->IsUndefined()) {
5219 PolymorphicCodeCacheHashTable* hash_table =
5220 PolymorphicCodeCacheHashTable::cast(cache());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005221 return Handle<Object>(hash_table->Lookup(maps, flags));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005222 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005223 return GetIsolate()->factory()->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005224 }
5225}
5226
5227
5228// Despite their name, object of this class are not stored in the actual
5229// hash table; instead they're temporarily used for lookups. It is therefore
5230// safe to have a weak (non-owning) pointer to a MapList as a member field.
5231class PolymorphicCodeCacheHashTableKey : public HashTableKey {
5232 public:
5233 // Callers must ensure that |maps| outlives the newly constructed object.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005234 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005235 : maps_(maps),
5236 code_flags_(code_flags) {}
5237
5238 bool IsMatch(Object* other) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005239 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005240 int other_flags;
5241 FromObject(other, &other_flags, &other_maps);
5242 if (code_flags_ != other_flags) return false;
5243 if (maps_->length() != other_maps.length()) return false;
5244 // Compare just the hashes first because it's faster.
5245 int this_hash = MapsHashHelper(maps_, code_flags_);
5246 int other_hash = MapsHashHelper(&other_maps, other_flags);
5247 if (this_hash != other_hash) return false;
5248
5249 // Full comparison: for each map in maps_, look for an equivalent map in
5250 // other_maps. This implementation is slow, but probably good enough for
5251 // now because the lists are short (<= 4 elements currently).
5252 for (int i = 0; i < maps_->length(); ++i) {
5253 bool match_found = false;
5254 for (int j = 0; j < other_maps.length(); ++j) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005255 if (maps_->at(i)->EquivalentTo(*other_maps.at(j))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005256 match_found = true;
5257 break;
5258 }
5259 }
5260 if (!match_found) return false;
5261 }
5262 return true;
5263 }
5264
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005265 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005266 uint32_t hash = code_flags;
5267 for (int i = 0; i < maps->length(); ++i) {
5268 hash ^= maps->at(i)->Hash();
5269 }
5270 return hash;
5271 }
5272
5273 uint32_t Hash() {
5274 return MapsHashHelper(maps_, code_flags_);
5275 }
5276
5277 uint32_t HashForObject(Object* obj) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005278 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005279 int other_flags;
5280 FromObject(obj, &other_flags, &other_maps);
5281 return MapsHashHelper(&other_maps, other_flags);
5282 }
5283
5284 MUST_USE_RESULT MaybeObject* AsObject() {
5285 Object* obj;
5286 // The maps in |maps_| must be copied to a newly allocated FixedArray,
5287 // both because the referenced MapList is short-lived, and because C++
5288 // objects can't be stored in the heap anyway.
5289 { MaybeObject* maybe_obj =
5290 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
5291 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5292 }
5293 FixedArray* list = FixedArray::cast(obj);
5294 list->set(0, Smi::FromInt(code_flags_));
5295 for (int i = 0; i < maps_->length(); ++i) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005296 list->set(i + 1, *maps_->at(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005297 }
5298 return list;
5299 }
5300
5301 private:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005302 static MapHandleList* FromObject(Object* obj,
5303 int* code_flags,
5304 MapHandleList* maps) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005305 FixedArray* list = FixedArray::cast(obj);
5306 maps->Rewind(0);
5307 *code_flags = Smi::cast(list->get(0))->value();
5308 for (int i = 1; i < list->length(); ++i) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005309 maps->Add(Handle<Map>(Map::cast(list->get(i))));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005310 }
5311 return maps;
5312 }
5313
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005314 MapHandleList* maps_; // weak.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005315 int code_flags_;
5316 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
5317};
5318
5319
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005320Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
5321 int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005322 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5323 int entry = FindEntry(&key);
5324 if (entry == kNotFound) return GetHeap()->undefined_value();
5325 return get(EntryToIndex(entry) + 1);
5326}
5327
5328
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005329MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005330 int code_flags,
5331 Code* code) {
5332 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5333 Object* obj;
5334 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5335 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5336 }
5337 PolymorphicCodeCacheHashTable* cache =
5338 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
5339 int entry = cache->FindInsertionEntry(key.Hash());
5340 { MaybeObject* maybe_obj = key.AsObject();
5341 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5342 }
5343 cache->set(EntryToIndex(entry), obj);
5344 cache->set(EntryToIndex(entry) + 1, code);
5345 cache->ElementAdded();
5346 return cache;
5347}
5348
5349
John Reck59135872010-11-02 12:39:01 -07005350MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005351 ElementsAccessor* accessor = array->GetElementsAccessor();
5352 MaybeObject* maybe_result =
5353 accessor->AddElementsToFixedArray(array->elements(), this, array, array);
5354 FixedArray* result;
5355 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
5356#ifdef DEBUG
5357 if (FLAG_enable_slow_asserts) {
5358 for (int i = 0; i < result->length(); i++) {
5359 Object* current = result->get(i);
5360 ASSERT(current->IsNumber() || current->IsString());
Steve Blocka7e24c12009-10-30 11:49:00 +00005361 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005362 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005363#endif
5364 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00005365}
5366
5367
John Reck59135872010-11-02 12:39:01 -07005368MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005369 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
5370 MaybeObject* maybe_result =
5371 accessor->AddElementsToFixedArray(other, this, NULL, NULL);
5372 FixedArray* result;
5373 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
Ben Murdochf87a2032010-10-22 12:50:53 +01005374#ifdef DEBUG
5375 if (FLAG_enable_slow_asserts) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005376 for (int i = 0; i < result->length(); i++) {
5377 Object* current = result->get(i);
5378 ASSERT(current->IsNumber() || current->IsString());
Ben Murdochf87a2032010-10-22 12:50:53 +01005379 }
5380 }
5381#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00005382 return result;
5383}
5384
5385
John Reck59135872010-11-02 12:39:01 -07005386MaybeObject* FixedArray::CopySize(int new_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01005387 Heap* heap = GetHeap();
5388 if (new_length == 0) return heap->empty_fixed_array();
John Reck59135872010-11-02 12:39:01 -07005389 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01005390 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
John Reck59135872010-11-02 12:39:01 -07005391 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5392 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005393 FixedArray* result = FixedArray::cast(obj);
5394 // Copy the content
Leon Clarke4515c472010-02-03 11:58:03 +00005395 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00005396 int len = length();
5397 if (new_length < len) len = new_length;
5398 result->set_map(map());
Leon Clarke4515c472010-02-03 11:58:03 +00005399 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00005400 for (int i = 0; i < len; i++) {
5401 result->set(i, get(i), mode);
5402 }
5403 return result;
5404}
5405
5406
5407void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Leon Clarke4515c472010-02-03 11:58:03 +00005408 AssertNoAllocation no_gc;
5409 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00005410 for (int index = 0; index < len; index++) {
5411 dest->set(dest_pos+index, get(pos+index), mode);
5412 }
5413}
5414
5415
5416#ifdef DEBUG
5417bool FixedArray::IsEqualTo(FixedArray* other) {
5418 if (length() != other->length()) return false;
5419 for (int i = 0 ; i < length(); ++i) {
5420 if (get(i) != other->get(i)) return false;
5421 }
5422 return true;
5423}
5424#endif
5425
5426
John Reck59135872010-11-02 12:39:01 -07005427MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01005428 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005429 if (number_of_descriptors == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01005430 return heap->empty_descriptor_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00005431 }
5432 // Allocate the array of keys.
John Reck59135872010-11-02 12:39:01 -07005433 Object* array;
5434 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01005435 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
John Reck59135872010-11-02 12:39:01 -07005436 if (!maybe_array->ToObject(&array)) return maybe_array;
5437 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005438 // Do not use DescriptorArray::cast on incomplete object.
5439 FixedArray* result = FixedArray::cast(array);
5440
5441 // Allocate the content array and set it in the descriptor array.
John Reck59135872010-11-02 12:39:01 -07005442 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01005443 heap->AllocateFixedArray(number_of_descriptors << 1);
John Reck59135872010-11-02 12:39:01 -07005444 if (!maybe_array->ToObject(&array)) return maybe_array;
5445 }
Ben Murdoch257744e2011-11-30 15:57:28 +00005446 result->set(kBitField3StorageIndex, Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00005447 result->set(kContentArrayIndex, array);
5448 result->set(kEnumerationIndexIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00005449 Smi::FromInt(PropertyDetails::kInitialIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00005450 return result;
5451}
5452
5453
5454void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
5455 FixedArray* new_cache) {
5456 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
5457 if (HasEnumCache()) {
5458 FixedArray::cast(get(kEnumerationIndexIndex))->
5459 set(kEnumCacheBridgeCacheIndex, new_cache);
5460 } else {
5461 if (IsEmpty()) return; // Do nothing for empty descriptor array.
5462 FixedArray::cast(bridge_storage)->
5463 set(kEnumCacheBridgeCacheIndex, new_cache);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005464 NoWriteBarrierSet(FixedArray::cast(bridge_storage),
5465 kEnumCacheBridgeEnumIndex,
5466 get(kEnumerationIndexIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00005467 set(kEnumerationIndexIndex, bridge_storage);
5468 }
5469}
5470
5471
John Reck59135872010-11-02 12:39:01 -07005472MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
5473 TransitionFlag transition_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005474 // Transitions are only kept when inserting another transition.
5475 // This precondition is not required by this function's implementation, but
5476 // is currently required by the semantics of maps, so we check it.
5477 // Conversely, we filter after replacing, so replacing a transition and
5478 // removing all other transitions is not supported.
5479 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
5480 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
5481 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
5482
5483 // Ensure the key is a symbol.
John Reck59135872010-11-02 12:39:01 -07005484 Object* result;
5485 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
5486 if (!maybe_result->ToObject(&result)) return maybe_result;
5487 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005488
5489 int transitions = 0;
5490 int null_descriptors = 0;
5491 if (remove_transitions) {
5492 for (int i = 0; i < number_of_descriptors(); i++) {
5493 if (IsTransition(i)) transitions++;
5494 if (IsNullDescriptor(i)) null_descriptors++;
5495 }
5496 } else {
5497 for (int i = 0; i < number_of_descriptors(); i++) {
5498 if (IsNullDescriptor(i)) null_descriptors++;
5499 }
5500 }
5501 int new_size = number_of_descriptors() - transitions - null_descriptors;
5502
5503 // If key is in descriptor, we replace it in-place when filtering.
5504 // Count a null descriptor for key as inserted, not replaced.
5505 int index = Search(descriptor->GetKey());
5506 const bool inserting = (index == kNotFound);
5507 const bool replacing = !inserting;
5508 bool keep_enumeration_index = false;
5509 if (inserting) {
5510 ++new_size;
5511 }
5512 if (replacing) {
5513 // We are replacing an existing descriptor. We keep the enumeration
5514 // index of a visible property.
5515 PropertyType t = PropertyDetails(GetDetails(index)).type();
5516 if (t == CONSTANT_FUNCTION ||
5517 t == FIELD ||
5518 t == CALLBACKS ||
5519 t == INTERCEPTOR) {
5520 keep_enumeration_index = true;
5521 } else if (remove_transitions) {
5522 // Replaced descriptor has been counted as removed if it is
5523 // a transition that will be replaced. Adjust count in this case.
5524 ++new_size;
5525 }
5526 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005527
5528 DescriptorArray* new_descriptors;
John Reck59135872010-11-02 12:39:01 -07005529 { MaybeObject* maybe_result = Allocate(new_size);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005530 if (!maybe_result->To<DescriptorArray>(&new_descriptors)) {
5531 return maybe_result;
5532 }
John Reck59135872010-11-02 12:39:01 -07005533 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005534
5535 DescriptorArray::WhitenessWitness witness(new_descriptors);
5536
Steve Blocka7e24c12009-10-30 11:49:00 +00005537 // Set the enumeration index in the descriptors and set the enumeration index
5538 // in the result.
5539 int enumeration_index = NextEnumerationIndex();
5540 if (!descriptor->GetDetails().IsTransition()) {
5541 if (keep_enumeration_index) {
5542 descriptor->SetEnumerationIndex(
5543 PropertyDetails(GetDetails(index)).index());
5544 } else {
5545 descriptor->SetEnumerationIndex(enumeration_index);
5546 ++enumeration_index;
5547 }
5548 }
5549 new_descriptors->SetNextEnumerationIndex(enumeration_index);
5550
5551 // Copy the descriptors, filtering out transitions and null descriptors,
5552 // and inserting or replacing a descriptor.
5553 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
5554 int from_index = 0;
5555 int to_index = 0;
5556
5557 for (; from_index < number_of_descriptors(); from_index++) {
5558 String* key = GetKey(from_index);
5559 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
5560 break;
5561 }
5562 if (IsNullDescriptor(from_index)) continue;
5563 if (remove_transitions && IsTransition(from_index)) continue;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005564 new_descriptors->CopyFrom(to_index++, this, from_index, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +00005565 }
5566
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005567 new_descriptors->Set(to_index++, descriptor, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +00005568 if (replacing) from_index++;
5569
5570 for (; from_index < number_of_descriptors(); from_index++) {
5571 if (IsNullDescriptor(from_index)) continue;
5572 if (remove_transitions && IsTransition(from_index)) continue;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005573 new_descriptors->CopyFrom(to_index++, this, from_index, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +00005574 }
5575
5576 ASSERT(to_index == new_descriptors->number_of_descriptors());
5577 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
5578
5579 return new_descriptors;
5580}
5581
5582
John Reck59135872010-11-02 12:39:01 -07005583MaybeObject* DescriptorArray::RemoveTransitions() {
Steve Blocka7e24c12009-10-30 11:49:00 +00005584 // Remove all transitions and null descriptors. Return a copy of the array
5585 // with all transitions removed, or a Failure object if the new array could
5586 // not be allocated.
5587
5588 // Compute the size of the map transition entries to be removed.
5589 int num_removed = 0;
5590 for (int i = 0; i < number_of_descriptors(); i++) {
5591 if (!IsProperty(i)) num_removed++;
5592 }
5593
5594 // Allocate the new descriptor array.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005595 DescriptorArray* new_descriptors;
John Reck59135872010-11-02 12:39:01 -07005596 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005597 if (!maybe_result->To<DescriptorArray>(&new_descriptors)) {
5598 return maybe_result;
5599 }
John Reck59135872010-11-02 12:39:01 -07005600 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005601
5602 DescriptorArray::WhitenessWitness witness(new_descriptors);
Steve Blocka7e24c12009-10-30 11:49:00 +00005603
5604 // Copy the content.
5605 int next_descriptor = 0;
5606 for (int i = 0; i < number_of_descriptors(); i++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005607 if (IsProperty(i)) {
5608 new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
5609 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005610 }
5611 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
5612
5613 return new_descriptors;
5614}
5615
5616
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005617void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005618 // In-place heap sort.
5619 int len = number_of_descriptors();
5620
5621 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01005622 // Index of the last node with children
5623 const int max_parent_index = (len / 2) - 1;
5624 for (int i = max_parent_index; i >= 0; --i) {
5625 int parent_index = i;
5626 const uint32_t parent_hash = GetKey(i)->Hash();
5627 while (parent_index <= max_parent_index) {
5628 int child_index = 2 * parent_index + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00005629 uint32_t child_hash = GetKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01005630 if (child_index + 1 < len) {
5631 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5632 if (right_child_hash > child_hash) {
5633 child_index++;
5634 child_hash = right_child_hash;
5635 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005636 }
Steve Block6ded16b2010-05-10 14:33:55 +01005637 if (child_hash <= parent_hash) break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005638 NoWriteBarrierSwapDescriptors(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01005639 // Now element at child_index could be < its children.
5640 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00005641 }
5642 }
5643
5644 // Extract elements and create sorted array.
5645 for (int i = len - 1; i > 0; --i) {
5646 // Put max element at the back of the array.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005647 NoWriteBarrierSwapDescriptors(0, i);
5648 // Shift down the new top element.
Steve Blocka7e24c12009-10-30 11:49:00 +00005649 int parent_index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01005650 const uint32_t parent_hash = GetKey(parent_index)->Hash();
5651 const int max_parent_index = (i / 2) - 1;
5652 while (parent_index <= max_parent_index) {
5653 int child_index = parent_index * 2 + 1;
5654 uint32_t child_hash = GetKey(child_index)->Hash();
5655 if (child_index + 1 < i) {
5656 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5657 if (right_child_hash > child_hash) {
5658 child_index++;
5659 child_hash = right_child_hash;
5660 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005661 }
Steve Block6ded16b2010-05-10 14:33:55 +01005662 if (child_hash <= parent_hash) break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005663 NoWriteBarrierSwapDescriptors(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01005664 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00005665 }
5666 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005667}
Steve Blocka7e24c12009-10-30 11:49:00 +00005668
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005669
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005670void DescriptorArray::Sort(const WhitenessWitness& witness) {
5671 SortUnchecked(witness);
Steve Blocka7e24c12009-10-30 11:49:00 +00005672 SLOW_ASSERT(IsSortedNoDuplicates());
5673}
5674
5675
5676int DescriptorArray::BinarySearch(String* name, int low, int high) {
5677 uint32_t hash = name->Hash();
5678
5679 while (low <= high) {
5680 int mid = (low + high) / 2;
5681 String* mid_name = GetKey(mid);
5682 uint32_t mid_hash = mid_name->Hash();
5683
5684 if (mid_hash > hash) {
5685 high = mid - 1;
5686 continue;
5687 }
5688 if (mid_hash < hash) {
5689 low = mid + 1;
5690 continue;
5691 }
5692 // Found an element with the same hash-code.
5693 ASSERT(hash == mid_hash);
5694 // There might be more, so we find the first one and
5695 // check them all to see if we have a match.
5696 if (name == mid_name && !is_null_descriptor(mid)) return mid;
5697 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
5698 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
5699 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
5700 }
5701 break;
5702 }
5703 return kNotFound;
5704}
5705
5706
5707int DescriptorArray::LinearSearch(String* name, int len) {
5708 uint32_t hash = name->Hash();
5709 for (int number = 0; number < len; number++) {
5710 String* entry = GetKey(number);
5711 if ((entry->Hash() == hash) &&
5712 name->Equals(entry) &&
5713 !is_null_descriptor(number)) {
5714 return number;
5715 }
5716 }
5717 return kNotFound;
5718}
5719
5720
Ben Murdochb0fe1622011-05-05 13:52:32 +01005721MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5722 PretenureFlag pretenure) {
5723 ASSERT(deopt_entry_count > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01005724 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005725 pretenure);
5726}
5727
5728
5729MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5730 PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01005731 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5732 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005733 pretenure);
5734}
5735
5736
Steve Blocka7e24c12009-10-30 11:49:00 +00005737#ifdef DEBUG
5738bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5739 if (IsEmpty()) return other->IsEmpty();
5740 if (other->IsEmpty()) return false;
5741 if (length() != other->length()) return false;
5742 for (int i = 0; i < length(); ++i) {
5743 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5744 }
5745 return GetContentArray()->IsEqualTo(other->GetContentArray());
5746}
5747#endif
5748
5749
Steve Blocka7e24c12009-10-30 11:49:00 +00005750bool String::LooksValid() {
Steve Block44f0eee2011-05-26 01:26:41 +01005751 if (!Isolate::Current()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00005752 return true;
5753}
5754
5755
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005756String::FlatContent String::GetFlatContent() {
Steve Blocka7e24c12009-10-30 11:49:00 +00005757 int length = this->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005758 StringShape shape(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00005759 String* string = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00005760 int offset = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005761 if (shape.representation_tag() == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005762 ConsString* cons = ConsString::cast(string);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005763 if (cons->second()->length() != 0) {
5764 return FlatContent();
5765 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005766 string = cons->first();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005767 shape = StringShape(string);
Steve Blocka7e24c12009-10-30 11:49:00 +00005768 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005769 if (shape.representation_tag() == kSlicedStringTag) {
5770 SlicedString* slice = SlicedString::cast(string);
5771 offset = slice->offset();
5772 string = slice->parent();
5773 shape = StringShape(string);
5774 ASSERT(shape.representation_tag() != kConsStringTag &&
5775 shape.representation_tag() != kSlicedStringTag);
Steve Blocka7e24c12009-10-30 11:49:00 +00005776 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005777 if (shape.encoding_tag() == kAsciiStringTag) {
5778 const char* start;
5779 if (shape.representation_tag() == kSeqStringTag) {
5780 start = SeqAsciiString::cast(string)->GetChars();
5781 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005782 start = ExternalAsciiString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005783 }
5784 return FlatContent(Vector<const char>(start + offset, length));
5785 } else {
5786 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
5787 const uc16* start;
5788 if (shape.representation_tag() == kSeqStringTag) {
5789 start = SeqTwoByteString::cast(string)->GetChars();
5790 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005791 start = ExternalTwoByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005792 }
5793 return FlatContent(Vector<const uc16>(start + offset, length));
5794 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005795}
5796
5797
Ben Murdoch589d6972011-11-30 16:04:58 +00005798SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5799 RobustnessFlag robust_flag,
5800 int offset,
5801 int length,
5802 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005803 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00005804 return SmartArrayPointer<char>(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00005805 }
Steve Block44f0eee2011-05-26 01:26:41 +01005806 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005807
5808 // Negative length means the to the end of the string.
5809 if (length < 0) length = kMaxInt - offset;
5810
5811 // Compute the size of the UTF-8 string. Start at the specified offset.
Steve Block44f0eee2011-05-26 01:26:41 +01005812 Access<StringInputBuffer> buffer(
5813 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005814 buffer->Reset(offset, this);
5815 int character_position = offset;
5816 int utf8_bytes = 0;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005817 while (buffer->has_more() && character_position++ < offset + length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005818 uint16_t character = buffer->GetNext();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005819 utf8_bytes += unibrow::Utf8::Length(character);
Steve Blocka7e24c12009-10-30 11:49:00 +00005820 }
5821
5822 if (length_return) {
5823 *length_return = utf8_bytes;
5824 }
5825
5826 char* result = NewArray<char>(utf8_bytes + 1);
5827
5828 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
5829 buffer->Rewind();
5830 buffer->Seek(offset);
5831 character_position = offset;
5832 int utf8_byte_position = 0;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005833 while (buffer->has_more() && character_position++ < offset + length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005834 uint16_t character = buffer->GetNext();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005835 if (allow_nulls == DISALLOW_NULLS && character == 0) {
5836 character = ' ';
Steve Blocka7e24c12009-10-30 11:49:00 +00005837 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005838 utf8_byte_position +=
5839 unibrow::Utf8::Encode(result + utf8_byte_position, character);
Steve Blocka7e24c12009-10-30 11:49:00 +00005840 }
5841 result[utf8_byte_position] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00005842 return SmartArrayPointer<char>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005843}
5844
5845
Ben Murdoch589d6972011-11-30 16:04:58 +00005846SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5847 RobustnessFlag robust_flag,
5848 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005849 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
5850}
5851
5852
5853const uc16* String::GetTwoByteData() {
5854 return GetTwoByteData(0);
5855}
5856
5857
5858const uc16* String::GetTwoByteData(unsigned start) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005859 ASSERT(!IsAsciiRepresentationUnderneath());
Steve Blocka7e24c12009-10-30 11:49:00 +00005860 switch (StringShape(this).representation_tag()) {
5861 case kSeqStringTag:
5862 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
5863 case kExternalStringTag:
5864 return ExternalTwoByteString::cast(this)->
5865 ExternalTwoByteStringGetData(start);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005866 case kSlicedStringTag: {
5867 SlicedString* slice = SlicedString::cast(this);
5868 return slice->parent()->GetTwoByteData(start + slice->offset());
5869 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005870 case kConsStringTag:
5871 UNREACHABLE();
5872 return NULL;
5873 }
5874 UNREACHABLE();
5875 return NULL;
5876}
5877
5878
Ben Murdoch589d6972011-11-30 16:04:58 +00005879SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005880 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00005881 return SmartArrayPointer<uc16>();
Steve Blocka7e24c12009-10-30 11:49:00 +00005882 }
Steve Block44f0eee2011-05-26 01:26:41 +01005883 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005884
Steve Block44f0eee2011-05-26 01:26:41 +01005885 Access<StringInputBuffer> buffer(
5886 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005887 buffer->Reset(this);
5888
5889 uc16* result = NewArray<uc16>(length() + 1);
5890
5891 int i = 0;
5892 while (buffer->has_more()) {
5893 uint16_t character = buffer->GetNext();
5894 result[i++] = character;
5895 }
5896 result[i] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00005897 return SmartArrayPointer<uc16>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005898}
5899
5900
5901const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
5902 return reinterpret_cast<uc16*>(
5903 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
5904}
5905
5906
5907void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5908 unsigned* offset_ptr,
5909 unsigned max_chars) {
5910 unsigned chars_read = 0;
5911 unsigned offset = *offset_ptr;
5912 while (chars_read < max_chars) {
5913 uint16_t c = *reinterpret_cast<uint16_t*>(
5914 reinterpret_cast<char*>(this) -
5915 kHeapObjectTag + kHeaderSize + offset * kShortSize);
5916 if (c <= kMaxAsciiCharCode) {
5917 // Fast case for ASCII characters. Cursor is an input output argument.
5918 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5919 rbb->util_buffer,
5920 rbb->capacity,
5921 rbb->cursor)) {
5922 break;
5923 }
5924 } else {
5925 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5926 rbb->util_buffer,
5927 rbb->capacity,
5928 rbb->cursor)) {
5929 break;
5930 }
5931 }
5932 offset++;
5933 chars_read++;
5934 }
5935 *offset_ptr = offset;
5936 rbb->remaining += chars_read;
5937}
5938
5939
5940const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
5941 unsigned* remaining,
5942 unsigned* offset_ptr,
5943 unsigned max_chars) {
5944 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
5945 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
5946 *remaining = max_chars;
5947 *offset_ptr += max_chars;
5948 return b;
5949}
5950
5951
5952// This will iterate unless the block of string data spans two 'halves' of
5953// a ConsString, in which case it will recurse. Since the block of string
5954// data to be read has a maximum size this limits the maximum recursion
5955// depth to something sane. Since C++ does not have tail call recursion
5956// elimination, the iteration must be explicit. Since this is not an
5957// -IntoBuffer method it can delegate to one of the efficient
5958// *AsciiStringReadBlock routines.
5959const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
5960 unsigned* offset_ptr,
5961 unsigned max_chars) {
5962 ConsString* current = this;
5963 unsigned offset = *offset_ptr;
5964 int offset_correction = 0;
5965
5966 while (true) {
5967 String* left = current->first();
5968 unsigned left_length = (unsigned)left->length();
5969 if (left_length > offset &&
5970 (max_chars <= left_length - offset ||
5971 (rbb->capacity <= left_length - offset &&
5972 (max_chars = left_length - offset, true)))) { // comma operator!
5973 // Left hand side only - iterate unless we have reached the bottom of
5974 // the cons tree. The assignment on the left of the comma operator is
5975 // in order to make use of the fact that the -IntoBuffer routines can
5976 // produce at most 'capacity' characters. This enables us to postpone
5977 // the point where we switch to the -IntoBuffer routines (below) in order
5978 // to maximize the chances of delegating a big chunk of work to the
5979 // efficient *AsciiStringReadBlock routines.
5980 if (StringShape(left).IsCons()) {
5981 current = ConsString::cast(left);
5982 continue;
5983 } else {
5984 const unibrow::byte* answer =
5985 String::ReadBlock(left, rbb, &offset, max_chars);
5986 *offset_ptr = offset + offset_correction;
5987 return answer;
5988 }
5989 } else if (left_length <= offset) {
5990 // Right hand side only - iterate unless we have reached the bottom of
5991 // the cons tree.
5992 String* right = current->second();
5993 offset -= left_length;
5994 offset_correction += left_length;
5995 if (StringShape(right).IsCons()) {
5996 current = ConsString::cast(right);
5997 continue;
5998 } else {
5999 const unibrow::byte* answer =
6000 String::ReadBlock(right, rbb, &offset, max_chars);
6001 *offset_ptr = offset + offset_correction;
6002 return answer;
6003 }
6004 } else {
6005 // The block to be read spans two sides of the ConsString, so we call the
6006 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
6007 // are able to assemble data from several part strings because they use
6008 // the util_buffer to store their data and never return direct pointers
6009 // to their storage. We don't try to read more than the buffer capacity
6010 // here or we can get too much recursion.
6011 ASSERT(rbb->remaining == 0);
6012 ASSERT(rbb->cursor == 0);
6013 current->ConsStringReadBlockIntoBuffer(
6014 rbb,
6015 &offset,
6016 max_chars > rbb->capacity ? rbb->capacity : max_chars);
6017 *offset_ptr = offset + offset_correction;
6018 return rbb->util_buffer;
6019 }
6020 }
6021}
6022
6023
Steve Blocka7e24c12009-10-30 11:49:00 +00006024const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
6025 unsigned* remaining,
6026 unsigned* offset_ptr,
6027 unsigned max_chars) {
6028 // Cast const char* to unibrow::byte* (signedness difference).
6029 const unibrow::byte* b =
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006030 reinterpret_cast<const unibrow::byte*>(GetChars()) + *offset_ptr;
Steve Blocka7e24c12009-10-30 11:49:00 +00006031 *remaining = max_chars;
6032 *offset_ptr += max_chars;
6033 return b;
6034}
6035
6036
Steve Blocka7e24c12009-10-30 11:49:00 +00006037void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
6038 ReadBlockBuffer* rbb,
6039 unsigned* offset_ptr,
6040 unsigned max_chars) {
6041 unsigned chars_read = 0;
6042 unsigned offset = *offset_ptr;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006043 const uint16_t* data = GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006044 while (chars_read < max_chars) {
6045 uint16_t c = data[offset];
6046 if (c <= kMaxAsciiCharCode) {
6047 // Fast case for ASCII characters. Cursor is an input output argument.
6048 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6049 rbb->util_buffer,
6050 rbb->capacity,
6051 rbb->cursor))
6052 break;
6053 } else {
6054 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6055 rbb->util_buffer,
6056 rbb->capacity,
6057 rbb->cursor))
6058 break;
6059 }
6060 offset++;
6061 chars_read++;
6062 }
6063 *offset_ptr = offset;
6064 rbb->remaining += chars_read;
6065}
6066
6067
6068void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6069 unsigned* offset_ptr,
6070 unsigned max_chars) {
6071 unsigned capacity = rbb->capacity - rbb->cursor;
6072 if (max_chars > capacity) max_chars = capacity;
6073 memcpy(rbb->util_buffer + rbb->cursor,
6074 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
6075 *offset_ptr * kCharSize,
6076 max_chars);
6077 rbb->remaining += max_chars;
6078 *offset_ptr += max_chars;
6079 rbb->cursor += max_chars;
6080}
6081
6082
6083void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
6084 ReadBlockBuffer* rbb,
6085 unsigned* offset_ptr,
6086 unsigned max_chars) {
6087 unsigned capacity = rbb->capacity - rbb->cursor;
6088 if (max_chars > capacity) max_chars = capacity;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006089 memcpy(rbb->util_buffer + rbb->cursor, GetChars() + *offset_ptr, max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006090 rbb->remaining += max_chars;
6091 *offset_ptr += max_chars;
6092 rbb->cursor += max_chars;
6093}
6094
6095
6096// This method determines the type of string involved and then copies
6097// a whole chunk of characters into a buffer, or returns a pointer to a buffer
6098// where they can be found. The pointer is not necessarily valid across a GC
6099// (see AsciiStringReadBlock).
6100const unibrow::byte* String::ReadBlock(String* input,
6101 ReadBlockBuffer* rbb,
6102 unsigned* offset_ptr,
6103 unsigned max_chars) {
6104 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
6105 if (max_chars == 0) {
6106 rbb->remaining = 0;
6107 return NULL;
6108 }
6109 switch (StringShape(input).representation_tag()) {
6110 case kSeqStringTag:
6111 if (input->IsAsciiRepresentation()) {
6112 SeqAsciiString* str = SeqAsciiString::cast(input);
6113 return str->SeqAsciiStringReadBlock(&rbb->remaining,
6114 offset_ptr,
6115 max_chars);
6116 } else {
6117 SeqTwoByteString* str = SeqTwoByteString::cast(input);
6118 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6119 offset_ptr,
6120 max_chars);
6121 return rbb->util_buffer;
6122 }
6123 case kConsStringTag:
6124 return ConsString::cast(input)->ConsStringReadBlock(rbb,
6125 offset_ptr,
6126 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006127 case kExternalStringTag:
6128 if (input->IsAsciiRepresentation()) {
6129 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
6130 &rbb->remaining,
6131 offset_ptr,
6132 max_chars);
6133 } else {
6134 ExternalTwoByteString::cast(input)->
6135 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6136 offset_ptr,
6137 max_chars);
6138 return rbb->util_buffer;
6139 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006140 case kSlicedStringTag:
6141 return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
6142 offset_ptr,
6143 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006144 default:
6145 break;
6146 }
6147
6148 UNREACHABLE();
6149 return 0;
6150}
6151
6152
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006153// This method determines the type of string involved and then gets the UTF8
6154// length of the string. It doesn't flatten the string and has log(n) recursion
6155// for a string of length n.
6156int String::Utf8Length(String* input, int from, int to) {
6157 if (from == to) return 0;
6158 int total = 0;
6159 while (true) {
6160 if (input->IsAsciiRepresentation()) return total + to - from;
6161 switch (StringShape(input).representation_tag()) {
6162 case kConsStringTag: {
6163 ConsString* str = ConsString::cast(input);
6164 String* first = str->first();
6165 String* second = str->second();
6166 int first_length = first->length();
6167 if (first_length - from < to - first_length) {
6168 if (first_length > from) {
6169 // Left hand side is shorter.
6170 total += Utf8Length(first, from, first_length);
6171 input = second;
6172 from = 0;
6173 to -= first_length;
6174 } else {
6175 // We only need the right hand side.
6176 input = second;
6177 from -= first_length;
6178 to -= first_length;
6179 }
6180 } else {
6181 if (first_length <= to) {
6182 // Right hand side is shorter.
6183 total += Utf8Length(second, 0, to - first_length);
6184 input = first;
6185 to = first_length;
6186 } else {
6187 // We only need the left hand side.
6188 input = first;
6189 }
6190 }
6191 continue;
6192 }
6193 case kExternalStringTag:
6194 case kSeqStringTag: {
6195 Vector<const uc16> vector = input->GetFlatContent().ToUC16Vector();
6196 const uc16* p = vector.start();
6197 for (int i = from; i < to; i++) {
6198 total += unibrow::Utf8::Length(p[i]);
6199 }
6200 return total;
6201 }
6202 case kSlicedStringTag: {
6203 SlicedString* str = SlicedString::cast(input);
6204 int offset = str->offset();
6205 input = str->parent();
6206 from += offset;
6207 to += offset;
6208 continue;
6209 }
6210 default:
6211 break;
6212 }
6213 UNREACHABLE();
6214 return 0;
6215 }
6216 return 0;
6217}
6218
6219
Steve Blocka7e24c12009-10-30 11:49:00 +00006220void Relocatable::PostGarbageCollectionProcessing() {
Steve Block44f0eee2011-05-26 01:26:41 +01006221 Isolate* isolate = Isolate::Current();
6222 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00006223 while (current != NULL) {
6224 current->PostGarbageCollection();
6225 current = current->prev_;
6226 }
6227}
6228
6229
6230// Reserve space for statics needing saving and restoring.
6231int Relocatable::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +01006232 return sizeof(Isolate::Current()->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00006233}
6234
6235
6236// Archive statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00006237char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01006238 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
6239 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00006240 return to + ArchiveSpacePerThread();
6241}
6242
6243
6244// Restore statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00006245char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01006246 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00006247 return from + ArchiveSpacePerThread();
6248}
6249
6250
6251char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
6252 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
6253 Iterate(v, top);
6254 return thread_storage + ArchiveSpacePerThread();
6255}
6256
6257
6258void Relocatable::Iterate(ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01006259 Isolate* isolate = Isolate::Current();
6260 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00006261}
6262
6263
6264void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
6265 Relocatable* current = top;
6266 while (current != NULL) {
6267 current->IterateInstance(v);
6268 current = current->prev_;
6269 }
6270}
6271
6272
Steve Block44f0eee2011-05-26 01:26:41 +01006273FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
6274 : Relocatable(isolate),
6275 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00006276 length_(str->length()) {
6277 PostGarbageCollection();
6278}
6279
6280
Steve Block44f0eee2011-05-26 01:26:41 +01006281FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
6282 : Relocatable(isolate),
6283 str_(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00006284 is_ascii_(true),
6285 length_(input.length()),
6286 start_(input.start()) { }
6287
6288
6289void FlatStringReader::PostGarbageCollection() {
6290 if (str_ == NULL) return;
6291 Handle<String> str(str_);
6292 ASSERT(str->IsFlat());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006293 String::FlatContent content = str->GetFlatContent();
6294 ASSERT(content.IsFlat());
6295 is_ascii_ = content.IsAscii();
Steve Blocka7e24c12009-10-30 11:49:00 +00006296 if (is_ascii_) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006297 start_ = content.ToAsciiVector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00006298 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006299 start_ = content.ToUC16Vector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00006300 }
6301}
6302
6303
6304void StringInputBuffer::Seek(unsigned pos) {
6305 Reset(pos, input_);
6306}
6307
6308
6309void SafeStringInputBuffer::Seek(unsigned pos) {
6310 Reset(pos, input_);
6311}
6312
6313
6314// This method determines the type of string involved and then copies
6315// a whole chunk of characters into a buffer. It can be used with strings
6316// that have been glued together to form a ConsString and which must cooperate
6317// to fill up a buffer.
6318void String::ReadBlockIntoBuffer(String* input,
6319 ReadBlockBuffer* rbb,
6320 unsigned* offset_ptr,
6321 unsigned max_chars) {
6322 ASSERT(*offset_ptr <= (unsigned)input->length());
6323 if (max_chars == 0) return;
6324
6325 switch (StringShape(input).representation_tag()) {
6326 case kSeqStringTag:
6327 if (input->IsAsciiRepresentation()) {
6328 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
6329 offset_ptr,
6330 max_chars);
6331 return;
6332 } else {
6333 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6334 offset_ptr,
6335 max_chars);
6336 return;
6337 }
6338 case kConsStringTag:
6339 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
6340 offset_ptr,
6341 max_chars);
6342 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00006343 case kExternalStringTag:
6344 if (input->IsAsciiRepresentation()) {
Steve Blockd0582a62009-12-15 09:54:21 +00006345 ExternalAsciiString::cast(input)->
6346 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
6347 } else {
6348 ExternalTwoByteString::cast(input)->
6349 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6350 offset_ptr,
6351 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006352 }
6353 return;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006354 case kSlicedStringTag:
6355 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
6356 offset_ptr,
6357 max_chars);
6358 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00006359 default:
6360 break;
6361 }
6362
6363 UNREACHABLE();
6364 return;
6365}
6366
6367
6368const unibrow::byte* String::ReadBlock(String* input,
6369 unibrow::byte* util_buffer,
6370 unsigned capacity,
6371 unsigned* remaining,
6372 unsigned* offset_ptr) {
6373 ASSERT(*offset_ptr <= (unsigned)input->length());
6374 unsigned chars = input->length() - *offset_ptr;
6375 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6376 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
6377 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6378 *remaining = rbb.remaining;
6379 return answer;
6380}
6381
6382
6383const unibrow::byte* String::ReadBlock(String** raw_input,
6384 unibrow::byte* util_buffer,
6385 unsigned capacity,
6386 unsigned* remaining,
6387 unsigned* offset_ptr) {
6388 Handle<String> input(raw_input);
6389 ASSERT(*offset_ptr <= (unsigned)input->length());
6390 unsigned chars = input->length() - *offset_ptr;
6391 if (chars > capacity) chars = capacity;
6392 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6393 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
6394 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6395 *remaining = rbb.remaining;
6396 return rbb.util_buffer;
6397}
6398
6399
6400// This will iterate unless the block of string data spans two 'halves' of
6401// a ConsString, in which case it will recurse. Since the block of string
6402// data to be read has a maximum size this limits the maximum recursion
6403// depth to something sane. Since C++ does not have tail call recursion
6404// elimination, the iteration must be explicit.
6405void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6406 unsigned* offset_ptr,
6407 unsigned max_chars) {
6408 ConsString* current = this;
6409 unsigned offset = *offset_ptr;
6410 int offset_correction = 0;
6411
6412 while (true) {
6413 String* left = current->first();
6414 unsigned left_length = (unsigned)left->length();
6415 if (left_length > offset &&
6416 max_chars <= left_length - offset) {
6417 // Left hand side only - iterate unless we have reached the bottom of
6418 // the cons tree.
6419 if (StringShape(left).IsCons()) {
6420 current = ConsString::cast(left);
6421 continue;
6422 } else {
6423 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
6424 *offset_ptr = offset + offset_correction;
6425 return;
6426 }
6427 } else if (left_length <= offset) {
6428 // Right hand side only - iterate unless we have reached the bottom of
6429 // the cons tree.
6430 offset -= left_length;
6431 offset_correction += left_length;
6432 String* right = current->second();
6433 if (StringShape(right).IsCons()) {
6434 current = ConsString::cast(right);
6435 continue;
6436 } else {
6437 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6438 *offset_ptr = offset + offset_correction;
6439 return;
6440 }
6441 } else {
6442 // The block to be read spans two sides of the ConsString, so we recurse.
6443 // First recurse on the left.
6444 max_chars -= left_length - offset;
6445 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
6446 // We may have reached the max or there may not have been enough space
6447 // in the buffer for the characters in the left hand side.
6448 if (offset == left_length) {
6449 // Recurse on the right.
6450 String* right = String::cast(current->second());
6451 offset -= left_length;
6452 offset_correction += left_length;
6453 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6454 }
6455 *offset_ptr = offset + offset_correction;
6456 return;
6457 }
6458 }
6459}
6460
6461
Steve Blocka7e24c12009-10-30 11:49:00 +00006462uint16_t ConsString::ConsStringGet(int index) {
6463 ASSERT(index >= 0 && index < this->length());
6464
6465 // Check for a flattened cons string
6466 if (second()->length() == 0) {
6467 String* left = first();
6468 return left->Get(index);
6469 }
6470
6471 String* string = String::cast(this);
6472
6473 while (true) {
6474 if (StringShape(string).IsCons()) {
6475 ConsString* cons_string = ConsString::cast(string);
6476 String* left = cons_string->first();
6477 if (left->length() > index) {
6478 string = left;
6479 } else {
6480 index -= left->length();
6481 string = cons_string->second();
6482 }
6483 } else {
6484 return string->Get(index);
6485 }
6486 }
6487
6488 UNREACHABLE();
6489 return 0;
6490}
6491
6492
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006493uint16_t SlicedString::SlicedStringGet(int index) {
6494 return parent()->Get(offset() + index);
6495}
6496
6497
6498const unibrow::byte* SlicedString::SlicedStringReadBlock(
6499 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6500 unsigned offset = this->offset();
6501 *offset_ptr += offset;
6502 const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
6503 buffer, offset_ptr, chars);
6504 *offset_ptr -= offset;
6505 return answer;
6506}
6507
6508
6509void SlicedString::SlicedStringReadBlockIntoBuffer(
6510 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6511 unsigned offset = this->offset();
6512 *offset_ptr += offset;
6513 String::ReadBlockIntoBuffer(String::cast(parent()),
6514 buffer, offset_ptr, chars);
6515 *offset_ptr -= offset;
6516}
6517
Steve Blocka7e24c12009-10-30 11:49:00 +00006518template <typename sinkchar>
6519void String::WriteToFlat(String* src,
6520 sinkchar* sink,
6521 int f,
6522 int t) {
6523 String* source = src;
6524 int from = f;
6525 int to = t;
6526 while (true) {
6527 ASSERT(0 <= from && from <= to && to <= source->length());
6528 switch (StringShape(source).full_representation_tag()) {
6529 case kAsciiStringTag | kExternalStringTag: {
6530 CopyChars(sink,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006531 ExternalAsciiString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +00006532 to - from);
6533 return;
6534 }
6535 case kTwoByteStringTag | kExternalStringTag: {
6536 const uc16* data =
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006537 ExternalTwoByteString::cast(source)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006538 CopyChars(sink,
6539 data + from,
6540 to - from);
6541 return;
6542 }
6543 case kAsciiStringTag | kSeqStringTag: {
6544 CopyChars(sink,
6545 SeqAsciiString::cast(source)->GetChars() + from,
6546 to - from);
6547 return;
6548 }
6549 case kTwoByteStringTag | kSeqStringTag: {
6550 CopyChars(sink,
6551 SeqTwoByteString::cast(source)->GetChars() + from,
6552 to - from);
6553 return;
6554 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006555 case kAsciiStringTag | kConsStringTag:
6556 case kTwoByteStringTag | kConsStringTag: {
6557 ConsString* cons_string = ConsString::cast(source);
6558 String* first = cons_string->first();
6559 int boundary = first->length();
6560 if (to - boundary >= boundary - from) {
6561 // Right hand side is longer. Recurse over left.
6562 if (from < boundary) {
6563 WriteToFlat(first, sink, from, boundary);
6564 sink += boundary - from;
6565 from = 0;
6566 } else {
6567 from -= boundary;
6568 }
6569 to -= boundary;
6570 source = cons_string->second();
6571 } else {
6572 // Left hand side is longer. Recurse over right.
6573 if (to > boundary) {
6574 String* second = cons_string->second();
6575 WriteToFlat(second,
6576 sink + boundary - from,
6577 0,
6578 to - boundary);
6579 to = boundary;
6580 }
6581 source = first;
6582 }
6583 break;
6584 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006585 case kAsciiStringTag | kSlicedStringTag:
6586 case kTwoByteStringTag | kSlicedStringTag: {
6587 SlicedString* slice = SlicedString::cast(source);
6588 unsigned offset = slice->offset();
6589 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
6590 return;
6591 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006592 }
6593 }
6594}
6595
6596
Steve Blocka7e24c12009-10-30 11:49:00 +00006597template <typename IteratorA, typename IteratorB>
6598static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
6599 // General slow case check. We know that the ia and ib iterators
6600 // have the same length.
6601 while (ia->has_more()) {
6602 uc32 ca = ia->GetNext();
6603 uc32 cb = ib->GetNext();
6604 if (ca != cb)
6605 return false;
6606 }
6607 return true;
6608}
6609
6610
6611// Compares the contents of two strings by reading and comparing
6612// int-sized blocks of characters.
6613template <typename Char>
6614static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
6615 int length = a.length();
6616 ASSERT_EQ(length, b.length());
6617 const Char* pa = a.start();
6618 const Char* pb = b.start();
6619 int i = 0;
6620#ifndef V8_HOST_CAN_READ_UNALIGNED
6621 // If this architecture isn't comfortable reading unaligned ints
6622 // then we have to check that the strings are aligned before
6623 // comparing them blockwise.
6624 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
6625 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
6626 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
6627 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
6628#endif
6629 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
6630 int endpoint = length - kStepSize;
6631 // Compare blocks until we reach near the end of the string.
6632 for (; i <= endpoint; i += kStepSize) {
6633 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
6634 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
6635 if (wa != wb) {
6636 return false;
6637 }
6638 }
6639#ifndef V8_HOST_CAN_READ_UNALIGNED
6640 }
6641#endif
6642 // Compare the remaining characters that didn't fit into a block.
6643 for (; i < length; i++) {
6644 if (a[i] != b[i]) {
6645 return false;
6646 }
6647 }
6648 return true;
6649}
6650
6651
Steve Blocka7e24c12009-10-30 11:49:00 +00006652template <typename IteratorA>
Steve Block44f0eee2011-05-26 01:26:41 +01006653static inline bool CompareStringContentsPartial(Isolate* isolate,
6654 IteratorA* ia,
6655 String* b) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006656 String::FlatContent content = b->GetFlatContent();
6657 if (content.IsFlat()) {
6658 if (content.IsAscii()) {
6659 VectorIterator<char> ib(content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006660 return CompareStringContents(ia, &ib);
6661 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006662 VectorIterator<uc16> ib(content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006663 return CompareStringContents(ia, &ib);
6664 }
6665 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006666 isolate->objects_string_compare_buffer_b()->Reset(0, b);
6667 return CompareStringContents(ia,
6668 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006669 }
6670}
6671
6672
Steve Blocka7e24c12009-10-30 11:49:00 +00006673bool String::SlowEquals(String* other) {
6674 // Fast check: negative check with lengths.
6675 int len = length();
6676 if (len != other->length()) return false;
6677 if (len == 0) return true;
6678
6679 // Fast check: if hash code is computed for both strings
6680 // a fast negative check can be performed.
6681 if (HasHashCode() && other->HasHashCode()) {
6682 if (Hash() != other->Hash()) return false;
6683 }
6684
Leon Clarkef7060e22010-06-03 12:02:55 +01006685 // We know the strings are both non-empty. Compare the first chars
6686 // before we try to flatten the strings.
6687 if (this->Get(0) != other->Get(0)) return false;
6688
6689 String* lhs = this->TryFlattenGetString();
6690 String* rhs = other->TryFlattenGetString();
6691
6692 if (StringShape(lhs).IsSequentialAscii() &&
6693 StringShape(rhs).IsSequentialAscii()) {
6694 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
6695 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006696 return CompareRawStringContents(Vector<const char>(str1, len),
6697 Vector<const char>(str2, len));
6698 }
6699
Steve Block44f0eee2011-05-26 01:26:41 +01006700 Isolate* isolate = GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006701 String::FlatContent lhs_content = lhs->GetFlatContent();
6702 String::FlatContent rhs_content = rhs->GetFlatContent();
6703 if (lhs_content.IsFlat()) {
6704 if (lhs_content.IsAscii()) {
6705 Vector<const char> vec1 = lhs_content.ToAsciiVector();
6706 if (rhs_content.IsFlat()) {
6707 if (rhs_content.IsAscii()) {
6708 Vector<const char> vec2 = rhs_content.ToAsciiVector();
Steve Blocka7e24c12009-10-30 11:49:00 +00006709 return CompareRawStringContents(vec1, vec2);
6710 } else {
6711 VectorIterator<char> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006712 VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006713 return CompareStringContents(&buf1, &ib);
6714 }
6715 } else {
6716 VectorIterator<char> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01006717 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6718 return CompareStringContents(&buf1,
6719 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006720 }
6721 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006722 Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
6723 if (rhs_content.IsFlat()) {
6724 if (rhs_content.IsAscii()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006725 VectorIterator<uc16> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006726 VectorIterator<char> ib(rhs_content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006727 return CompareStringContents(&buf1, &ib);
6728 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006729 Vector<const uc16> vec2(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006730 return CompareRawStringContents(vec1, vec2);
6731 }
6732 } else {
6733 VectorIterator<uc16> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01006734 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6735 return CompareStringContents(&buf1,
6736 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006737 }
6738 }
6739 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006740 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
6741 return CompareStringContentsPartial(isolate,
6742 isolate->objects_string_compare_buffer_a(), rhs);
Steve Blocka7e24c12009-10-30 11:49:00 +00006743 }
6744}
6745
6746
6747bool String::MarkAsUndetectable() {
6748 if (StringShape(this).IsSymbol()) return false;
6749
6750 Map* map = this->map();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006751 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01006752 if (map == heap->string_map()) {
6753 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006754 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01006755 } else if (map == heap->ascii_string_map()) {
6756 this->set_map(heap->undetectable_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006757 return true;
6758 }
6759 // Rest cannot be marked as undetectable
6760 return false;
6761}
6762
6763
6764bool String::IsEqualTo(Vector<const char> str) {
Steve Block44f0eee2011-05-26 01:26:41 +01006765 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006766 int slen = length();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006767 Access<UnicodeCache::Utf8Decoder>
6768 decoder(isolate->unicode_cache()->utf8_decoder());
Steve Blocka7e24c12009-10-30 11:49:00 +00006769 decoder->Reset(str.start(), str.length());
6770 int i;
6771 for (i = 0; i < slen && decoder->has_more(); i++) {
6772 uc32 r = decoder->GetNext();
6773 if (Get(i) != r) return false;
6774 }
6775 return i == slen && !decoder->has_more();
6776}
6777
6778
Steve Block9fac8402011-05-12 15:51:54 +01006779bool String::IsAsciiEqualTo(Vector<const char> str) {
6780 int slen = length();
6781 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006782 FlatContent content = GetFlatContent();
6783 if (content.IsAscii()) {
6784 return CompareChars(content.ToAsciiVector().start(),
6785 str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006786 }
6787 for (int i = 0; i < slen; i++) {
6788 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +01006789 }
6790 return true;
6791}
6792
6793
6794bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
6795 int slen = length();
6796 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006797 FlatContent content = GetFlatContent();
6798 if (content.IsTwoByte()) {
6799 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006800 }
Steve Block9fac8402011-05-12 15:51:54 +01006801 for (int i = 0; i < slen; i++) {
6802 if (Get(i) != str[i]) return false;
6803 }
6804 return true;
6805}
6806
6807
Steve Blocka7e24c12009-10-30 11:49:00 +00006808uint32_t String::ComputeAndSetHash() {
6809 // Should only be called if hash code has not yet been computed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006810 ASSERT(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00006811
Steve Block6ded16b2010-05-10 14:33:55 +01006812 const int len = length();
6813
Steve Blocka7e24c12009-10-30 11:49:00 +00006814 // Compute the hash code.
Steve Block6ded16b2010-05-10 14:33:55 +01006815 uint32_t field = 0;
6816 if (StringShape(this).IsSequentialAscii()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006817 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
Steve Block6ded16b2010-05-10 14:33:55 +01006818 } else if (StringShape(this).IsSequentialTwoByte()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006819 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
Steve Block6ded16b2010-05-10 14:33:55 +01006820 } else {
6821 StringInputBuffer buffer(this);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006822 field = ComputeHashField(&buffer, len);
Steve Block6ded16b2010-05-10 14:33:55 +01006823 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006824
6825 // Store the hash code in the object.
Steve Blockd0582a62009-12-15 09:54:21 +00006826 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00006827
6828 // Check the hash code is there.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006829 ASSERT(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00006830 uint32_t result = field >> kHashShift;
6831 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
6832 return result;
6833}
6834
6835
6836bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
6837 uint32_t* index,
6838 int length) {
6839 if (length == 0 || length > kMaxArrayIndexSize) return false;
6840 uc32 ch = buffer->GetNext();
6841
6842 // If the string begins with a '0' character, it must only consist
6843 // of it to be a legal array index.
6844 if (ch == '0') {
6845 *index = 0;
6846 return length == 1;
6847 }
6848
6849 // Convert string to uint32 array index; character by character.
6850 int d = ch - '0';
6851 if (d < 0 || d > 9) return false;
6852 uint32_t result = d;
6853 while (buffer->has_more()) {
6854 d = buffer->GetNext() - '0';
6855 if (d < 0 || d > 9) return false;
6856 // Check that the new result is below the 32 bit limit.
6857 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
6858 result = (result * 10) + d;
6859 }
6860
6861 *index = result;
6862 return true;
6863}
6864
6865
6866bool String::SlowAsArrayIndex(uint32_t* index) {
6867 if (length() <= kMaxCachedArrayIndexLength) {
6868 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00006869 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006870 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00006871 // Isolate the array index form the full hash field.
6872 *index = (kArrayIndexHashMask & field) >> kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00006873 return true;
6874 } else {
6875 StringInputBuffer buffer(this);
6876 return ComputeArrayIndex(&buffer, index, length());
6877 }
6878}
6879
6880
Iain Merrick9ac36c92010-09-13 15:29:50 +01006881uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006882 // For array indexes mix the length into the hash as an array index could
6883 // be zero.
6884 ASSERT(length > 0);
6885 ASSERT(length <= String::kMaxArrayIndexSize);
6886 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
6887 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01006888
6889 value <<= String::kHashShift;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006890 value |= length << String::kArrayIndexHashLengthShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01006891
6892 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
6893 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
6894 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006895 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00006896}
6897
6898
6899uint32_t StringHasher::GetHashField() {
6900 ASSERT(is_valid());
Steve Blockd0582a62009-12-15 09:54:21 +00006901 if (length_ <= String::kMaxHashCalcLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006902 if (is_array_index()) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01006903 return MakeArrayIndexHash(array_index(), length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00006904 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006905 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00006906 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006907 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00006908 }
6909}
6910
6911
Steve Blockd0582a62009-12-15 09:54:21 +00006912uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006913 int length) {
6914 StringHasher hasher(length);
Steve Blocka7e24c12009-10-30 11:49:00 +00006915
6916 // Very long strings have a trivial hash that doesn't inspect the
6917 // string contents.
6918 if (hasher.has_trivial_hash()) {
6919 return hasher.GetHashField();
6920 }
6921
6922 // Do the iterative array index computation as long as there is a
6923 // chance this is an array index.
6924 while (buffer->has_more() && hasher.is_array_index()) {
6925 hasher.AddCharacter(buffer->GetNext());
6926 }
6927
6928 // Process the remaining characters without updating the array
6929 // index.
6930 while (buffer->has_more()) {
6931 hasher.AddCharacterNoIndex(buffer->GetNext());
6932 }
6933
6934 return hasher.GetHashField();
6935}
6936
6937
John Reck59135872010-11-02 12:39:01 -07006938MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01006939 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006940 if (start == 0 && end == length()) return this;
Steve Block44f0eee2011-05-26 01:26:41 +01006941 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
Steve Blockd0582a62009-12-15 09:54:21 +00006942 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00006943}
6944
6945
6946void String::PrintOn(FILE* file) {
6947 int length = this->length();
6948 for (int i = 0; i < length; i++) {
6949 fprintf(file, "%c", Get(i));
6950 }
6951}
6952
6953
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006954void Map::CreateOneBackPointer(Map* target) {
6955#ifdef DEBUG
6956 // Verify target.
6957 Object* source_prototype = prototype();
6958 Object* target_prototype = target->prototype();
6959 ASSERT(source_prototype->IsJSReceiver() ||
6960 source_prototype->IsMap() ||
6961 source_prototype->IsNull());
6962 ASSERT(target_prototype->IsJSReceiver() ||
6963 target_prototype->IsNull());
6964 ASSERT(source_prototype->IsMap() ||
6965 source_prototype == target_prototype);
6966#endif
6967 // Point target back to source. set_prototype() will not let us set
6968 // the prototype to a map, as we do here.
6969 *RawField(target, kPrototypeOffset) = this;
6970}
6971
6972
Steve Blocka7e24c12009-10-30 11:49:00 +00006973void Map::CreateBackPointers() {
6974 DescriptorArray* descriptors = instance_descriptors();
6975 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006976 if (descriptors->IsTransition(i)) {
6977 Object* object = reinterpret_cast<Object*>(descriptors->GetValue(i));
6978 if (object->IsMap()) {
6979 CreateOneBackPointer(reinterpret_cast<Map*>(object));
6980 } else {
6981 ASSERT(object->IsFixedArray());
6982 ASSERT(descriptors->GetType(i) == ELEMENTS_TRANSITION);
6983 FixedArray* array = reinterpret_cast<FixedArray*>(object);
6984 for (int i = 0; i < array->length(); ++i) {
6985 Map* target = reinterpret_cast<Map*>(array->get(i));
6986 if (!target->IsUndefined()) {
6987 CreateOneBackPointer(target);
6988 }
6989 }
6990 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006991 }
6992 }
6993}
6994
6995
Steve Block44f0eee2011-05-26 01:26:41 +01006996void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006997 // Live DescriptorArray objects will be marked, so we must use
6998 // low-level accessors to get and modify their data.
6999 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00007000 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
7001 if (d->IsEmpty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00007002 Smi* NullDescriptorDetails =
7003 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
7004 FixedArray* contents = reinterpret_cast<FixedArray*>(
7005 d->get(DescriptorArray::kContentArrayIndex));
7006 ASSERT(contents->length() >= 2);
7007 for (int i = 0; i < contents->length(); i += 2) {
7008 // If the pair (value, details) is a map transition,
7009 // check if the target is live. If not, null the descriptor.
7010 // Also drop the back pointer for that map transition, so that this
7011 // map is not reached again by following a back pointer from a
7012 // non-live object.
7013 PropertyDetails details(Smi::cast(contents->get(i + 1)));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007014 if (IsTransitionType(details.type())) {
7015 Object* object = reinterpret_cast<Object*>(contents->get(i));
7016 if (object->IsMap()) {
7017 Map* target = reinterpret_cast<Map*>(object);
7018 ASSERT(target->IsHeapObject());
7019 MarkBit map_mark = Marking::MarkBitFrom(target);
7020 if (!map_mark.Get()) {
7021 ASSERT(target->IsMap());
7022 contents->set_unchecked(i + 1, NullDescriptorDetails);
7023 contents->set_null_unchecked(heap, i);
7024 ASSERT(target->prototype() == this ||
7025 target->prototype() == real_prototype);
7026 // Getter prototype() is read-only, set_prototype() has side effects.
7027 *RawField(target, Map::kPrototypeOffset) = real_prototype;
7028 }
7029 } else {
7030 ASSERT(object->IsFixedArray());
7031 ASSERT(details.type() == ELEMENTS_TRANSITION);
7032 FixedArray* array = reinterpret_cast<FixedArray*>(object);
7033 bool reachable_map_found = false;
7034 for (int j = 0; j < array->length(); ++j) {
7035 Map* target = reinterpret_cast<Map*>(array->get(j));
7036 ASSERT(target->IsHeapObject());
7037 MarkBit map_mark = Marking::MarkBitFrom(target);
7038 if (!map_mark.Get()) {
7039 ASSERT(target->IsMap());
7040 array->set_undefined(j);
7041 ASSERT(target->prototype() == this ||
7042 target->prototype() == real_prototype);
7043 // Getter prototype() is read-only, set_prototype() has side
7044 // effects.
7045 *RawField(target, Map::kPrototypeOffset) = real_prototype;
7046 } else if (target->IsMap()) {
7047 reachable_map_found = true;
7048 }
7049 }
7050 // If no map was found, make sure the FixedArray also gets collected.
7051 if (!reachable_map_found) {
7052 contents->set_unchecked(i + 1, NullDescriptorDetails);
7053 contents->set_null_unchecked(heap, i);
7054 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007055 }
7056 }
7057 }
7058}
7059
7060
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007061int Map::Hash() {
7062 // For performance reasons we only hash the 3 most variable fields of a map:
7063 // constructor, prototype and bit_field2.
7064
7065 // Shift away the tag.
7066 int hash = (static_cast<uint32_t>(
7067 reinterpret_cast<uintptr_t>(constructor())) >> 2);
7068
7069 // XOR-ing the prototype and constructor directly yields too many zero bits
7070 // when the two pointers are close (which is fairly common).
7071 // To avoid this we shift the prototype 4 bits relatively to the constructor.
7072 hash ^= (static_cast<uint32_t>(
7073 reinterpret_cast<uintptr_t>(prototype())) << 2);
7074
7075 return hash ^ (hash >> 16) ^ bit_field2();
7076}
7077
7078
7079bool Map::EquivalentToForNormalization(Map* other,
7080 PropertyNormalizationMode mode) {
7081 return
7082 constructor() == other->constructor() &&
7083 prototype() == other->prototype() &&
7084 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
7085 0 :
7086 other->inobject_properties()) &&
7087 instance_type() == other->instance_type() &&
7088 bit_field() == other->bit_field() &&
7089 bit_field2() == other->bit_field2() &&
7090 (bit_field3() & ~(1<<Map::kIsShared)) ==
7091 (other->bit_field3() & ~(1<<Map::kIsShared));
7092}
7093
7094
Steve Block791712a2010-08-27 10:21:07 +01007095void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
7096 // Iterate over all fields in the body but take care in dealing with
7097 // the code entry.
7098 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
7099 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
7100 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
7101}
7102
7103
Ben Murdochb0fe1622011-05-05 13:52:32 +01007104void JSFunction::MarkForLazyRecompilation() {
7105 ASSERT(is_compiled() && !IsOptimized());
Ben Murdochb8e0da22011-05-16 14:20:40 +01007106 ASSERT(shared()->allows_lazy_compilation() ||
7107 code()->optimizable());
Steve Block44f0eee2011-05-26 01:26:41 +01007108 Builtins* builtins = GetIsolate()->builtins();
7109 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007110}
7111
7112
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007113bool SharedFunctionInfo::EnsureCompiled(Handle<SharedFunctionInfo> shared,
7114 ClearExceptionFlag flag) {
7115 return shared->is_compiled() || CompileLazy(shared, flag);
7116}
7117
7118
7119static bool CompileLazyHelper(CompilationInfo* info,
7120 ClearExceptionFlag flag) {
7121 // Compile the source information to a code object.
7122 ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
7123 ASSERT(!info->isolate()->has_pending_exception());
7124 bool result = Compiler::CompileLazy(info);
7125 ASSERT(result != Isolate::Current()->has_pending_exception());
7126 if (!result && flag == CLEAR_EXCEPTION) {
7127 info->isolate()->clear_pending_exception();
7128 }
7129 return result;
7130}
7131
7132
7133bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
7134 ClearExceptionFlag flag) {
7135 CompilationInfo info(shared);
7136 return CompileLazyHelper(&info, flag);
7137}
7138
7139
7140bool JSFunction::CompileLazy(Handle<JSFunction> function,
7141 ClearExceptionFlag flag) {
7142 bool result = true;
7143 if (function->shared()->is_compiled()) {
7144 function->ReplaceCode(function->shared()->code());
7145 function->shared()->set_code_age(0);
7146 } else {
7147 CompilationInfo info(function);
7148 result = CompileLazyHelper(&info, flag);
7149 ASSERT(!result || function->is_compiled());
7150 }
7151 return result;
7152}
7153
7154
7155bool JSFunction::CompileOptimized(Handle<JSFunction> function,
7156 int osr_ast_id,
7157 ClearExceptionFlag flag) {
7158 CompilationInfo info(function);
7159 info.SetOptimizing(osr_ast_id);
7160 return CompileLazyHelper(&info, flag);
7161}
7162
7163
Ben Murdochb0fe1622011-05-05 13:52:32 +01007164bool JSFunction::IsInlineable() {
7165 if (IsBuiltin()) return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007166 SharedFunctionInfo* shared_info = shared();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007167 // Check that the function has a script associated with it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007168 if (!shared_info->script()->IsScript()) return false;
7169 if (shared_info->optimization_disabled()) return false;
7170 Code* code = shared_info->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007171 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
7172 // If we never ran this (unlikely) then lets try to optimize it.
7173 if (code->kind() != Code::FUNCTION) return true;
7174 return code->optimizable();
7175}
7176
7177
Steve Blocka7e24c12009-10-30 11:49:00 +00007178Object* JSFunction::SetInstancePrototype(Object* value) {
7179 ASSERT(value->IsJSObject());
Steve Block44f0eee2011-05-26 01:26:41 +01007180 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007181 if (has_initial_map()) {
7182 initial_map()->set_prototype(value);
7183 } else {
7184 // Put the value in the initial map field until an initial map is
7185 // needed. At that point, a new initial map is created and the
7186 // prototype is put into the initial map where it belongs.
7187 set_prototype_or_initial_map(value);
7188 }
Steve Block44f0eee2011-05-26 01:26:41 +01007189 heap->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00007190 return value;
7191}
7192
7193
John Reck59135872010-11-02 12:39:01 -07007194MaybeObject* JSFunction::SetPrototype(Object* value) {
Steve Block6ded16b2010-05-10 14:33:55 +01007195 ASSERT(should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +00007196 Object* construct_prototype = value;
7197
7198 // If the value is not a JSObject, store the value in the map's
7199 // constructor field so it can be accessed. Also, set the prototype
7200 // used for constructing objects to the original object prototype.
7201 // See ECMA-262 13.2.2.
7202 if (!value->IsJSObject()) {
7203 // Copy the map so this does not affect unrelated functions.
7204 // Remove map transitions because they point to maps with a
7205 // different prototype.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007206 Object* new_object;
John Reck59135872010-11-02 12:39:01 -07007207 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007208 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07007209 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01007210 Map* new_map = Map::cast(new_object);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007211 Heap* heap = new_map->GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007212 set_map(new_map);
7213 new_map->set_constructor(value);
7214 new_map->set_non_instance_prototype(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00007215 construct_prototype =
Steve Block44f0eee2011-05-26 01:26:41 +01007216 heap->isolate()->context()->global_context()->
7217 initial_object_prototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00007218 } else {
7219 map()->set_non_instance_prototype(false);
7220 }
7221
7222 return SetInstancePrototype(construct_prototype);
7223}
7224
7225
Steve Block6ded16b2010-05-10 14:33:55 +01007226Object* JSFunction::RemovePrototype() {
Steve Block44f0eee2011-05-26 01:26:41 +01007227 Context* global_context = context()->global_context();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007228 Map* no_prototype_map = shared()->is_classic_mode()
7229 ? global_context->function_without_prototype_map()
7230 : global_context->strict_mode_function_without_prototype_map();
Steve Block44f0eee2011-05-26 01:26:41 +01007231
7232 if (map() == no_prototype_map) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007233 // Be idempotent.
7234 return this;
7235 }
Steve Block44f0eee2011-05-26 01:26:41 +01007236
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007237 ASSERT(map() == (shared()->is_classic_mode()
7238 ? global_context->function_map()
7239 : global_context->strict_mode_function_map()));
Steve Block44f0eee2011-05-26 01:26:41 +01007240
7241 set_map(no_prototype_map);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007242 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01007243 return this;
7244}
7245
7246
Steve Blocka7e24c12009-10-30 11:49:00 +00007247Object* JSFunction::SetInstanceClassName(String* name) {
7248 shared()->set_instance_class_name(name);
7249 return this;
7250}
7251
7252
Ben Murdochb0fe1622011-05-05 13:52:32 +01007253void JSFunction::PrintName(FILE* out) {
Ben Murdoch589d6972011-11-30 16:04:58 +00007254 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007255 PrintF(out, "%s", *name);
7256}
7257
7258
Steve Blocka7e24c12009-10-30 11:49:00 +00007259Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
7260 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
7261}
7262
7263
Steve Block44f0eee2011-05-26 01:26:41 +01007264MaybeObject* Oddball::Initialize(const char* to_string,
7265 Object* to_number,
7266 byte kind) {
John Reck59135872010-11-02 12:39:01 -07007267 Object* symbol;
Steve Block44f0eee2011-05-26 01:26:41 +01007268 { MaybeObject* maybe_symbol =
7269 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
John Reck59135872010-11-02 12:39:01 -07007270 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
7271 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007272 set_to_string(String::cast(symbol));
7273 set_to_number(to_number);
Steve Block44f0eee2011-05-26 01:26:41 +01007274 set_kind(kind);
Steve Blocka7e24c12009-10-30 11:49:00 +00007275 return this;
7276}
7277
7278
Ben Murdochf87a2032010-10-22 12:50:53 +01007279String* SharedFunctionInfo::DebugName() {
7280 Object* n = name();
7281 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
7282 return String::cast(n);
7283}
7284
7285
Steve Blocka7e24c12009-10-30 11:49:00 +00007286bool SharedFunctionInfo::HasSourceCode() {
7287 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01007288 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00007289}
7290
7291
7292Object* SharedFunctionInfo::GetSourceCode() {
Steve Block44f0eee2011-05-26 01:26:41 +01007293 Isolate* isolate = GetIsolate();
7294 if (!HasSourceCode()) return isolate->heap()->undefined_value();
7295 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007296 Object* source = Script::cast(script())->source();
Steve Block44f0eee2011-05-26 01:26:41 +01007297 return *SubString(Handle<String>(String::cast(source), isolate),
Steve Blocka7e24c12009-10-30 11:49:00 +00007298 start_position(), end_position());
7299}
7300
7301
Ben Murdochb0fe1622011-05-05 13:52:32 +01007302int SharedFunctionInfo::SourceSize() {
7303 return end_position() - start_position();
7304}
7305
7306
Steve Blocka7e24c12009-10-30 11:49:00 +00007307int SharedFunctionInfo::CalculateInstanceSize() {
7308 int instance_size =
7309 JSObject::kHeaderSize +
7310 expected_nof_properties() * kPointerSize;
7311 if (instance_size > JSObject::kMaxInstanceSize) {
7312 instance_size = JSObject::kMaxInstanceSize;
7313 }
7314 return instance_size;
7315}
7316
7317
7318int SharedFunctionInfo::CalculateInObjectProperties() {
7319 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
7320}
7321
7322
Andrei Popescu402d9372010-02-26 13:31:12 +00007323bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
7324 // Check the basic conditions for generating inline constructor code.
7325 if (!FLAG_inline_new
7326 || !has_only_simple_this_property_assignments()
7327 || this_property_assignments_count() == 0) {
7328 return false;
7329 }
7330
7331 // If the prototype is null inline constructors cause no problems.
7332 if (!prototype->IsJSObject()) {
7333 ASSERT(prototype->IsNull());
7334 return true;
7335 }
7336
Ben Murdoch8b112d22011-06-08 16:22:53 +01007337 Heap* heap = GetHeap();
7338
Andrei Popescu402d9372010-02-26 13:31:12 +00007339 // Traverse the proposed prototype chain looking for setters for properties of
7340 // the same names as are set by the inline constructor.
7341 for (Object* obj = prototype;
Steve Block44f0eee2011-05-26 01:26:41 +01007342 obj != heap->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00007343 obj = obj->GetPrototype()) {
7344 JSObject* js_object = JSObject::cast(obj);
7345 for (int i = 0; i < this_property_assignments_count(); i++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007346 LookupResult result(heap->isolate());
Andrei Popescu402d9372010-02-26 13:31:12 +00007347 String* name = GetThisPropertyAssignmentName(i);
7348 js_object->LocalLookupRealNamedProperty(name, &result);
7349 if (result.IsProperty() && result.type() == CALLBACKS) {
7350 return false;
7351 }
7352 }
7353 }
7354
7355 return true;
7356}
7357
7358
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007359void SharedFunctionInfo::ForbidInlineConstructor() {
7360 set_compiler_hints(BooleanBit::set(compiler_hints(),
7361 kHasOnlySimpleThisPropertyAssignments,
7362 false));
7363}
7364
7365
Steve Blocka7e24c12009-10-30 11:49:00 +00007366void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +00007367 bool only_simple_this_property_assignments,
7368 FixedArray* assignments) {
7369 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00007370 kHasOnlySimpleThisPropertyAssignments,
7371 only_simple_this_property_assignments));
7372 set_this_property_assignments(assignments);
7373 set_this_property_assignments_count(assignments->length() / 3);
7374}
7375
7376
7377void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
Steve Block44f0eee2011-05-26 01:26:41 +01007378 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007379 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00007380 kHasOnlySimpleThisPropertyAssignments,
7381 false));
Steve Block44f0eee2011-05-26 01:26:41 +01007382 set_this_property_assignments(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007383 set_this_property_assignments_count(0);
7384}
7385
7386
7387String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
7388 Object* obj = this_property_assignments();
7389 ASSERT(obj->IsFixedArray());
7390 ASSERT(index < this_property_assignments_count());
7391 obj = FixedArray::cast(obj)->get(index * 3);
7392 ASSERT(obj->IsString());
7393 return String::cast(obj);
7394}
7395
7396
7397bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
7398 Object* obj = this_property_assignments();
7399 ASSERT(obj->IsFixedArray());
7400 ASSERT(index < this_property_assignments_count());
7401 obj = FixedArray::cast(obj)->get(index * 3 + 1);
7402 return Smi::cast(obj)->value() != -1;
7403}
7404
7405
7406int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
7407 ASSERT(IsThisPropertyAssignmentArgument(index));
7408 Object* obj =
7409 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
7410 return Smi::cast(obj)->value();
7411}
7412
7413
7414Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
7415 ASSERT(!IsThisPropertyAssignmentArgument(index));
7416 Object* obj =
7417 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
7418 return obj;
7419}
7420
7421
Steve Blocka7e24c12009-10-30 11:49:00 +00007422// Support function for printing the source code to a StringStream
7423// without any allocation in the heap.
7424void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
7425 int max_length) {
7426 // For some native functions there is no source.
Ben Murdochb0fe1622011-05-05 13:52:32 +01007427 if (!HasSourceCode()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007428 accumulator->Add("<No Source>");
7429 return;
7430 }
7431
Steve Blockd0582a62009-12-15 09:54:21 +00007432 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00007433 // Don't use String::cast because we don't want more assertion errors while
7434 // we are already creating a stack dump.
7435 String* script_source =
7436 reinterpret_cast<String*>(Script::cast(script())->source());
7437
7438 if (!script_source->LooksValid()) {
7439 accumulator->Add("<Invalid Source>");
7440 return;
7441 }
7442
7443 if (!is_toplevel()) {
7444 accumulator->Add("function ");
7445 Object* name = this->name();
7446 if (name->IsString() && String::cast(name)->length() > 0) {
7447 accumulator->PrintName(name);
7448 }
7449 }
7450
7451 int len = end_position() - start_position();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007452 if (len <= max_length || max_length < 0) {
7453 accumulator->Put(script_source, start_position(), end_position());
7454 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00007455 accumulator->Put(script_source,
7456 start_position(),
7457 start_position() + max_length);
7458 accumulator->Add("...\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00007459 }
7460}
7461
7462
Ben Murdochb0fe1622011-05-05 13:52:32 +01007463static bool IsCodeEquivalent(Code* code, Code* recompiled) {
7464 if (code->instruction_size() != recompiled->instruction_size()) return false;
7465 ByteArray* code_relocation = code->relocation_info();
7466 ByteArray* recompiled_relocation = recompiled->relocation_info();
7467 int length = code_relocation->length();
7468 if (length != recompiled_relocation->length()) return false;
7469 int compare = memcmp(code_relocation->GetDataStartAddress(),
7470 recompiled_relocation->GetDataStartAddress(),
7471 length);
7472 return compare == 0;
7473}
7474
7475
7476void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
7477 ASSERT(!has_deoptimization_support());
7478 AssertNoAllocation no_allocation;
7479 Code* code = this->code();
7480 if (IsCodeEquivalent(code, recompiled)) {
7481 // Copy the deoptimization data from the recompiled code.
7482 code->set_deoptimization_data(recompiled->deoptimization_data());
7483 code->set_has_deoptimization_support(true);
7484 } else {
7485 // TODO(3025757): In case the recompiled isn't equivalent to the
7486 // old code, we have to replace it. We should try to avoid this
7487 // altogether because it flushes valuable type feedback by
7488 // effectively resetting all IC state.
7489 set_code(recompiled);
7490 }
7491 ASSERT(has_deoptimization_support());
7492}
7493
7494
Ben Murdoch257744e2011-11-30 15:57:28 +00007495void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
7496 // Disable optimization for the shared function info and mark the
7497 // code as non-optimizable. The marker on the shared function info
7498 // is there because we flush non-optimized code thereby loosing the
7499 // non-optimizable information for the code. When the code is
7500 // regenerated and set on the shared function info it is marked as
7501 // non-optimizable if optimization is disabled for the shared
7502 // function info.
7503 set_optimization_disabled(true);
7504 // Code should be the lazy compilation stub or else unoptimized. If the
7505 // latter, disable optimization for the code too.
7506 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
7507 if (code()->kind() == Code::FUNCTION) {
7508 code()->set_optimizable(false);
7509 }
7510 if (FLAG_trace_opt) {
7511 PrintF("[disabled optimization for: ");
7512 function->PrintName();
7513 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
7514 }
7515}
7516
7517
Ben Murdochb0fe1622011-05-05 13:52:32 +01007518bool SharedFunctionInfo::VerifyBailoutId(int id) {
7519 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
7520 // we are always bailing out on ARM.
7521
7522 ASSERT(id != AstNode::kNoNumber);
7523 Code* unoptimized = code();
7524 DeoptimizationOutputData* data =
7525 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
7526 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
7527 USE(ignore);
7528 return true; // Return true if there was no ASSERT.
7529}
7530
7531
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007532void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
7533 ASSERT(!IsInobjectSlackTrackingInProgress());
7534
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007535 if (!FLAG_clever_optimizations) return;
7536
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007537 // Only initiate the tracking the first time.
7538 if (live_objects_may_exist()) return;
7539 set_live_objects_may_exist(true);
7540
7541 // No tracking during the snapshot construction phase.
7542 if (Serializer::enabled()) return;
7543
7544 if (map->unused_property_fields() == 0) return;
7545
7546 // Nonzero counter is a leftover from the previous attempt interrupted
7547 // by GC, keep it.
7548 if (construction_count() == 0) {
7549 set_construction_count(kGenerousAllocationCount);
7550 }
7551 set_initial_map(map);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007552 Builtins* builtins = map->GetHeap()->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01007553 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007554 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01007555 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007556}
7557
7558
7559// Called from GC, hence reinterpret_cast and unchecked accessors.
7560void SharedFunctionInfo::DetachInitialMap() {
7561 Map* map = reinterpret_cast<Map*>(initial_map());
7562
7563 // Make the map remember to restore the link if it survives the GC.
7564 map->set_bit_field2(
7565 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
7566
7567 // Undo state changes made by StartInobjectTracking (except the
7568 // construction_count). This way if the initial map does not survive the GC
7569 // then StartInobjectTracking will be called again the next time the
7570 // constructor is called. The countdown will continue and (possibly after
7571 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007572 Heap* heap = map->GetHeap();
7573 set_initial_map(heap->raw_unchecked_undefined_value());
7574 Builtins* builtins = heap->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01007575 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007576 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01007577 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007578 // It is safe to clear the flag: it will be set again if the map is live.
7579 set_live_objects_may_exist(false);
7580}
7581
7582
7583// Called from GC, hence reinterpret_cast and unchecked accessors.
7584void SharedFunctionInfo::AttachInitialMap(Map* map) {
7585 map->set_bit_field2(
7586 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
7587
7588 // Resume inobject slack tracking.
7589 set_initial_map(map);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007590 Builtins* builtins = map->GetHeap()->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01007591 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007592 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01007593 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007594 // The map survived the gc, so there may be objects referencing it.
7595 set_live_objects_may_exist(true);
7596}
7597
7598
7599static void GetMinInobjectSlack(Map* map, void* data) {
7600 int slack = map->unused_property_fields();
7601 if (*reinterpret_cast<int*>(data) > slack) {
7602 *reinterpret_cast<int*>(data) = slack;
7603 }
7604}
7605
7606
7607static void ShrinkInstanceSize(Map* map, void* data) {
7608 int slack = *reinterpret_cast<int*>(data);
7609 map->set_inobject_properties(map->inobject_properties() - slack);
7610 map->set_unused_property_fields(map->unused_property_fields() - slack);
7611 map->set_instance_size(map->instance_size() - slack * kPointerSize);
7612
7613 // Visitor id might depend on the instance size, recalculate it.
7614 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
7615}
7616
7617
7618void SharedFunctionInfo::CompleteInobjectSlackTracking() {
7619 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
7620 Map* map = Map::cast(initial_map());
7621
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007622 Heap* heap = map->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01007623 set_initial_map(heap->undefined_value());
7624 Builtins* builtins = heap->isolate()->builtins();
7625 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007626 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01007627 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007628
7629 int slack = map->unused_property_fields();
7630 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
7631 if (slack != 0) {
7632 // Resize the initial map and all maps in its transition tree.
7633 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007634
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007635 // Give the correct expected_nof_properties to initial maps created later.
7636 ASSERT(expected_nof_properties() >= slack);
7637 set_expected_nof_properties(expected_nof_properties() - slack);
7638 }
7639}
7640
7641
Steve Blocka7e24c12009-10-30 11:49:00 +00007642void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
7643 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
7644 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
7645 Object* old_target = target;
7646 VisitPointer(&target);
7647 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
7648}
7649
7650
Steve Block791712a2010-08-27 10:21:07 +01007651void ObjectVisitor::VisitCodeEntry(Address entry_address) {
7652 Object* code = Code::GetObjectFromEntryAddress(entry_address);
7653 Object* old_code = code;
7654 VisitPointer(&code);
7655 if (code != old_code) {
7656 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
7657 }
7658}
7659
7660
Ben Murdochb0fe1622011-05-05 13:52:32 +01007661void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
7662 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
7663 Object* cell = rinfo->target_cell();
7664 Object* old_cell = cell;
7665 VisitPointer(&cell);
7666 if (cell != old_cell) {
7667 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
7668 }
7669}
7670
7671
Steve Blocka7e24c12009-10-30 11:49:00 +00007672void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007673 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
7674 rinfo->IsPatchedReturnSequence()) ||
7675 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
7676 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007677 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
7678 Object* old_target = target;
7679 VisitPointer(&target);
7680 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
7681}
7682
7683
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007684void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
7685 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
7686 VisitPointer(rinfo->target_object_address());
7687}
7688
7689void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
7690 Address* p = rinfo->target_reference_address();
7691 VisitExternalReferences(p, p + 1);
7692}
7693
Ben Murdochb0fe1622011-05-05 13:52:32 +01007694void Code::InvalidateRelocation() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007695 set_relocation_info(GetHeap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007696}
7697
7698
Steve Blockd0582a62009-12-15 09:54:21 +00007699void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007700 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
7701 it.rinfo()->apply(delta);
7702 }
7703 CPU::FlushICache(instruction_start(), instruction_size());
7704}
7705
7706
7707void Code::CopyFrom(const CodeDesc& desc) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007708 ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
7709
Steve Blocka7e24c12009-10-30 11:49:00 +00007710 // copy code
7711 memmove(instruction_start(), desc.buffer, desc.instr_size);
7712
Steve Blocka7e24c12009-10-30 11:49:00 +00007713 // copy reloc info
7714 memmove(relocation_start(),
7715 desc.buffer + desc.buffer_size - desc.reloc_size,
7716 desc.reloc_size);
7717
7718 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +00007719 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +00007720 int mode_mask = RelocInfo::kCodeTargetMask |
7721 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb0fe1622011-05-05 13:52:32 +01007722 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
Steve Blocka7e24c12009-10-30 11:49:00 +00007723 RelocInfo::kApplyMask;
Steve Block3ce2e202009-11-05 08:53:23 +00007724 Assembler* origin = desc.origin; // Needed to find target_object on X64.
Steve Blocka7e24c12009-10-30 11:49:00 +00007725 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
7726 RelocInfo::Mode mode = it.rinfo()->rmode();
7727 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +00007728 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007729 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007730 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007731 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
7732 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
Steve Blocka7e24c12009-10-30 11:49:00 +00007733 } else if (RelocInfo::IsCodeTarget(mode)) {
7734 // rewrite code handles in inline cache targets to direct
7735 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +00007736 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00007737 Code* code = Code::cast(*p);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007738 it.rinfo()->set_target_address(code->instruction_start(),
7739 SKIP_WRITE_BARRIER);
Steve Blocka7e24c12009-10-30 11:49:00 +00007740 } else {
7741 it.rinfo()->apply(delta);
7742 }
7743 }
7744 CPU::FlushICache(instruction_start(), instruction_size());
7745}
7746
7747
7748// Locate the source position which is closest to the address in the code. This
7749// is using the source position information embedded in the relocation info.
7750// The position returned is relative to the beginning of the script where the
7751// source for this function is found.
7752int Code::SourcePosition(Address pc) {
7753 int distance = kMaxInt;
7754 int position = RelocInfo::kNoPosition; // Initially no position found.
7755 // Run through all the relocation info to find the best matching source
7756 // position. All the code needs to be considered as the sequence of the
7757 // instructions in the code does not necessarily follow the same order as the
7758 // source.
7759 RelocIterator it(this, RelocInfo::kPositionMask);
7760 while (!it.done()) {
7761 // Only look at positions after the current pc.
7762 if (it.rinfo()->pc() < pc) {
7763 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +00007764
7765 int dist = static_cast<int>(pc - it.rinfo()->pc());
7766 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00007767 // If this position is closer than the current candidate or if it has the
7768 // same distance as the current candidate and the position is higher then
7769 // this position is the new candidate.
7770 if ((dist < distance) ||
7771 (dist == distance && pos > position)) {
7772 position = pos;
7773 distance = dist;
7774 }
7775 }
7776 it.next();
7777 }
7778 return position;
7779}
7780
7781
7782// Same as Code::SourcePosition above except it only looks for statement
7783// positions.
7784int Code::SourceStatementPosition(Address pc) {
7785 // First find the position as close as possible using all position
7786 // information.
7787 int position = SourcePosition(pc);
7788 // Now find the closest statement position before the position.
7789 int statement_position = 0;
7790 RelocIterator it(this, RelocInfo::kPositionMask);
7791 while (!it.done()) {
7792 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +00007793 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00007794 if (statement_position < p && p <= position) {
7795 statement_position = p;
7796 }
7797 }
7798 it.next();
7799 }
7800 return statement_position;
7801}
7802
7803
Ben Murdochb8e0da22011-05-16 14:20:40 +01007804SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007805 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01007806 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007807}
7808
7809
7810void Code::SetNoStackCheckTable() {
7811 // Indicate the absence of a stack-check table by a table start after the
7812 // end of the instructions. Table start must be aligned, so round up.
Steve Block1e0659c2011-05-24 12:43:12 +01007813 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007814}
7815
7816
7817Map* Code::FindFirstMap() {
7818 ASSERT(is_inline_cache_stub());
7819 AssertNoAllocation no_allocation;
7820 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
7821 for (RelocIterator it(this, mask); !it.done(); it.next()) {
7822 RelocInfo* info = it.rinfo();
7823 Object* object = info->target_object();
7824 if (object->IsMap()) return Map::cast(object);
7825 }
7826 return NULL;
7827}
7828
7829
Steve Blocka7e24c12009-10-30 11:49:00 +00007830#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +01007831
Ben Murdochb0fe1622011-05-05 13:52:32 +01007832void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
7833 disasm::NameConverter converter;
7834 int deopt_count = DeoptCount();
7835 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
7836 if (0 == deopt_count) return;
7837
Ben Murdoch2b4ba112012-01-20 14:57:15 +00007838 PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc",
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007839 FLAG_print_code_verbose ? "commands" : "");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007840 for (int i = 0; i < deopt_count; i++) {
Ben Murdoch2b4ba112012-01-20 14:57:15 +00007841 PrintF(out, "%6d %6d %6d %6d",
7842 i,
7843 AstId(i)->value(),
7844 ArgumentsStackHeight(i)->value(),
7845 Pc(i)->value());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007846
7847 if (!FLAG_print_code_verbose) {
7848 PrintF(out, "\n");
7849 continue;
7850 }
7851 // Print details of the frame translation.
Ben Murdochb0fe1622011-05-05 13:52:32 +01007852 int translation_index = TranslationIndex(i)->value();
7853 TranslationIterator iterator(TranslationByteArray(), translation_index);
7854 Translation::Opcode opcode =
7855 static_cast<Translation::Opcode>(iterator.Next());
7856 ASSERT(Translation::BEGIN == opcode);
7857 int frame_count = iterator.Next();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007858 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
7859 frame_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007860
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007861 while (iterator.HasNext() &&
7862 Translation::BEGIN !=
7863 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
7864 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
7865
7866 switch (opcode) {
7867 case Translation::BEGIN:
7868 UNREACHABLE();
7869 break;
7870
7871 case Translation::FRAME: {
7872 int ast_id = iterator.Next();
7873 int function_id = iterator.Next();
7874 JSFunction* function =
7875 JSFunction::cast(LiteralArray()->get(function_id));
7876 unsigned height = iterator.Next();
Ben Murdoch589d6972011-11-30 16:04:58 +00007877 PrintF(out, "{ast_id=%d, function=", ast_id);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007878 function->PrintName(out);
7879 PrintF(out, ", height=%u}", height);
7880 break;
7881 }
7882
7883 case Translation::DUPLICATE:
7884 break;
7885
7886 case Translation::REGISTER: {
7887 int reg_code = iterator.Next();
7888 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7889 break;
7890 }
7891
7892 case Translation::INT32_REGISTER: {
7893 int reg_code = iterator.Next();
7894 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7895 break;
7896 }
7897
7898 case Translation::DOUBLE_REGISTER: {
7899 int reg_code = iterator.Next();
7900 PrintF(out, "{input=%s}",
7901 DoubleRegister::AllocationIndexToString(reg_code));
7902 break;
7903 }
7904
7905 case Translation::STACK_SLOT: {
7906 int input_slot_index = iterator.Next();
7907 PrintF(out, "{input=%d}", input_slot_index);
7908 break;
7909 }
7910
7911 case Translation::INT32_STACK_SLOT: {
7912 int input_slot_index = iterator.Next();
7913 PrintF(out, "{input=%d}", input_slot_index);
7914 break;
7915 }
7916
7917 case Translation::DOUBLE_STACK_SLOT: {
7918 int input_slot_index = iterator.Next();
7919 PrintF(out, "{input=%d}", input_slot_index);
7920 break;
7921 }
7922
7923 case Translation::LITERAL: {
7924 unsigned literal_index = iterator.Next();
7925 PrintF(out, "{literal_id=%u}", literal_index);
7926 break;
7927 }
7928
7929 case Translation::ARGUMENTS_OBJECT:
7930 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01007931 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007932 PrintF(out, "\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007933 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007934 }
7935}
7936
7937
7938void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
7939 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
7940 this->DeoptPoints());
7941 if (this->DeoptPoints() == 0) return;
7942
7943 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
7944 for (int i = 0; i < this->DeoptPoints(); i++) {
7945 int pc_and_state = this->PcAndState(i)->value();
7946 PrintF("%6d %8d %s\n",
7947 this->AstId(i)->value(),
7948 FullCodeGenerator::PcField::decode(pc_and_state),
7949 FullCodeGenerator::State2String(
7950 FullCodeGenerator::StateField::decode(pc_and_state)));
7951 }
7952}
7953
Ben Murdochb0fe1622011-05-05 13:52:32 +01007954
Steve Blocka7e24c12009-10-30 11:49:00 +00007955// Identify kind of code.
7956const char* Code::Kind2String(Kind kind) {
7957 switch (kind) {
7958 case FUNCTION: return "FUNCTION";
Ben Murdochb0fe1622011-05-05 13:52:32 +01007959 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
Steve Blocka7e24c12009-10-30 11:49:00 +00007960 case STUB: return "STUB";
7961 case BUILTIN: return "BUILTIN";
7962 case LOAD_IC: return "LOAD_IC";
7963 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
7964 case STORE_IC: return "STORE_IC";
7965 case KEYED_STORE_IC: return "KEYED_STORE_IC";
7966 case CALL_IC: return "CALL_IC";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007967 case KEYED_CALL_IC: return "KEYED_CALL_IC";
Ben Murdoch257744e2011-11-30 15:57:28 +00007968 case UNARY_OP_IC: return "UNARY_OP_IC";
7969 case BINARY_OP_IC: return "BINARY_OP_IC";
Ben Murdochb0fe1622011-05-05 13:52:32 +01007970 case COMPARE_IC: return "COMPARE_IC";
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007971 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00007972 }
7973 UNREACHABLE();
7974 return NULL;
7975}
7976
7977
7978const char* Code::ICState2String(InlineCacheState state) {
7979 switch (state) {
7980 case UNINITIALIZED: return "UNINITIALIZED";
7981 case PREMONOMORPHIC: return "PREMONOMORPHIC";
7982 case MONOMORPHIC: return "MONOMORPHIC";
7983 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
7984 case MEGAMORPHIC: return "MEGAMORPHIC";
7985 case DEBUG_BREAK: return "DEBUG_BREAK";
7986 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
7987 }
7988 UNREACHABLE();
7989 return NULL;
7990}
7991
7992
7993const char* Code::PropertyType2String(PropertyType type) {
7994 switch (type) {
7995 case NORMAL: return "NORMAL";
7996 case FIELD: return "FIELD";
7997 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
7998 case CALLBACKS: return "CALLBACKS";
Ben Murdoch257744e2011-11-30 15:57:28 +00007999 case HANDLER: return "HANDLER";
Steve Blocka7e24c12009-10-30 11:49:00 +00008000 case INTERCEPTOR: return "INTERCEPTOR";
8001 case MAP_TRANSITION: return "MAP_TRANSITION";
Ben Murdoch589d6972011-11-30 16:04:58 +00008002 case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
Steve Blocka7e24c12009-10-30 11:49:00 +00008003 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
8004 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
8005 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008006 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +00008007 return NULL;
8008}
8009
Ben Murdochb0fe1622011-05-05 13:52:32 +01008010
Steve Block1e0659c2011-05-24 12:43:12 +01008011void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
8012 const char* name = NULL;
8013 switch (kind) {
8014 case CALL_IC:
8015 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
8016 name = "STRING_INDEX_OUT_OF_BOUNDS";
8017 }
8018 break;
8019 case STORE_IC:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008020 case KEYED_STORE_IC:
8021 if (extra == kStrictMode) {
Steve Block1e0659c2011-05-24 12:43:12 +01008022 name = "STRICT";
8023 }
8024 break;
8025 default:
8026 break;
8027 }
8028 if (name != NULL) {
8029 PrintF(out, "extra_ic_state = %s\n", name);
8030 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008031 PrintF(out, "extra_ic_state = %d\n", extra);
Steve Block1e0659c2011-05-24 12:43:12 +01008032 }
8033}
8034
8035
Ben Murdochb0fe1622011-05-05 13:52:32 +01008036void Code::Disassemble(const char* name, FILE* out) {
8037 PrintF(out, "kind = %s\n", Kind2String(kind()));
Steve Blocka7e24c12009-10-30 11:49:00 +00008038 if (is_inline_cache_stub()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008039 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
Steve Block1e0659c2011-05-24 12:43:12 +01008040 PrintExtraICState(out, kind(), extra_ic_state());
Steve Blocka7e24c12009-10-30 11:49:00 +00008041 if (ic_state() == MONOMORPHIC) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008042 PrintF(out, "type = %s\n", PropertyType2String(type()));
Steve Blocka7e24c12009-10-30 11:49:00 +00008043 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008044 if (is_call_stub() || is_keyed_call_stub()) {
8045 PrintF(out, "argc = %d\n", arguments_count());
8046 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008047 }
8048 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008049 PrintF(out, "name = %s\n", name);
8050 }
8051 if (kind() == OPTIMIZED_FUNCTION) {
8052 PrintF(out, "stack_slots = %d\n", stack_slots());
Steve Blocka7e24c12009-10-30 11:49:00 +00008053 }
8054
Ben Murdochb0fe1622011-05-05 13:52:32 +01008055 PrintF(out, "Instructions (size = %d)\n", instruction_size());
8056 Disassembler::Decode(out, this);
8057 PrintF(out, "\n");
8058
Ben Murdochb0fe1622011-05-05 13:52:32 +01008059 if (kind() == FUNCTION) {
8060 DeoptimizationOutputData* data =
8061 DeoptimizationOutputData::cast(this->deoptimization_data());
8062 data->DeoptimizationOutputDataPrint(out);
8063 } else if (kind() == OPTIMIZED_FUNCTION) {
8064 DeoptimizationInputData* data =
8065 DeoptimizationInputData::cast(this->deoptimization_data());
8066 data->DeoptimizationInputDataPrint(out);
8067 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008068 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01008069
8070 if (kind() == OPTIMIZED_FUNCTION) {
8071 SafepointTable table(this);
8072 PrintF(out, "Safepoints (size = %u)\n", table.size());
8073 for (unsigned i = 0; i < table.length(); i++) {
8074 unsigned pc_offset = table.GetPcOffset(i);
8075 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
8076 table.PrintEntry(i);
8077 PrintF(out, " (sp -> fp)");
Ben Murdochb8e0da22011-05-16 14:20:40 +01008078 SafepointEntry entry = table.GetEntry(i);
8079 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
8080 PrintF(out, " %6d", entry.deoptimization_index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008081 } else {
8082 PrintF(out, " <none>");
8083 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01008084 if (entry.argument_count() > 0) {
8085 PrintF(out, " argc: %d", entry.argument_count());
8086 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008087 PrintF(out, "\n");
8088 }
8089 PrintF(out, "\n");
8090 } else if (kind() == FUNCTION) {
Steve Block1e0659c2011-05-24 12:43:12 +01008091 unsigned offset = stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008092 // If there is no stack check table, the "table start" will at or after
8093 // (due to alignment) the end of the instruction stream.
8094 if (static_cast<int>(offset) < instruction_size()) {
8095 unsigned* address =
8096 reinterpret_cast<unsigned*>(instruction_start() + offset);
8097 unsigned length = address[0];
8098 PrintF(out, "Stack checks (size = %u)\n", length);
8099 PrintF(out, "ast_id pc_offset\n");
8100 for (unsigned i = 0; i < length; ++i) {
8101 unsigned index = (2 * i) + 1;
8102 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
8103 }
8104 PrintF(out, "\n");
8105 }
8106 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008107
8108 PrintF("RelocInfo (size = %d)\n", relocation_size());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008109 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
8110 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00008111}
8112#endif // ENABLE_DISASSEMBLER
8113
8114
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008115static void CopyFastElementsToFast(FixedArray* source,
8116 FixedArray* destination,
8117 WriteBarrierMode mode) {
8118 uint32_t count = static_cast<uint32_t>(source->length());
8119 for (uint32_t i = 0; i < count; ++i) {
8120 destination->set(i, source->get(i), mode);
8121 }
8122}
8123
8124
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008125static void CopySlowElementsToFast(NumberDictionary* source,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008126 FixedArray* destination,
8127 WriteBarrierMode mode) {
8128 for (int i = 0; i < source->Capacity(); ++i) {
8129 Object* key = source->KeyAt(i);
8130 if (key->IsNumber()) {
8131 uint32_t entry = static_cast<uint32_t>(key->Number());
8132 destination->set(entry, source->ValueAt(i), mode);
8133 }
8134 }
8135}
8136
8137
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008138MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8139 int capacity,
8140 int length,
8141 SetFastElementsCapacityMode set_capacity_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01008142 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00008143 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01008144 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01008145
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008146 // Allocate a new fast elements backing store.
8147 FixedArray* new_elements = NULL;
8148 { Object* object;
8149 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
8150 if (!maybe->ToObject(&object)) return maybe;
8151 new_elements = FixedArray::cast(object);
8152 }
8153
8154 // Find the new map to use for this object if there is a map change.
8155 Map* new_map = NULL;
8156 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
8157 Object* object;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008158 bool has_fast_smi_only_elements =
8159 (set_capacity_mode == kAllowSmiOnlyElements) &&
8160 (elements()->map()->has_fast_smi_only_elements() ||
8161 elements() == heap->empty_fixed_array());
8162 ElementsKind elements_kind = has_fast_smi_only_elements
8163 ? FAST_SMI_ONLY_ELEMENTS
8164 : FAST_ELEMENTS;
8165 MaybeObject* maybe = GetElementsTransitionMap(elements_kind);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008166 if (!maybe->ToObject(&object)) return maybe;
8167 new_map = Map::cast(object);
8168 }
8169
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008170 FixedArrayBase* old_elements_raw = elements();
8171 ElementsKind elements_kind = GetElementsKind();
8172 switch (elements_kind) {
8173 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008174 case FAST_ELEMENTS: {
8175 AssertNoAllocation no_gc;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008176 WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc));
8177 CopyFastElementsToFast(FixedArray::cast(old_elements_raw),
8178 new_elements, mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008179 set_map(new_map);
8180 set_elements(new_elements);
8181 break;
8182 }
8183 case DICTIONARY_ELEMENTS: {
8184 AssertNoAllocation no_gc;
8185 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008186 CopySlowElementsToFast(NumberDictionary::cast(old_elements_raw),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008187 new_elements,
8188 mode);
8189 set_map(new_map);
8190 set_elements(new_elements);
8191 break;
8192 }
8193 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8194 AssertNoAllocation no_gc;
8195 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
8196 // The object's map and the parameter map are unchanged, the unaliased
8197 // arguments are copied to the new backing store.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008198 FixedArray* parameter_map = FixedArray::cast(old_elements_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008199 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8200 if (arguments->IsDictionary()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008201 CopySlowElementsToFast(NumberDictionary::cast(arguments),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008202 new_elements,
8203 mode);
8204 } else {
8205 CopyFastElementsToFast(arguments, new_elements, mode);
8206 }
8207 parameter_map->set(1, new_elements);
8208 break;
8209 }
8210 case FAST_DOUBLE_ELEMENTS: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008211 FixedDoubleArray* old_elements = FixedDoubleArray::cast(old_elements_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008212 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
8213 // Fill out the new array with this content and array holes.
8214 for (uint32_t i = 0; i < old_length; i++) {
8215 if (!old_elements->is_the_hole(i)) {
8216 Object* obj;
8217 // Objects must be allocated in the old object space, since the
8218 // overall number of HeapNumbers needed for the conversion might
8219 // exceed the capacity of new space, and we would fail repeatedly
8220 // trying to convert the FixedDoubleArray.
8221 MaybeObject* maybe_value_object =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008222 GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
8223 TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008224 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
8225 // Force write barrier. It's not worth trying to exploit
8226 // elems->GetWriteBarrierMode(), since it requires an
8227 // AssertNoAllocation stack object that would have to be positioned
8228 // after the HeapNumber allocation anyway.
8229 new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
8230 }
8231 }
8232 set_map(new_map);
8233 set_elements(new_elements);
8234 break;
8235 }
8236 case EXTERNAL_BYTE_ELEMENTS:
8237 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8238 case EXTERNAL_SHORT_ELEMENTS:
8239 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8240 case EXTERNAL_INT_ELEMENTS:
8241 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8242 case EXTERNAL_FLOAT_ELEMENTS:
8243 case EXTERNAL_DOUBLE_ELEMENTS:
8244 case EXTERNAL_PIXEL_ELEMENTS:
8245 UNREACHABLE();
8246 break;
8247 }
8248
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008249 if (FLAG_trace_elements_transitions) {
8250 PrintElementsTransition(stdout, elements_kind, old_elements_raw,
8251 FAST_ELEMENTS, new_elements);
8252 }
8253
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008254 // Update the length if necessary.
8255 if (IsJSArray()) {
8256 JSArray::cast(this)->set_length(Smi::FromInt(length));
8257 }
8258
8259 return new_elements;
8260}
8261
8262
8263MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
8264 int capacity,
8265 int length) {
8266 Heap* heap = GetHeap();
8267 // We should never end in here with a pixel or external array.
8268 ASSERT(!HasExternalArrayElements());
8269
John Reck59135872010-11-02 12:39:01 -07008270 Object* obj;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008271 { MaybeObject* maybe_obj =
8272 heap->AllocateUninitializedFixedDoubleArray(capacity);
John Reck59135872010-11-02 12:39:01 -07008273 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8274 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008275 FixedDoubleArray* elems = FixedDoubleArray::cast(obj);
Steve Block8defd9f2010-07-08 12:39:36 +01008276
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008277 { MaybeObject* maybe_obj =
8278 GetElementsTransitionMap(FAST_DOUBLE_ELEMENTS);
John Reck59135872010-11-02 12:39:01 -07008279 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8280 }
Steve Block8defd9f2010-07-08 12:39:36 +01008281 Map* new_map = Map::cast(obj);
8282
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008283 FixedArrayBase* old_elements = elements();
8284 ElementsKind elements_kind(GetElementsKind());
Leon Clarke4515c472010-02-03 11:58:03 +00008285 AssertNoAllocation no_gc;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008286 switch (elements_kind) {
8287 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00008288 case FAST_ELEMENTS: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008289 elems->Initialize(FixedArray::cast(old_elements));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008290 break;
8291 }
8292 case FAST_DOUBLE_ELEMENTS: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008293 elems->Initialize(FixedDoubleArray::cast(old_elements));
Steve Blocka7e24c12009-10-30 11:49:00 +00008294 break;
8295 }
8296 case DICTIONARY_ELEMENTS: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008297 elems->Initialize(NumberDictionary::cast(old_elements));
Steve Blocka7e24c12009-10-30 11:49:00 +00008298 break;
8299 }
8300 default:
8301 UNREACHABLE();
8302 break;
8303 }
Steve Block8defd9f2010-07-08 12:39:36 +01008304
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008305 if (FLAG_trace_elements_transitions) {
8306 PrintElementsTransition(stdout, elements_kind, old_elements,
8307 FAST_DOUBLE_ELEMENTS, elems);
8308 }
8309
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008310 ASSERT(new_map->has_fast_double_elements());
Steve Block8defd9f2010-07-08 12:39:36 +01008311 set_map(new_map);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008312 ASSERT(elems->IsFixedDoubleArray());
Steve Blocka7e24c12009-10-30 11:49:00 +00008313 set_elements(elems);
Steve Block8defd9f2010-07-08 12:39:36 +01008314
8315 if (IsJSArray()) {
8316 JSArray::cast(this)->set_length(Smi::FromInt(length));
8317 }
8318
8319 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00008320}
8321
8322
John Reck59135872010-11-02 12:39:01 -07008323MaybeObject* JSArray::Initialize(int capacity) {
Steve Block44f0eee2011-05-26 01:26:41 +01008324 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008325 ASSERT(capacity >= 0);
Leon Clarke4515c472010-02-03 11:58:03 +00008326 set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00008327 FixedArray* new_elements;
8328 if (capacity == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01008329 new_elements = heap->empty_fixed_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00008330 } else {
John Reck59135872010-11-02 12:39:01 -07008331 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01008332 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07008333 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8334 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008335 new_elements = FixedArray::cast(obj);
8336 }
8337 set_elements(new_elements);
8338 return this;
8339}
8340
8341
8342void JSArray::Expand(int required_size) {
8343 Handle<JSArray> self(this);
8344 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
8345 int old_size = old_backing->length();
Steve Blockd0582a62009-12-15 09:54:21 +00008346 int new_size = required_size > old_size ? required_size : old_size;
Steve Block44f0eee2011-05-26 01:26:41 +01008347 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00008348 // Can't use this any more now because we may have had a GC!
8349 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008350 GetIsolate()->factory()->SetContent(self, new_backing);
Steve Blocka7e24c12009-10-30 11:49:00 +00008351}
8352
8353
John Reck59135872010-11-02 12:39:01 -07008354MaybeObject* JSObject::SetElementsLength(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00008355 // We should never end in here with a pixel or external array.
Steve Block6ded16b2010-05-10 14:33:55 +01008356 ASSERT(AllowsSetElementsLength());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008357 return GetElementsAccessor()->SetLength(this, len);
Steve Blocka7e24c12009-10-30 11:49:00 +00008358}
8359
8360
Steve Block053d10c2011-06-13 19:13:29 +01008361Object* Map::GetPrototypeTransition(Object* prototype) {
8362 FixedArray* cache = prototype_transitions();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008363 int number_of_transitions = NumberOfProtoTransitions();
8364 const int proto_offset =
8365 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
8366 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
8367 const int step = kProtoTransitionElementsPerEntry;
8368 for (int i = 0; i < number_of_transitions; i++) {
8369 if (cache->get(proto_offset + i * step) == prototype) {
8370 Object* map = cache->get(map_offset + i * step);
8371 ASSERT(map->IsMap());
8372 return map;
8373 }
Steve Block053d10c2011-06-13 19:13:29 +01008374 }
8375 return NULL;
8376}
8377
8378
8379MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008380 ASSERT(map->IsMap());
8381 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
Steve Block053d10c2011-06-13 19:13:29 +01008382 // Don't cache prototype transition if this map is shared.
8383 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
8384
8385 FixedArray* cache = prototype_transitions();
8386
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008387 const int step = kProtoTransitionElementsPerEntry;
8388 const int header = kProtoTransitionHeaderSize;
Steve Block053d10c2011-06-13 19:13:29 +01008389
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008390 int capacity = (cache->length() - header) / step;
Steve Block053d10c2011-06-13 19:13:29 +01008391
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008392 int transitions = NumberOfProtoTransitions() + 1;
8393
8394 if (transitions > capacity) {
Steve Block053d10c2011-06-13 19:13:29 +01008395 if (capacity > kMaxCachedPrototypeTransitions) return this;
8396
8397 FixedArray* new_cache;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008398 // Grow array by factor 2 over and above what we need.
8399 { MaybeObject* maybe_cache =
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008400 GetHeap()->AllocateFixedArray(transitions * 2 * step + header);
Steve Block053d10c2011-06-13 19:13:29 +01008401 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
8402 }
8403
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008404 for (int i = 0; i < capacity * step; i++) {
8405 new_cache->set(i + header, cache->get(i + header));
8406 }
Steve Block053d10c2011-06-13 19:13:29 +01008407 cache = new_cache;
8408 set_prototype_transitions(cache);
8409 }
8410
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008411 int last = transitions - 1;
8412
8413 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
8414 cache->set(header + last * step + kProtoTransitionMapOffset, map);
8415 SetNumberOfProtoTransitions(transitions);
Steve Block053d10c2011-06-13 19:13:29 +01008416
8417 return cache;
8418}
8419
8420
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008421MaybeObject* JSReceiver::SetPrototype(Object* value,
8422 bool skip_hidden_prototypes) {
8423#ifdef DEBUG
8424 int size = Size();
8425#endif
8426
Steve Block44f0eee2011-05-26 01:26:41 +01008427 Heap* heap = GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +00008428 // Silently ignore the change if value is not a JSObject or null.
8429 // SpiderMonkey behaves this way.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008430 if (!value->IsJSReceiver() && !value->IsNull()) return value;
Andrei Popescu402d9372010-02-26 13:31:12 +00008431
Ben Murdoch8b112d22011-06-08 16:22:53 +01008432 // From 8.6.2 Object Internal Methods
8433 // ...
8434 // In addition, if [[Extensible]] is false the value of the [[Class]] and
8435 // [[Prototype]] internal properties of the object may not be modified.
8436 // ...
8437 // Implementation specific extensions that modify [[Class]], [[Prototype]]
8438 // or [[Extensible]] must not violate the invariants defined in the preceding
8439 // paragraph.
8440 if (!this->map()->is_extensible()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008441 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01008442 Handle<Object> handle(this, heap->isolate());
8443 return heap->isolate()->Throw(
8444 *FACTORY->NewTypeError("non_extensible_proto",
8445 HandleVector<Object>(&handle, 1)));
8446 }
8447
Andrei Popescu402d9372010-02-26 13:31:12 +00008448 // Before we can set the prototype we need to be sure
8449 // prototype cycles are prevented.
8450 // It is sufficient to validate that the receiver is not in the new prototype
8451 // chain.
Steve Block44f0eee2011-05-26 01:26:41 +01008452 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008453 if (JSReceiver::cast(pt) == this) {
Andrei Popescu402d9372010-02-26 13:31:12 +00008454 // Cycle detected.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008455 HandleScope scope(heap->isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01008456 return heap->isolate()->Throw(
8457 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
Andrei Popescu402d9372010-02-26 13:31:12 +00008458 }
8459 }
8460
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008461 JSReceiver* real_receiver = this;
Andrei Popescu402d9372010-02-26 13:31:12 +00008462
8463 if (skip_hidden_prototypes) {
8464 // Find the first object in the chain whose prototype object is not
8465 // hidden and set the new prototype on that object.
8466 Object* current_proto = real_receiver->GetPrototype();
8467 while (current_proto->IsJSObject() &&
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008468 JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) {
8469 real_receiver = JSReceiver::cast(current_proto);
Andrei Popescu402d9372010-02-26 13:31:12 +00008470 current_proto = current_proto->GetPrototype();
8471 }
8472 }
8473
8474 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +01008475 Map* map = real_receiver->map();
8476
8477 // Nothing to do if prototype is already set.
8478 if (map->prototype() == value) return value;
8479
8480 Object* new_map = map->GetPrototypeTransition(value);
8481 if (new_map == NULL) {
8482 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
8483 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
8484 }
8485
8486 { MaybeObject* maybe_new_cache =
8487 map->PutPrototypeTransition(value, Map::cast(new_map));
8488 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
8489 }
8490
8491 Map::cast(new_map)->set_prototype(value);
John Reck59135872010-11-02 12:39:01 -07008492 }
Steve Block053d10c2011-06-13 19:13:29 +01008493 ASSERT(Map::cast(new_map)->prototype() == value);
Andrei Popescu402d9372010-02-26 13:31:12 +00008494 real_receiver->set_map(Map::cast(new_map));
8495
Steve Block44f0eee2011-05-26 01:26:41 +01008496 heap->ClearInstanceofCache();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008497 ASSERT(size == Size());
Andrei Popescu402d9372010-02-26 13:31:12 +00008498 return value;
8499}
8500
8501
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008502MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
8503 uint32_t first_arg,
8504 uint32_t arg_count) {
8505 // Elements in |Arguments| are ordered backwards (because they're on the
8506 // stack), but the method that's called here iterates over them in forward
8507 // direction.
8508 return EnsureCanContainElements(
8509 args->arguments() - first_arg - (arg_count - 1),
8510 arg_count);
8511}
8512
8513
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008514bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008515 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008516 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00008517 case FAST_ELEMENTS: {
8518 uint32_t length = IsJSArray() ?
8519 static_cast<uint32_t>
8520 (Smi::cast(JSArray::cast(this)->length())->value()) :
8521 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8522 if ((index < length) &&
8523 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8524 return true;
8525 }
8526 break;
8527 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008528 case FAST_DOUBLE_ELEMENTS: {
8529 uint32_t length = IsJSArray() ?
8530 static_cast<uint32_t>
8531 (Smi::cast(JSArray::cast(this)->length())->value()) :
8532 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8533 if ((index < length) &&
8534 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
8535 return true;
8536 }
8537 break;
8538 }
Steve Block44f0eee2011-05-26 01:26:41 +01008539 case EXTERNAL_PIXEL_ELEMENTS: {
8540 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008541 if (index < static_cast<uint32_t>(pixels->length())) {
8542 return true;
8543 }
8544 break;
8545 }
Steve Block3ce2e202009-11-05 08:53:23 +00008546 case EXTERNAL_BYTE_ELEMENTS:
8547 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8548 case EXTERNAL_SHORT_ELEMENTS:
8549 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8550 case EXTERNAL_INT_ELEMENTS:
8551 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008552 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008553 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008554 ExternalArray* array = ExternalArray::cast(elements());
8555 if (index < static_cast<uint32_t>(array->length())) {
8556 return true;
8557 }
8558 break;
8559 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008560 case DICTIONARY_ELEMENTS: {
8561 if (element_dictionary()->FindEntry(index)
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008562 != NumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008563 return true;
8564 }
8565 break;
8566 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008567 case NON_STRICT_ARGUMENTS_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00008568 UNREACHABLE();
8569 break;
8570 }
8571
8572 // Handle [] on String objects.
8573 if (this->IsStringObjectWithCharacterAt(index)) return true;
8574
8575 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01008576 if (pt->IsNull()) return false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008577 if (pt->IsJSProxy()) {
8578 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8579 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8580 receiver, index) != ABSENT;
8581 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008582 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8583}
8584
8585
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008586bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01008587 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008588 // Make sure that the top context does not change when doing
8589 // callbacks or interceptor calls.
8590 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008591 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008592 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008593 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00008594 Handle<JSObject> holder_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01008595 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008596 v8::AccessorInfo info(args.end());
8597 if (!interceptor->query()->IsUndefined()) {
8598 v8::IndexedPropertyQuery query =
8599 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01008600 LOG(isolate,
8601 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
Iain Merrick75681382010-08-19 15:07:18 +01008602 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00008603 {
8604 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008605 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008606 result = query(index, info);
8607 }
Iain Merrick75681382010-08-19 15:07:18 +01008608 if (!result.IsEmpty()) {
8609 ASSERT(result->IsInt32());
8610 return true; // absence of property is signaled by empty handle.
8611 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008612 } else if (!interceptor->getter()->IsUndefined()) {
8613 v8::IndexedPropertyGetter getter =
8614 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008615 LOG(isolate,
8616 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
Steve Blocka7e24c12009-10-30 11:49:00 +00008617 v8::Handle<v8::Value> result;
8618 {
8619 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008620 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008621 result = getter(index, info);
8622 }
8623 if (!result.IsEmpty()) return true;
8624 }
8625 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
8626}
8627
8628
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008629JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008630 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008631 if (IsAccessCheckNeeded()) {
8632 Heap* heap = GetHeap();
8633 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8634 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8635 return UNDEFINED_ELEMENT;
8636 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008637 }
8638
Steve Block1e0659c2011-05-24 12:43:12 +01008639 if (IsJSGlobalProxy()) {
8640 Object* proto = GetPrototype();
8641 if (proto->IsNull()) return UNDEFINED_ELEMENT;
8642 ASSERT(proto->IsJSGlobalObject());
8643 return JSObject::cast(proto)->HasLocalElement(index);
8644 }
8645
Steve Blocka7e24c12009-10-30 11:49:00 +00008646 // Check for lookup interceptor
8647 if (HasIndexedInterceptor()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008648 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
8649 : UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00008650 }
8651
8652 // Handle [] on String objects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008653 if (this->IsStringObjectWithCharacterAt(index)) {
8654 return STRING_CHARACTER_ELEMENT;
8655 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008656
8657 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008658 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00008659 case FAST_ELEMENTS: {
8660 uint32_t length = IsJSArray() ?
8661 static_cast<uint32_t>
8662 (Smi::cast(JSArray::cast(this)->length())->value()) :
8663 static_cast<uint32_t>(FixedArray::cast(elements())->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008664 if ((index < length) &&
8665 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8666 return FAST_ELEMENT;
8667 }
8668 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008669 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008670 case FAST_DOUBLE_ELEMENTS: {
8671 uint32_t length = IsJSArray() ?
8672 static_cast<uint32_t>
8673 (Smi::cast(JSArray::cast(this)->length())->value()) :
8674 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8675 if ((index < length) &&
8676 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
8677 return FAST_ELEMENT;
8678 }
8679 break;
8680 }
Steve Block44f0eee2011-05-26 01:26:41 +01008681 case EXTERNAL_PIXEL_ELEMENTS: {
8682 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008683 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
8684 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008685 }
Steve Block3ce2e202009-11-05 08:53:23 +00008686 case EXTERNAL_BYTE_ELEMENTS:
8687 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8688 case EXTERNAL_SHORT_ELEMENTS:
8689 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8690 case EXTERNAL_INT_ELEMENTS:
8691 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008692 case EXTERNAL_FLOAT_ELEMENTS:
8693 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008694 ExternalArray* array = ExternalArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008695 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
8696 break;
Steve Block3ce2e202009-11-05 08:53:23 +00008697 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008698 case DICTIONARY_ELEMENTS: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008699 if (element_dictionary()->FindEntry(index) !=
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008700 NumberDictionary::kNotFound) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008701 return DICTIONARY_ELEMENT;
8702 }
8703 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008704 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008705 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8706 // Aliased parameters and non-aliased elements in a fast backing store
8707 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
8708 // backing store behave as DICTIONARY_ELEMENT.
8709 FixedArray* parameter_map = FixedArray::cast(elements());
8710 uint32_t length = parameter_map->length();
8711 Object* probe =
8712 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
8713 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8714 // If not aliased, check the arguments.
8715 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8716 if (arguments->IsDictionary()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008717 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
8718 if (dictionary->FindEntry(index) != NumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008719 return DICTIONARY_ELEMENT;
8720 }
8721 } else {
8722 length = arguments->length();
8723 probe = (index < length) ? arguments->get(index) : NULL;
8724 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8725 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008726 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008727 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008728 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008729
8730 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00008731}
8732
8733
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008734bool JSObject::HasElementInElements(FixedArray* elements,
8735 ElementsKind kind,
8736 uint32_t index) {
8737 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
8738 if (kind == FAST_ELEMENTS) {
8739 int length = IsJSArray()
8740 ? Smi::cast(JSArray::cast(this)->length())->value()
8741 : elements->length();
8742 if (index < static_cast<uint32_t>(length) &&
8743 !elements->get(index)->IsTheHole()) {
8744 return true;
8745 }
8746 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008747 if (NumberDictionary::cast(elements)->FindEntry(index) !=
8748 NumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008749 return true;
8750 }
8751 }
8752 return false;
8753}
8754
8755
8756bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008757 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008758 if (IsAccessCheckNeeded()) {
8759 Heap* heap = GetHeap();
8760 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8761 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8762 return false;
8763 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008764 }
8765
8766 // Check for lookup interceptor
8767 if (HasIndexedInterceptor()) {
8768 return HasElementWithInterceptor(receiver, index);
8769 }
8770
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008771 ElementsKind kind = GetElementsKind();
8772 switch (kind) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008773 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00008774 case FAST_ELEMENTS: {
8775 uint32_t length = IsJSArray() ?
8776 static_cast<uint32_t>
8777 (Smi::cast(JSArray::cast(this)->length())->value()) :
8778 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8779 if ((index < length) &&
8780 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
8781 break;
8782 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008783 case FAST_DOUBLE_ELEMENTS: {
8784 uint32_t length = IsJSArray() ?
8785 static_cast<uint32_t>
8786 (Smi::cast(JSArray::cast(this)->length())->value()) :
8787 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8788 if ((index < length) &&
8789 !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
8790 break;
8791 }
Steve Block44f0eee2011-05-26 01:26:41 +01008792 case EXTERNAL_PIXEL_ELEMENTS: {
8793 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008794 if (index < static_cast<uint32_t>(pixels->length())) {
8795 return true;
8796 }
8797 break;
8798 }
Steve Block3ce2e202009-11-05 08:53:23 +00008799 case EXTERNAL_BYTE_ELEMENTS:
8800 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8801 case EXTERNAL_SHORT_ELEMENTS:
8802 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8803 case EXTERNAL_INT_ELEMENTS:
8804 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008805 case EXTERNAL_FLOAT_ELEMENTS:
8806 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008807 ExternalArray* array = ExternalArray::cast(elements());
8808 if (index < static_cast<uint32_t>(array->length())) {
8809 return true;
8810 }
8811 break;
8812 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008813 case DICTIONARY_ELEMENTS: {
8814 if (element_dictionary()->FindEntry(index)
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008815 != NumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008816 return true;
8817 }
8818 break;
8819 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008820 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8821 FixedArray* parameter_map = FixedArray::cast(elements());
8822 uint32_t length = parameter_map->length();
8823 Object* probe =
8824 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
8825 if (probe != NULL && !probe->IsTheHole()) return true;
8826
8827 // Not a mapped parameter, check the arguments.
8828 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8829 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
8830 if (HasElementInElements(arguments, kind, index)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00008831 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008832 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008833 }
8834
8835 // Handle [] on String objects.
8836 if (this->IsStringObjectWithCharacterAt(index)) return true;
8837
8838 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01008839 if (pt->IsNull()) return false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008840 if (pt->IsJSProxy()) {
8841 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8842 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8843 receiver, index) != ABSENT;
8844 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008845 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8846}
8847
8848
John Reck59135872010-11-02 12:39:01 -07008849MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01008850 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008851 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008852 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01008853 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008854 // Make sure that the top context does not change when doing
8855 // callbacks or interceptor calls.
8856 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008857 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008858 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8859 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01008860 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008861 if (!interceptor->setter()->IsUndefined()) {
8862 v8::IndexedPropertySetter setter =
8863 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +01008864 LOG(isolate,
8865 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
8866 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008867 v8::AccessorInfo info(args.end());
8868 v8::Handle<v8::Value> result;
8869 {
8870 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008871 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008872 result = setter(index, v8::Utils::ToLocal(value_handle), info);
8873 }
Steve Block44f0eee2011-05-26 01:26:41 +01008874 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008875 if (!result.IsEmpty()) return *value_handle;
8876 }
John Reck59135872010-11-02 12:39:01 -07008877 MaybeObject* raw_result =
Steve Block9fac8402011-05-12 15:51:54 +01008878 this_handle->SetElementWithoutInterceptor(index,
8879 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008880 strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008881 check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01008882 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008883 return raw_result;
8884}
8885
8886
John Reck59135872010-11-02 12:39:01 -07008887MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
8888 Object* structure,
8889 uint32_t index,
8890 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01008891 Isolate* isolate = GetIsolate();
Ben Murdoch257744e2011-11-30 15:57:28 +00008892 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01008893
8894 // api style callbacks.
8895 if (structure->IsAccessorInfo()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00008896 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01008897 Object* fun_obj = data->getter();
8898 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Steve Block44f0eee2011-05-26 01:26:41 +01008899 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008900 Handle<JSObject> self(JSObject::cast(receiver));
8901 Handle<JSObject> holder_handle(JSObject::cast(holder));
Steve Block44f0eee2011-05-26 01:26:41 +01008902 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008903 Handle<String> key = isolate->factory()->NumberToString(number);
Steve Block44f0eee2011-05-26 01:26:41 +01008904 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
8905 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01008906 v8::AccessorInfo info(args.end());
8907 v8::Handle<v8::Value> result;
8908 {
8909 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008910 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01008911 result = call_fun(v8::Utils::ToLocal(key), info);
8912 }
Steve Block44f0eee2011-05-26 01:26:41 +01008913 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8914 if (result.IsEmpty()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008915 return *v8::Utils::OpenHandle(*result);
8916 }
8917
8918 // __defineGetter__ callback
8919 if (structure->IsFixedArray()) {
8920 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008921 if (getter->IsSpecFunction()) {
8922 // TODO(rossberg): nicer would be to cast to some JSCallable here...
8923 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
Leon Clarkef7060e22010-06-03 12:02:55 +01008924 }
8925 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +01008926 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008927 }
8928
8929 UNREACHABLE();
8930 return NULL;
8931}
8932
8933
John Reck59135872010-11-02 12:39:01 -07008934MaybeObject* JSObject::SetElementWithCallback(Object* structure,
8935 uint32_t index,
8936 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008937 JSObject* holder,
8938 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01008939 Isolate* isolate = GetIsolate();
8940 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008941
8942 // We should never get here to initialize a const with the hole
8943 // value since a const declaration would conflict with the setter.
8944 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01008945 Handle<Object> value_handle(value, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008946
8947 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00008948 // data structure used to store the callbacks. Eventually foreign
Leon Clarkef7060e22010-06-03 12:02:55 +01008949 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00008950 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01008951
8952 if (structure->IsAccessorInfo()) {
8953 // api style callbacks
Ben Murdoch257744e2011-11-30 15:57:28 +00008954 Handle<JSObject> self(this);
8955 Handle<JSObject> holder_handle(JSObject::cast(holder));
8956 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01008957 Object* call_obj = data->setter();
8958 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
8959 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +01008960 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8961 Handle<String> key(isolate->factory()->NumberToString(number));
Ben Murdoch257744e2011-11-30 15:57:28 +00008962 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
8963 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01008964 v8::AccessorInfo info(args.end());
8965 {
8966 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008967 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01008968 call_fun(v8::Utils::ToLocal(key),
8969 v8::Utils::ToLocal(value_handle),
8970 info);
8971 }
Steve Block44f0eee2011-05-26 01:26:41 +01008972 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008973 return *value_handle;
8974 }
8975
8976 if (structure->IsFixedArray()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008977 Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008978 if (setter->IsSpecFunction()) {
8979 // TODO(rossberg): nicer would be to cast to some JSCallable here...
8980 return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
Leon Clarkef7060e22010-06-03 12:02:55 +01008981 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008982 if (strict_mode == kNonStrictMode) {
8983 return value;
8984 }
Steve Block44f0eee2011-05-26 01:26:41 +01008985 Handle<Object> holder_handle(holder, isolate);
8986 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Leon Clarkef7060e22010-06-03 12:02:55 +01008987 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01008988 return isolate->Throw(
8989 *isolate->factory()->NewTypeError("no_setter_in_callback",
8990 HandleVector(args, 2)));
Leon Clarkef7060e22010-06-03 12:02:55 +01008991 }
8992 }
8993
8994 UNREACHABLE();
8995 return NULL;
8996}
8997
8998
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008999bool JSObject::HasFastArgumentsElements() {
9000 Heap* heap = GetHeap();
9001 if (!elements()->IsFixedArray()) return false;
9002 FixedArray* elements = FixedArray::cast(this->elements());
9003 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9004 return false;
9005 }
9006 FixedArray* arguments = FixedArray::cast(elements->get(1));
9007 return !arguments->IsDictionary();
9008}
9009
9010
9011bool JSObject::HasDictionaryArgumentsElements() {
9012 Heap* heap = GetHeap();
9013 if (!elements()->IsFixedArray()) return false;
9014 FixedArray* elements = FixedArray::cast(this->elements());
9015 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9016 return false;
9017 }
9018 FixedArray* arguments = FixedArray::cast(elements->get(1));
9019 return arguments->IsDictionary();
9020}
9021
9022
Steve Blocka7e24c12009-10-30 11:49:00 +00009023// Adding n elements in fast case is O(n*n).
9024// Note: revisit design to have dual undefined values to capture absent
9025// elements.
Steve Block9fac8402011-05-12 15:51:54 +01009026MaybeObject* JSObject::SetFastElement(uint32_t index,
9027 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009028 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01009029 bool check_prototype) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009030 ASSERT(HasFastTypeElements() ||
9031 HasFastArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009032
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009033 FixedArray* backing_store = FixedArray::cast(elements());
9034 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
9035 backing_store = FixedArray::cast(backing_store->get(1));
9036 } else {
9037 Object* writable;
9038 MaybeObject* maybe = EnsureWritableFastElements();
9039 if (!maybe->ToObject(&writable)) return maybe;
9040 backing_store = FixedArray::cast(writable);
John Reck59135872010-11-02 12:39:01 -07009041 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009042 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00009043
Steve Block9fac8402011-05-12 15:51:54 +01009044 if (check_prototype &&
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009045 (index >= capacity || backing_store->get(index)->IsTheHole())) {
Steve Block1e0659c2011-05-24 12:43:12 +01009046 bool found;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009047 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9048 value,
9049 &found,
9050 strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +01009051 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00009052 }
9053
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009054 uint32_t new_capacity = capacity;
9055 // Check if the length property of this object needs to be updated.
9056 uint32_t array_length = 0;
9057 bool must_update_array_length = false;
9058 if (IsJSArray()) {
9059 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9060 if (index >= array_length) {
9061 must_update_array_length = true;
9062 array_length = index + 1;
9063 }
9064 }
9065 // Check if the capacity of the backing store needs to be increased, or if
9066 // a transition to slow elements is necessary.
9067 if (index >= capacity) {
9068 bool convert_to_slow = true;
9069 if ((index - capacity) < kMaxGap) {
9070 new_capacity = NewElementsCapacity(index + 1);
9071 ASSERT(new_capacity > index);
9072 if (!ShouldConvertToSlowElements(new_capacity)) {
9073 convert_to_slow = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009074 }
9075 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009076 if (convert_to_slow) {
9077 MaybeObject* result = NormalizeElements();
9078 if (result->IsFailure()) return result;
9079 return SetDictionaryElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009080 }
9081 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009082 // Convert to fast double elements if appropriate.
9083 if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) {
9084 MaybeObject* maybe =
9085 SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
9086 if (maybe->IsFailure()) return maybe;
9087 FixedDoubleArray::cast(elements())->set(index, value->Number());
9088 return value;
9089 }
9090 // Change elements kind from SMI_ONLY to generic FAST if necessary.
9091 if (HasFastSmiOnlyElements() && !value->IsSmi()) {
9092 MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS);
9093 Map* new_map;
9094 if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
9095 set_map(new_map);
9096 if (FLAG_trace_elements_transitions) {
9097 PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
9098 FAST_ELEMENTS, elements());
9099 }
9100 }
9101 // Increase backing store capacity if that's been decided previously.
9102 if (new_capacity != capacity) {
9103 Object* new_elements;
9104 SetFastElementsCapacityMode set_capacity_mode =
9105 value->IsSmi() && HasFastSmiOnlyElements()
9106 ? kAllowSmiOnlyElements
9107 : kDontAllowSmiOnlyElements;
9108 MaybeObject* maybe =
9109 SetFastElementsCapacityAndLength(new_capacity,
9110 array_length,
9111 set_capacity_mode);
9112 if (!maybe->ToObject(&new_elements)) return maybe;
9113 FixedArray::cast(new_elements)->set(index, value);
9114 return value;
9115 }
9116 // Finally, set the new element and length.
9117 ASSERT(elements()->IsFixedArray());
9118 backing_store->set(index, value);
9119 if (must_update_array_length) {
9120 JSArray::cast(this)->set_length(Smi::FromInt(array_length));
9121 }
9122 return value;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009123}
9124
9125
9126MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
9127 Object* value,
9128 StrictModeFlag strict_mode,
9129 bool check_prototype) {
9130 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9131 Isolate* isolate = GetIsolate();
9132 Heap* heap = isolate->heap();
9133
9134 // Insert element in the dictionary.
9135 FixedArray* elements = FixedArray::cast(this->elements());
9136 bool is_arguments =
9137 (elements->map() == heap->non_strict_arguments_elements_map());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009138 NumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009139 if (is_arguments) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009140 dictionary = NumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009141 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009142 dictionary = NumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009143 }
9144
9145 int entry = dictionary->FindEntry(index);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009146 if (entry != NumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009147 Object* element = dictionary->ValueAt(entry);
9148 PropertyDetails details = dictionary->DetailsAt(entry);
9149 if (details.type() == CALLBACKS) {
9150 return SetElementWithCallback(element, index, value, this, strict_mode);
9151 } else {
9152 dictionary->UpdateMaxNumberKey(index);
9153 // If put fails in strict mode, throw an exception.
9154 if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) {
9155 Handle<Object> holder(this);
9156 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9157 Handle<Object> args[2] = { number, holder };
9158 Handle<Object> error =
9159 isolate->factory()->NewTypeError("strict_read_only_property",
9160 HandleVector(args, 2));
9161 return isolate->Throw(*error);
9162 }
9163 }
9164 } else {
9165 // Index not already used. Look for an accessor in the prototype chain.
9166 if (check_prototype) {
9167 bool found;
9168 MaybeObject* result =
9169 SetElementWithCallbackSetterInPrototypes(
9170 index, value, &found, strict_mode);
9171 if (found) return result;
9172 }
9173 // When we set the is_extensible flag to false we always force the
9174 // element into dictionary mode (and force them to stay there).
9175 if (!map()->is_extensible()) {
9176 if (strict_mode == kNonStrictMode) {
9177 return isolate->heap()->undefined_value();
9178 } else {
9179 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9180 Handle<String> name = isolate->factory()->NumberToString(number);
9181 Handle<Object> args[1] = { name };
9182 Handle<Object> error =
9183 isolate->factory()->NewTypeError("object_not_extensible",
9184 HandleVector(args, 1));
9185 return isolate->Throw(*error);
9186 }
9187 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009188 FixedArrayBase* new_dictionary;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009189 MaybeObject* maybe = dictionary->AtNumberPut(index, value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009190 if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009191 if (dictionary != NumberDictionary::cast(new_dictionary)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009192 if (is_arguments) {
9193 elements->set(1, new_dictionary);
9194 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009195 set_elements(new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009196 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009197 dictionary = NumberDictionary::cast(new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009198 }
9199 }
9200
9201 // Update the array length if this JSObject is an array.
9202 if (IsJSArray()) {
9203 MaybeObject* result =
9204 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
9205 if (result->IsFailure()) return result;
9206 }
9207
9208 // Attempt to put this object back in fast case.
9209 if (ShouldConvertToFastElements()) {
9210 uint32_t new_length = 0;
9211 if (IsJSArray()) {
9212 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
9213 } else {
9214 new_length = dictionary->max_number_key() + 1;
9215 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009216 MaybeObject* result = CanConvertToFastDoubleElements()
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009217 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009218 : SetFastElementsCapacityAndLength(new_length,
9219 new_length,
9220 kDontAllowSmiOnlyElements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009221 if (result->IsFailure()) return result;
9222#ifdef DEBUG
9223 if (FLAG_trace_normalization) {
9224 PrintF("Object elements are fast case again:\n");
9225 Print();
9226 }
9227#endif
9228 }
9229 return value;
9230}
9231
9232
9233MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
9234 uint32_t index,
9235 Object* value,
9236 StrictModeFlag strict_mode,
9237 bool check_prototype) {
9238 ASSERT(HasFastDoubleElements());
9239
9240 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
9241 uint32_t elms_length = static_cast<uint32_t>(elms->length());
9242
9243 // If storing to an element that isn't in the array, pass the store request
9244 // up the prototype chain before storing in the receiver's elements.
9245 if (check_prototype &&
9246 (index >= elms_length || elms->is_the_hole(index))) {
9247 bool found;
9248 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9249 value,
9250 &found,
9251 strict_mode);
9252 if (found) return result;
9253 }
9254
9255 // If the value object is not a heap number, switch to fast elements and try
9256 // again.
9257 bool value_is_smi = value->IsSmi();
9258 if (!value->IsNumber()) {
9259 Object* obj;
9260 uint32_t length = elms_length;
9261 if (IsJSArray()) {
9262 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9263 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009264 MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
9265 elms_length,
9266 length,
9267 kDontAllowSmiOnlyElements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009268 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009269 return SetFastElement(index,
9270 value,
9271 strict_mode,
9272 check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009273 }
9274
9275 double double_value = value_is_smi
9276 ? static_cast<double>(Smi::cast(value)->value())
9277 : HeapNumber::cast(value)->value();
9278
9279 // Check whether there is extra space in the fixed array.
Steve Blocka7e24c12009-10-30 11:49:00 +00009280 if (index < elms_length) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009281 elms->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009282 if (IsJSArray()) {
9283 // Update the length of the array if needed.
9284 uint32_t array_length = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009285 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00009286 if (index >= array_length) {
Leon Clarke4515c472010-02-03 11:58:03 +00009287 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00009288 }
9289 }
9290 return value;
9291 }
9292
9293 // Allow gap in fast case.
9294 if ((index - elms_length) < kMaxGap) {
9295 // Try allocating extra space.
9296 int new_capacity = NewElementsCapacity(index+1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009297 if (!ShouldConvertToSlowElements(new_capacity)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009298 ASSERT(static_cast<uint32_t>(new_capacity) > index);
John Reck59135872010-11-02 12:39:01 -07009299 Object* obj;
9300 { MaybeObject* maybe_obj =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009301 SetFastDoubleElementsCapacityAndLength(new_capacity,
9302 index + 1);
John Reck59135872010-11-02 12:39:01 -07009303 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9304 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009305 FixedDoubleArray::cast(elements())->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009306 return value;
9307 }
9308 }
9309
9310 // Otherwise default to slow case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009311 ASSERT(HasFastDoubleElements());
9312 ASSERT(map()->has_fast_double_elements());
9313 ASSERT(elements()->IsFixedDoubleArray());
John Reck59135872010-11-02 12:39:01 -07009314 Object* obj;
9315 { MaybeObject* maybe_obj = NormalizeElements();
9316 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9317 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009318 ASSERT(HasDictionaryElements());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009319 return SetElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009320}
9321
Iain Merrick75681382010-08-19 15:07:18 +01009322
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009323MaybeObject* JSReceiver::SetElement(uint32_t index,
9324 Object* value,
9325 StrictModeFlag strict_mode,
9326 bool check_proto) {
9327 return IsJSProxy()
9328 ? JSProxy::cast(this)->SetElementWithHandler(index, value, strict_mode)
9329 : JSObject::cast(this)->SetElement(index, value, strict_mode, check_proto)
9330 ;
9331}
9332
9333
Steve Block9fac8402011-05-12 15:51:54 +01009334MaybeObject* JSObject::SetElement(uint32_t index,
9335 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009336 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01009337 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009338 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009339 if (IsAccessCheckNeeded()) {
9340 Heap* heap = GetHeap();
9341 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009342 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01009343 Handle<Object> value_handle(value);
9344 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
9345 return *value_handle;
9346 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009347 }
9348
9349 if (IsJSGlobalProxy()) {
9350 Object* proto = GetPrototype();
9351 if (proto->IsNull()) return value;
9352 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009353 return JSObject::cast(proto)->SetElement(index,
9354 value,
9355 strict_mode,
9356 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009357 }
9358
9359 // Check for lookup interceptor
9360 if (HasIndexedInterceptor()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009361 return SetElementWithInterceptor(index,
9362 value,
9363 strict_mode,
9364 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009365 }
9366
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009367 return SetElementWithoutInterceptor(index,
9368 value,
9369 strict_mode,
9370 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009371}
9372
9373
John Reck59135872010-11-02 12:39:01 -07009374MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01009375 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009376 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01009377 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01009378 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00009379 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009380 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00009381 case FAST_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009382 return SetFastElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009383 case FAST_DOUBLE_ELEMENTS:
9384 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01009385 case EXTERNAL_PIXEL_ELEMENTS: {
9386 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009387 return pixels->SetValue(index, value);
9388 }
Steve Block3ce2e202009-11-05 08:53:23 +00009389 case EXTERNAL_BYTE_ELEMENTS: {
9390 ExternalByteArray* array = ExternalByteArray::cast(elements());
9391 return array->SetValue(index, value);
9392 }
9393 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9394 ExternalUnsignedByteArray* array =
9395 ExternalUnsignedByteArray::cast(elements());
9396 return array->SetValue(index, value);
9397 }
9398 case EXTERNAL_SHORT_ELEMENTS: {
9399 ExternalShortArray* array = ExternalShortArray::cast(elements());
9400 return array->SetValue(index, value);
9401 }
9402 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9403 ExternalUnsignedShortArray* array =
9404 ExternalUnsignedShortArray::cast(elements());
9405 return array->SetValue(index, value);
9406 }
9407 case EXTERNAL_INT_ELEMENTS: {
9408 ExternalIntArray* array = ExternalIntArray::cast(elements());
9409 return array->SetValue(index, value);
9410 }
9411 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9412 ExternalUnsignedIntArray* array =
9413 ExternalUnsignedIntArray::cast(elements());
9414 return array->SetValue(index, value);
9415 }
9416 case EXTERNAL_FLOAT_ELEMENTS: {
9417 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
9418 return array->SetValue(index, value);
9419 }
Ben Murdoch257744e2011-11-30 15:57:28 +00009420 case EXTERNAL_DOUBLE_ELEMENTS: {
9421 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
9422 return array->SetValue(index, value);
9423 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009424 case DICTIONARY_ELEMENTS:
9425 return SetDictionaryElement(index, value, strict_mode, check_prototype);
9426 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9427 FixedArray* parameter_map = FixedArray::cast(elements());
9428 uint32_t length = parameter_map->length();
9429 Object* probe =
9430 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
9431 if (probe != NULL && !probe->IsTheHole()) {
9432 Context* context = Context::cast(parameter_map->get(0));
9433 int context_index = Smi::cast(probe)->value();
9434 ASSERT(!context->get(context_index)->IsTheHole());
9435 context->set(context_index, value);
9436 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00009437 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009438 // Object is not mapped, defer to the arguments.
9439 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9440 if (arguments->IsDictionary()) {
9441 return SetDictionaryElement(index, value, strict_mode,
9442 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009443 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009444 return SetFastElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009445 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009446 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009447 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009448 }
9449 // All possible cases have been handled above. Add a return to avoid the
9450 // complaints from the compiler.
9451 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01009452 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009453}
9454
9455
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009456MUST_USE_RESULT MaybeObject* JSObject::TransitionElementsKind(
9457 ElementsKind to_kind) {
9458 ElementsKind from_kind = map()->elements_kind();
9459 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9460 uint32_t capacity = static_cast<uint32_t>(elms->length());
9461 uint32_t length = capacity;
9462 if (IsJSArray()) {
9463 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9464 }
9465 if (from_kind == FAST_SMI_ONLY_ELEMENTS) {
9466 if (to_kind == FAST_DOUBLE_ELEMENTS) {
9467 MaybeObject* maybe_result =
9468 SetFastDoubleElementsCapacityAndLength(capacity, length);
9469 if (maybe_result->IsFailure()) return maybe_result;
9470 return this;
9471 } else if (to_kind == FAST_ELEMENTS) {
9472 MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS);
9473 Map* new_map;
9474 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9475 if (FLAG_trace_elements_transitions) {
9476 PrintElementsTransition(stdout, from_kind, elms, FAST_ELEMENTS, elms);
9477 }
9478 set_map(new_map);
9479 return this;
9480 }
9481 } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
9482 MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
9483 capacity, length, kDontAllowSmiOnlyElements);
9484 if (maybe_result->IsFailure()) return maybe_result;
9485 return this;
9486 }
9487 // This method should never be called for any other case than the ones
9488 // handled above.
9489 UNREACHABLE();
9490 return GetIsolate()->heap()->null_value();
9491}
9492
9493
9494// static
9495bool Map::IsValidElementsTransition(ElementsKind from_kind,
9496 ElementsKind to_kind) {
9497 return
9498 (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9499 (to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) ||
9500 (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS);
9501}
9502
9503
John Reck59135872010-11-02 12:39:01 -07009504MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
9505 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009506 uint32_t old_len = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009507 CHECK(length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +00009508 // Check to see if we need to update the length. For now, we make
9509 // sure that the length stays within 32-bits (unsigned).
9510 if (index >= old_len && index != 0xffffffff) {
John Reck59135872010-11-02 12:39:01 -07009511 Object* len;
9512 { MaybeObject* maybe_len =
Steve Block44f0eee2011-05-26 01:26:41 +01009513 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
John Reck59135872010-11-02 12:39:01 -07009514 if (!maybe_len->ToObject(&len)) return maybe_len;
9515 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009516 set_length(len);
9517 }
9518 return value;
9519}
9520
9521
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009522MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07009523 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01009524 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00009525 // Make sure that the top context does not change when doing
9526 // callbacks or interceptor calls.
9527 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01009528 HandleScope scope(isolate);
9529 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
9530 Handle<Object> this_handle(receiver, isolate);
9531 Handle<JSObject> holder_handle(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009532 if (!interceptor->getter()->IsUndefined()) {
9533 v8::IndexedPropertyGetter getter =
9534 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01009535 LOG(isolate,
9536 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
9537 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00009538 v8::AccessorInfo info(args.end());
9539 v8::Handle<v8::Value> result;
9540 {
9541 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01009542 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009543 result = getter(index, info);
9544 }
Steve Block44f0eee2011-05-26 01:26:41 +01009545 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009546 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
9547 }
9548
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009549 Heap* heap = holder_handle->GetHeap();
9550 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
9551 MaybeObject* raw_result = handler->Get(holder_handle->elements(),
9552 index,
9553 *holder_handle,
9554 *this_handle);
9555 if (raw_result != heap->the_hole_value()) return raw_result;
9556
Steve Block44f0eee2011-05-26 01:26:41 +01009557 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009558
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009559 Object* pt = holder_handle->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01009560 if (pt == heap->null_value()) return heap->undefined_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009561 return pt->GetElementWithReceiver(*this_handle, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00009562}
9563
9564
9565bool JSObject::HasDenseElements() {
9566 int capacity = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009567 int used = 0;
9568 GetElementsCapacityAndUsage(&capacity, &used);
9569 return (capacity == 0) || (used > (capacity / 2));
9570}
9571
9572
9573void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
9574 *capacity = 0;
9575 *used = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00009576
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009577 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
9578 FixedArray* backing_store = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00009579 switch (GetElementsKind()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009580 case NON_STRICT_ARGUMENTS_ELEMENTS:
9581 backing_store_base =
9582 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
9583 backing_store = FixedArray::cast(backing_store_base);
9584 if (backing_store->IsDictionary()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009585 NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009586 *capacity = dictionary->Capacity();
9587 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009588 break;
9589 }
9590 // Fall through.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009591 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009592 case FAST_ELEMENTS:
9593 backing_store = FixedArray::cast(backing_store_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009594 *capacity = backing_store->length();
9595 for (int i = 0; i < *capacity; ++i) {
9596 if (!backing_store->get(i)->IsTheHole()) ++(*used);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009597 }
9598 break;
9599 case DICTIONARY_ELEMENTS: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009600 NumberDictionary* dictionary =
9601 NumberDictionary::cast(FixedArray::cast(elements()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009602 *capacity = dictionary->Capacity();
9603 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009604 break;
9605 }
9606 case FAST_DOUBLE_ELEMENTS: {
9607 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009608 *capacity = elms->length();
9609 for (int i = 0; i < *capacity; i++) {
9610 if (!elms->is_the_hole(i)) ++(*used);
Steve Blocka7e24c12009-10-30 11:49:00 +00009611 }
9612 break;
9613 }
Steve Block3ce2e202009-11-05 08:53:23 +00009614 case EXTERNAL_BYTE_ELEMENTS:
9615 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9616 case EXTERNAL_SHORT_ELEMENTS:
9617 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9618 case EXTERNAL_INT_ELEMENTS:
9619 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009620 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009621 case EXTERNAL_DOUBLE_ELEMENTS:
9622 case EXTERNAL_PIXEL_ELEMENTS:
9623 // External arrays are considered 100% used.
9624 ExternalArray* external_array = ExternalArray::cast(elements());
9625 *capacity = external_array->length();
9626 *used = external_array->length();
9627 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00009628 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009629}
9630
9631
9632bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009633 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
9634 kMaxUncheckedFastElementsLength);
9635 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
9636 (new_capacity <= kMaxUncheckedFastElementsLength &&
9637 GetHeap()->InNewSpace(this))) {
9638 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009639 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009640 // If the fast-case backing storage takes up roughly three times as
9641 // much space (in machine words) as a dictionary backing storage
9642 // would, the object should have slow elements.
9643 int old_capacity = 0;
9644 int used_elements = 0;
9645 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009646 int dictionary_size = NumberDictionary::ComputeCapacity(used_elements) *
9647 NumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009648 return 3 * dictionary_size <= new_capacity;
Steve Blocka7e24c12009-10-30 11:49:00 +00009649}
9650
9651
9652bool JSObject::ShouldConvertToFastElements() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009653 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009654 // If the elements are sparse, we should not go back to fast case.
9655 if (!HasDenseElements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00009656 // An object requiring access checks is never allowed to have fast
9657 // elements. If it had fast elements we would skip security checks.
9658 if (IsAccessCheckNeeded()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009659
9660 FixedArray* elements = FixedArray::cast(this->elements());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009661 NumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009662 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009663 dictionary = NumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009664 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009665 dictionary = NumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009666 }
9667 // If an element has been added at a very high index in the elements
9668 // dictionary, we cannot go back to fast case.
9669 if (dictionary->requires_slow_elements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00009670 // If the dictionary backing storage takes up roughly half as much
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009671 // space (in machine words) as a fast-case backing storage would,
9672 // the object should have fast elements.
9673 uint32_t array_size = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00009674 if (IsJSArray()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009675 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
Steve Blocka7e24c12009-10-30 11:49:00 +00009676 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009677 array_size = dictionary->max_number_key();
Steve Blocka7e24c12009-10-30 11:49:00 +00009678 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009679 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009680 NumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009681 return 2 * dictionary_size >= array_size;
Steve Blocka7e24c12009-10-30 11:49:00 +00009682}
9683
9684
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009685bool JSObject::CanConvertToFastDoubleElements() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009686 if (FLAG_unbox_double_arrays) {
9687 ASSERT(HasDictionaryElements());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009688 NumberDictionary* dictionary = NumberDictionary::cast(elements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009689 for (int i = 0; i < dictionary->Capacity(); i++) {
9690 Object* key = dictionary->KeyAt(i);
9691 if (key->IsNumber()) {
9692 if (!dictionary->ValueAt(i)->IsNumber()) return false;
9693 }
9694 }
9695 return true;
9696 } else {
9697 return false;
9698 }
9699}
9700
9701
Steve Blocka7e24c12009-10-30 11:49:00 +00009702// Certain compilers request function template instantiation when they
9703// see the definition of the other template functions in the
9704// class. This requires us to have the template functions put
9705// together, so even though this function belongs in objects-debug.cc,
9706// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +01009707#ifdef OBJECT_PRINT
Steve Blocka7e24c12009-10-30 11:49:00 +00009708template<typename Shape, typename Key>
Ben Murdochb0fe1622011-05-05 13:52:32 +01009709void Dictionary<Shape, Key>::Print(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009710 int capacity = HashTable<Shape, Key>::Capacity();
9711 for (int i = 0; i < capacity; i++) {
9712 Object* k = HashTable<Shape, Key>::KeyAt(i);
9713 if (HashTable<Shape, Key>::IsKey(k)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01009714 PrintF(out, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00009715 if (k->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01009716 String::cast(k)->StringPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00009717 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01009718 k->ShortPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00009719 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01009720 PrintF(out, ": ");
9721 ValueAt(i)->ShortPrint(out);
9722 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00009723 }
9724 }
9725}
9726#endif
9727
9728
9729template<typename Shape, typename Key>
9730void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
9731 int pos = 0;
9732 int capacity = HashTable<Shape, Key>::Capacity();
Leon Clarke4515c472010-02-03 11:58:03 +00009733 AssertNoAllocation no_gc;
9734 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00009735 for (int i = 0; i < capacity; i++) {
9736 Object* k = Dictionary<Shape, Key>::KeyAt(i);
9737 if (Dictionary<Shape, Key>::IsKey(k)) {
9738 elements->set(pos++, ValueAt(i), mode);
9739 }
9740 }
9741 ASSERT(pos == elements->length());
9742}
9743
9744
9745InterceptorInfo* JSObject::GetNamedInterceptor() {
9746 ASSERT(map()->has_named_interceptor());
9747 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01009748 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00009749 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01009750 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00009751 return InterceptorInfo::cast(result);
9752}
9753
9754
9755InterceptorInfo* JSObject::GetIndexedInterceptor() {
9756 ASSERT(map()->has_indexed_interceptor());
9757 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01009758 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00009759 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01009760 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00009761 return InterceptorInfo::cast(result);
9762}
9763
9764
John Reck59135872010-11-02 12:39:01 -07009765MaybeObject* JSObject::GetPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009766 JSReceiver* receiver,
John Reck59135872010-11-02 12:39:01 -07009767 String* name,
9768 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009769 // Check local property in holder, ignore interceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009770 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00009771 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009772 if (result.IsProperty()) {
9773 return GetProperty(receiver, &result, name, attributes);
9774 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009775 // Continue searching via the prototype chain.
9776 Object* pt = GetPrototype();
9777 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +01009778 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009779 return pt->GetPropertyWithReceiver(receiver, name, attributes);
9780}
9781
9782
John Reck59135872010-11-02 12:39:01 -07009783MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009784 JSReceiver* receiver,
Steve Blockd0582a62009-12-15 09:54:21 +00009785 String* name,
9786 PropertyAttributes* attributes) {
9787 // Check local property in holder, ignore interceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009788 LookupResult result(GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +00009789 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009790 if (result.IsProperty()) {
9791 return GetProperty(receiver, &result, name, attributes);
9792 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01009793 return GetHeap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00009794}
9795
9796
John Reck59135872010-11-02 12:39:01 -07009797MaybeObject* JSObject::GetPropertyWithInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009798 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00009799 String* name,
9800 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01009801 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00009802 InterceptorInfo* interceptor = GetNamedInterceptor();
Steve Block44f0eee2011-05-26 01:26:41 +01009803 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009804 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00009805 Handle<JSObject> holder_handle(this);
9806 Handle<String> name_handle(name);
9807
9808 if (!interceptor->getter()->IsUndefined()) {
9809 v8::NamedPropertyGetter getter =
9810 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01009811 LOG(isolate,
9812 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
9813 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00009814 v8::AccessorInfo info(args.end());
9815 v8::Handle<v8::Value> result;
9816 {
9817 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01009818 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009819 result = getter(v8::Utils::ToLocal(name_handle), info);
9820 }
Steve Block44f0eee2011-05-26 01:26:41 +01009821 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009822 if (!result.IsEmpty()) {
9823 *attributes = NONE;
9824 return *v8::Utils::OpenHandle(*result);
9825 }
9826 }
9827
John Reck59135872010-11-02 12:39:01 -07009828 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00009829 *receiver_handle,
9830 *name_handle,
9831 attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01009832 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009833 return result;
9834}
9835
9836
9837bool JSObject::HasRealNamedProperty(String* key) {
9838 // Check access rights if needed.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009839 Isolate* isolate = GetIsolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +01009840 if (IsAccessCheckNeeded()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009841 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9842 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009843 return false;
9844 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009845 }
9846
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009847 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009848 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009849 return result.IsProperty() && (result.type() != INTERCEPTOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00009850}
9851
9852
9853bool JSObject::HasRealElementProperty(uint32_t index) {
9854 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009855 if (IsAccessCheckNeeded()) {
9856 Heap* heap = GetHeap();
9857 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
9858 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9859 return false;
9860 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009861 }
9862
9863 // Handle [] on String objects.
9864 if (this->IsStringObjectWithCharacterAt(index)) return true;
9865
9866 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009867 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00009868 case FAST_ELEMENTS: {
9869 uint32_t length = IsJSArray() ?
9870 static_cast<uint32_t>(
9871 Smi::cast(JSArray::cast(this)->length())->value()) :
9872 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9873 return (index < length) &&
9874 !FixedArray::cast(elements())->get(index)->IsTheHole();
9875 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009876 case FAST_DOUBLE_ELEMENTS: {
9877 uint32_t length = IsJSArray() ?
9878 static_cast<uint32_t>(
9879 Smi::cast(JSArray::cast(this)->length())->value()) :
9880 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
9881 return (index < length) &&
9882 !FixedDoubleArray::cast(elements())->is_the_hole(index);
9883 break;
9884 }
Steve Block44f0eee2011-05-26 01:26:41 +01009885 case EXTERNAL_PIXEL_ELEMENTS: {
9886 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009887 return index < static_cast<uint32_t>(pixels->length());
9888 }
Steve Block3ce2e202009-11-05 08:53:23 +00009889 case EXTERNAL_BYTE_ELEMENTS:
9890 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9891 case EXTERNAL_SHORT_ELEMENTS:
9892 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9893 case EXTERNAL_INT_ELEMENTS:
9894 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009895 case EXTERNAL_FLOAT_ELEMENTS:
9896 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00009897 ExternalArray* array = ExternalArray::cast(elements());
9898 return index < static_cast<uint32_t>(array->length());
9899 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009900 case DICTIONARY_ELEMENTS: {
9901 return element_dictionary()->FindEntry(index)
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009902 != NumberDictionary::kNotFound;
Steve Blocka7e24c12009-10-30 11:49:00 +00009903 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009904 case NON_STRICT_ARGUMENTS_ELEMENTS:
9905 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00009906 break;
9907 }
9908 // All possibilities have been handled above already.
9909 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01009910 return GetHeap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009911}
9912
9913
9914bool JSObject::HasRealNamedCallbackProperty(String* key) {
9915 // Check access rights if needed.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009916 Isolate* isolate = GetIsolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +01009917 if (IsAccessCheckNeeded()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009918 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9919 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009920 return false;
9921 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009922 }
9923
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009924 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009925 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009926 return result.IsProperty() && (result.type() == CALLBACKS);
Steve Blocka7e24c12009-10-30 11:49:00 +00009927}
9928
9929
9930int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
9931 if (HasFastProperties()) {
9932 DescriptorArray* descs = map()->instance_descriptors();
9933 int result = 0;
9934 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009935 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009936 if (details.IsProperty() && (details.attributes() & filter) == 0) {
9937 result++;
9938 }
9939 }
9940 return result;
9941 } else {
9942 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
9943 }
9944}
9945
9946
9947int JSObject::NumberOfEnumProperties() {
9948 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
9949}
9950
9951
9952void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
9953 Object* temp = get(i);
9954 set(i, get(j));
9955 set(j, temp);
9956 if (this != numbers) {
9957 temp = numbers->get(i);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009958 numbers->set(i, Smi::cast(numbers->get(j)));
9959 numbers->set(j, Smi::cast(temp));
Steve Blocka7e24c12009-10-30 11:49:00 +00009960 }
9961}
9962
9963
9964static void InsertionSortPairs(FixedArray* content,
9965 FixedArray* numbers,
9966 int len) {
9967 for (int i = 1; i < len; i++) {
9968 int j = i;
9969 while (j > 0 &&
9970 (NumberToUint32(numbers->get(j - 1)) >
9971 NumberToUint32(numbers->get(j)))) {
9972 content->SwapPairs(numbers, j - 1, j);
9973 j--;
9974 }
9975 }
9976}
9977
9978
9979void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
9980 // In-place heap sort.
9981 ASSERT(content->length() == numbers->length());
9982
9983 // Bottom-up max-heap construction.
9984 for (int i = 1; i < len; ++i) {
9985 int child_index = i;
9986 while (child_index > 0) {
9987 int parent_index = ((child_index + 1) >> 1) - 1;
9988 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
9989 uint32_t child_value = NumberToUint32(numbers->get(child_index));
9990 if (parent_value < child_value) {
9991 content->SwapPairs(numbers, parent_index, child_index);
9992 } else {
9993 break;
9994 }
9995 child_index = parent_index;
9996 }
9997 }
9998
9999 // Extract elements and create sorted array.
10000 for (int i = len - 1; i > 0; --i) {
10001 // Put max element at the back of the array.
10002 content->SwapPairs(numbers, 0, i);
10003 // Sift down the new top element.
10004 int parent_index = 0;
10005 while (true) {
10006 int child_index = ((parent_index + 1) << 1) - 1;
10007 if (child_index >= i) break;
10008 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
10009 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
10010 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10011 if (child_index + 1 >= i || child1_value > child2_value) {
10012 if (parent_value > child1_value) break;
10013 content->SwapPairs(numbers, parent_index, child_index);
10014 parent_index = child_index;
10015 } else {
10016 if (parent_value > child2_value) break;
10017 content->SwapPairs(numbers, parent_index, child_index + 1);
10018 parent_index = child_index + 1;
10019 }
10020 }
10021 }
10022}
10023
10024
10025// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
10026void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
10027 ASSERT(this->length() == numbers->length());
10028 // For small arrays, simply use insertion sort.
10029 if (len <= 10) {
10030 InsertionSortPairs(this, numbers, len);
10031 return;
10032 }
10033 // Check the range of indices.
10034 uint32_t min_index = NumberToUint32(numbers->get(0));
10035 uint32_t max_index = min_index;
10036 uint32_t i;
10037 for (i = 1; i < len; i++) {
10038 if (NumberToUint32(numbers->get(i)) < min_index) {
10039 min_index = NumberToUint32(numbers->get(i));
10040 } else if (NumberToUint32(numbers->get(i)) > max_index) {
10041 max_index = NumberToUint32(numbers->get(i));
10042 }
10043 }
10044 if (max_index - min_index + 1 == len) {
10045 // Indices form a contiguous range, unless there are duplicates.
10046 // Do an in-place linear time sort assuming distinct numbers, but
10047 // avoid hanging in case they are not.
10048 for (i = 0; i < len; i++) {
10049 uint32_t p;
10050 uint32_t j = 0;
10051 // While the current element at i is not at its correct position p,
10052 // swap the elements at these two positions.
10053 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
10054 j++ < len) {
10055 SwapPairs(numbers, i, p);
10056 }
10057 }
10058 } else {
10059 HeapSortPairs(this, numbers, len);
10060 return;
10061 }
10062}
10063
10064
10065// Fill in the names of local properties into the supplied storage. The main
10066// purpose of this function is to provide reflection information for the object
10067// mirrors.
10068void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
10069 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
10070 if (HasFastProperties()) {
10071 DescriptorArray* descs = map()->instance_descriptors();
10072 for (int i = 0; i < descs->number_of_descriptors(); i++) {
10073 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
10074 }
10075 ASSERT(storage->length() >= index);
10076 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010077 property_dictionary()->CopyKeysTo(storage,
10078 index,
10079 StringDictionary::UNSORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000010080 }
10081}
10082
10083
10084int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
10085 return GetLocalElementKeys(NULL, filter);
10086}
10087
10088
10089int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +000010090 // Fast case for objects with no elements.
10091 if (!IsJSValue() && HasFastElements()) {
10092 uint32_t length = IsJSArray() ?
10093 static_cast<uint32_t>(
10094 Smi::cast(JSArray::cast(this)->length())->value()) :
10095 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10096 if (length == 0) return 0;
10097 }
10098 // Compute the number of enumerable elements.
Steve Blocka7e24c12009-10-30 11:49:00 +000010099 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
10100}
10101
10102
10103int JSObject::GetLocalElementKeys(FixedArray* storage,
10104 PropertyAttributes filter) {
10105 int counter = 0;
10106 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010107 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +000010108 case FAST_ELEMENTS: {
10109 int length = IsJSArray() ?
10110 Smi::cast(JSArray::cast(this)->length())->value() :
10111 FixedArray::cast(elements())->length();
10112 for (int i = 0; i < length; i++) {
10113 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
10114 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000010115 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010116 }
10117 counter++;
10118 }
10119 }
10120 ASSERT(!storage || storage->length() >= counter);
10121 break;
10122 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010123 case FAST_DOUBLE_ELEMENTS: {
10124 int length = IsJSArray() ?
10125 Smi::cast(JSArray::cast(this)->length())->value() :
10126 FixedDoubleArray::cast(elements())->length();
10127 for (int i = 0; i < length; i++) {
10128 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
10129 if (storage != NULL) {
10130 storage->set(counter, Smi::FromInt(i));
10131 }
10132 counter++;
10133 }
10134 }
10135 ASSERT(!storage || storage->length() >= counter);
10136 break;
10137 }
Steve Block44f0eee2011-05-26 01:26:41 +010010138 case EXTERNAL_PIXEL_ELEMENTS: {
10139 int length = ExternalPixelArray::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000010140 while (counter < length) {
10141 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000010142 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +000010143 }
10144 counter++;
10145 }
10146 ASSERT(!storage || storage->length() >= counter);
10147 break;
10148 }
Steve Block3ce2e202009-11-05 08:53:23 +000010149 case EXTERNAL_BYTE_ELEMENTS:
10150 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10151 case EXTERNAL_SHORT_ELEMENTS:
10152 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10153 case EXTERNAL_INT_ELEMENTS:
10154 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +000010155 case EXTERNAL_FLOAT_ELEMENTS:
10156 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +000010157 int length = ExternalArray::cast(elements())->length();
10158 while (counter < length) {
10159 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000010160 storage->set(counter, Smi::FromInt(counter));
Steve Block3ce2e202009-11-05 08:53:23 +000010161 }
10162 counter++;
10163 }
10164 ASSERT(!storage || storage->length() >= counter);
10165 break;
10166 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010167 case DICTIONARY_ELEMENTS: {
10168 if (storage != NULL) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010169 element_dictionary()->CopyKeysTo(storage,
10170 filter,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010171 NumberDictionary::SORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000010172 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010173 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000010174 break;
10175 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010176 case NON_STRICT_ARGUMENTS_ELEMENTS: {
10177 FixedArray* parameter_map = FixedArray::cast(elements());
10178 int mapped_length = parameter_map->length() - 2;
10179 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
10180 if (arguments->IsDictionary()) {
10181 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
10182 // will insert in storage starting at index 0.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010183 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010184 if (storage != NULL) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010185 dictionary->CopyKeysTo(storage, filter, NumberDictionary::UNSORTED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010186 }
10187 counter += dictionary->NumberOfElementsFilterAttributes(filter);
10188 for (int i = 0; i < mapped_length; ++i) {
10189 if (!parameter_map->get(i + 2)->IsTheHole()) {
10190 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10191 ++counter;
10192 }
10193 }
10194 if (storage != NULL) storage->SortPairs(storage, counter);
10195
10196 } else {
10197 int backing_length = arguments->length();
10198 int i = 0;
10199 for (; i < mapped_length; ++i) {
10200 if (!parameter_map->get(i + 2)->IsTheHole()) {
10201 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10202 ++counter;
10203 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
10204 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10205 ++counter;
10206 }
10207 }
10208 for (; i < backing_length; ++i) {
10209 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10210 ++counter;
10211 }
10212 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010213 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010214 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010215 }
10216
10217 if (this->IsJSValue()) {
10218 Object* val = JSValue::cast(this)->value();
10219 if (val->IsString()) {
10220 String* str = String::cast(val);
10221 if (storage) {
10222 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000010223 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010224 }
10225 }
10226 counter += str->length();
10227 }
10228 }
10229 ASSERT(!storage || storage->length() == counter);
10230 return counter;
10231}
10232
10233
10234int JSObject::GetEnumElementKeys(FixedArray* storage) {
10235 return GetLocalElementKeys(storage,
10236 static_cast<PropertyAttributes>(DONT_ENUM));
10237}
10238
10239
Steve Blocka7e24c12009-10-30 11:49:00 +000010240// StringKey simply carries a string object as key.
10241class StringKey : public HashTableKey {
10242 public:
10243 explicit StringKey(String* string) :
10244 string_(string),
10245 hash_(HashForObject(string)) { }
10246
10247 bool IsMatch(Object* string) {
10248 // We know that all entries in a hash table had their hash keys created.
10249 // Use that knowledge to have fast failure.
10250 if (hash_ != HashForObject(string)) {
10251 return false;
10252 }
10253 return string_->Equals(String::cast(string));
10254 }
10255
10256 uint32_t Hash() { return hash_; }
10257
10258 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
10259
10260 Object* AsObject() { return string_; }
10261
10262 String* string_;
10263 uint32_t hash_;
10264};
10265
10266
10267// StringSharedKeys are used as keys in the eval cache.
10268class StringSharedKey : public HashTableKey {
10269 public:
Steve Block1e0659c2011-05-24 12:43:12 +010010270 StringSharedKey(String* source,
10271 SharedFunctionInfo* shared,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010272 LanguageMode language_mode,
10273 int scope_position)
Steve Block1e0659c2011-05-24 12:43:12 +010010274 : source_(source),
10275 shared_(shared),
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010276 language_mode_(language_mode),
10277 scope_position_(scope_position) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000010278
10279 bool IsMatch(Object* other) {
10280 if (!other->IsFixedArray()) return false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010281 FixedArray* other_array = FixedArray::cast(other);
10282 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
Steve Blocka7e24c12009-10-30 11:49:00 +000010283 if (shared != shared_) return false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010284 int language_unchecked = Smi::cast(other_array->get(2))->value();
10285 ASSERT(language_unchecked == CLASSIC_MODE ||
10286 language_unchecked == STRICT_MODE ||
10287 language_unchecked == EXTENDED_MODE);
10288 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10289 if (language_mode != language_mode_) return false;
10290 int scope_position = Smi::cast(other_array->get(3))->value();
10291 if (scope_position != scope_position_) return false;
10292 String* source = String::cast(other_array->get(1));
Steve Blocka7e24c12009-10-30 11:49:00 +000010293 return source->Equals(source_);
10294 }
10295
10296 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +010010297 SharedFunctionInfo* shared,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010298 LanguageMode language_mode,
10299 int scope_position) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010300 uint32_t hash = source->Hash();
10301 if (shared->HasSourceCode()) {
10302 // Instead of using the SharedFunctionInfo pointer in the hash
10303 // code computation, we use a combination of the hash of the
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010304 // script source code and the start position of the calling scope.
10305 // We do this to ensure that the cache entries can survive garbage
Steve Blocka7e24c12009-10-30 11:49:00 +000010306 // collection.
10307 Script* script = Script::cast(shared->script());
10308 hash ^= String::cast(script->source())->Hash();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010309 if (language_mode == STRICT_MODE) hash ^= 0x8000;
10310 if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
10311 hash += scope_position;
Steve Blocka7e24c12009-10-30 11:49:00 +000010312 }
10313 return hash;
10314 }
10315
10316 uint32_t Hash() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010317 return StringSharedHashHelper(
10318 source_, shared_, language_mode_, scope_position_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010319 }
10320
10321 uint32_t HashForObject(Object* obj) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010322 FixedArray* other_array = FixedArray::cast(obj);
10323 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10324 String* source = String::cast(other_array->get(1));
10325 int language_unchecked = Smi::cast(other_array->get(2))->value();
10326 ASSERT(language_unchecked == CLASSIC_MODE ||
10327 language_unchecked == STRICT_MODE ||
10328 language_unchecked == EXTENDED_MODE);
10329 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10330 int scope_position = Smi::cast(other_array->get(3))->value();
10331 return StringSharedHashHelper(
10332 source, shared, language_mode, scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000010333 }
10334
John Reck59135872010-11-02 12:39:01 -070010335 MUST_USE_RESULT MaybeObject* AsObject() {
10336 Object* obj;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010337 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(4);
John Reck59135872010-11-02 12:39:01 -070010338 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10339 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010340 FixedArray* other_array = FixedArray::cast(obj);
10341 other_array->set(0, shared_);
10342 other_array->set(1, source_);
10343 other_array->set(2, Smi::FromInt(language_mode_));
10344 other_array->set(3, Smi::FromInt(scope_position_));
10345 return other_array;
Steve Blocka7e24c12009-10-30 11:49:00 +000010346 }
10347
10348 private:
10349 String* source_;
10350 SharedFunctionInfo* shared_;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010351 LanguageMode language_mode_;
10352 int scope_position_;
Steve Blocka7e24c12009-10-30 11:49:00 +000010353};
10354
10355
10356// RegExpKey carries the source and flags of a regular expression as key.
10357class RegExpKey : public HashTableKey {
10358 public:
10359 RegExpKey(String* string, JSRegExp::Flags flags)
10360 : string_(string),
10361 flags_(Smi::FromInt(flags.value())) { }
10362
Steve Block3ce2e202009-11-05 08:53:23 +000010363 // Rather than storing the key in the hash table, a pointer to the
10364 // stored value is stored where the key should be. IsMatch then
10365 // compares the search key to the found object, rather than comparing
10366 // a key to a key.
Steve Blocka7e24c12009-10-30 11:49:00 +000010367 bool IsMatch(Object* obj) {
10368 FixedArray* val = FixedArray::cast(obj);
10369 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
10370 && (flags_ == val->get(JSRegExp::kFlagsIndex));
10371 }
10372
10373 uint32_t Hash() { return RegExpHash(string_, flags_); }
10374
10375 Object* AsObject() {
10376 // Plain hash maps, which is where regexp keys are used, don't
10377 // use this function.
10378 UNREACHABLE();
10379 return NULL;
10380 }
10381
10382 uint32_t HashForObject(Object* obj) {
10383 FixedArray* val = FixedArray::cast(obj);
10384 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
10385 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
10386 }
10387
10388 static uint32_t RegExpHash(String* string, Smi* flags) {
10389 return string->Hash() + flags->value();
10390 }
10391
10392 String* string_;
10393 Smi* flags_;
10394};
10395
10396// Utf8SymbolKey carries a vector of chars as key.
10397class Utf8SymbolKey : public HashTableKey {
10398 public:
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010399 explicit Utf8SymbolKey(Vector<const char> string)
10400 : string_(string), hash_field_(0) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000010401
10402 bool IsMatch(Object* string) {
10403 return String::cast(string)->IsEqualTo(string_);
10404 }
10405
10406 uint32_t Hash() {
Steve Blockd0582a62009-12-15 09:54:21 +000010407 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +000010408 unibrow::Utf8InputBuffer<> buffer(string_.start(),
10409 static_cast<unsigned>(string_.length()));
10410 chars_ = buffer.Length();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010411 hash_field_ = String::ComputeHashField(&buffer, chars_);
Steve Blockd0582a62009-12-15 09:54:21 +000010412 uint32_t result = hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +000010413 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10414 return result;
10415 }
10416
10417 uint32_t HashForObject(Object* other) {
10418 return String::cast(other)->Hash();
10419 }
10420
John Reck59135872010-11-02 12:39:01 -070010421 MaybeObject* AsObject() {
Steve Blockd0582a62009-12-15 09:54:21 +000010422 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +010010423 return Isolate::Current()->heap()->AllocateSymbol(
10424 string_, chars_, hash_field_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010425 }
10426
10427 Vector<const char> string_;
Steve Blockd0582a62009-12-15 09:54:21 +000010428 uint32_t hash_field_;
Steve Blocka7e24c12009-10-30 11:49:00 +000010429 int chars_; // Caches the number of characters when computing the hash code.
10430};
10431
10432
Steve Block9fac8402011-05-12 15:51:54 +010010433template <typename Char>
10434class SequentialSymbolKey : public HashTableKey {
10435 public:
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010436 explicit SequentialSymbolKey(Vector<const Char> string)
10437 : string_(string), hash_field_(0) { }
Steve Block9fac8402011-05-12 15:51:54 +010010438
10439 uint32_t Hash() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010440 StringHasher hasher(string_.length());
Steve Block9fac8402011-05-12 15:51:54 +010010441
10442 // Very long strings have a trivial hash that doesn't inspect the
10443 // string contents.
10444 if (hasher.has_trivial_hash()) {
10445 hash_field_ = hasher.GetHashField();
10446 } else {
10447 int i = 0;
10448 // Do the iterative array index computation as long as there is a
10449 // chance this is an array index.
10450 while (i < string_.length() && hasher.is_array_index()) {
10451 hasher.AddCharacter(static_cast<uc32>(string_[i]));
10452 i++;
10453 }
10454
10455 // Process the remaining characters without updating the array
10456 // index.
10457 while (i < string_.length()) {
10458 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
10459 i++;
10460 }
10461 hash_field_ = hasher.GetHashField();
10462 }
10463
10464 uint32_t result = hash_field_ >> String::kHashShift;
10465 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10466 return result;
10467 }
10468
10469
10470 uint32_t HashForObject(Object* other) {
10471 return String::cast(other)->Hash();
10472 }
10473
10474 Vector<const Char> string_;
10475 uint32_t hash_field_;
10476};
10477
10478
10479
10480class AsciiSymbolKey : public SequentialSymbolKey<char> {
10481 public:
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010482 explicit AsciiSymbolKey(Vector<const char> str)
10483 : SequentialSymbolKey<char>(str) { }
Steve Block9fac8402011-05-12 15:51:54 +010010484
10485 bool IsMatch(Object* string) {
10486 return String::cast(string)->IsAsciiEqualTo(string_);
10487 }
10488
10489 MaybeObject* AsObject() {
10490 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +010010491 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +010010492 }
10493};
10494
10495
Ben Murdoch257744e2011-11-30 15:57:28 +000010496class SubStringAsciiSymbolKey : public HashTableKey {
10497 public:
10498 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
10499 int from,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010500 int length)
10501 : string_(string), from_(from), length_(length) { }
Ben Murdoch257744e2011-11-30 15:57:28 +000010502
10503 uint32_t Hash() {
10504 ASSERT(length_ >= 0);
10505 ASSERT(from_ + length_ <= string_->length());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010506 StringHasher hasher(length_);
Ben Murdoch257744e2011-11-30 15:57:28 +000010507
10508 // Very long strings have a trivial hash that doesn't inspect the
10509 // string contents.
10510 if (hasher.has_trivial_hash()) {
10511 hash_field_ = hasher.GetHashField();
10512 } else {
10513 int i = 0;
10514 // Do the iterative array index computation as long as there is a
10515 // chance this is an array index.
10516 while (i < length_ && hasher.is_array_index()) {
10517 hasher.AddCharacter(static_cast<uc32>(
10518 string_->SeqAsciiStringGet(i + from_)));
10519 i++;
10520 }
10521
10522 // Process the remaining characters without updating the array
10523 // index.
10524 while (i < length_) {
10525 hasher.AddCharacterNoIndex(static_cast<uc32>(
10526 string_->SeqAsciiStringGet(i + from_)));
10527 i++;
10528 }
10529 hash_field_ = hasher.GetHashField();
10530 }
10531
10532 uint32_t result = hash_field_ >> String::kHashShift;
10533 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10534 return result;
10535 }
10536
10537
10538 uint32_t HashForObject(Object* other) {
10539 return String::cast(other)->Hash();
10540 }
10541
10542 bool IsMatch(Object* string) {
10543 Vector<const char> chars(string_->GetChars() + from_, length_);
10544 return String::cast(string)->IsAsciiEqualTo(chars);
10545 }
10546
10547 MaybeObject* AsObject() {
10548 if (hash_field_ == 0) Hash();
10549 Vector<const char> chars(string_->GetChars() + from_, length_);
10550 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
10551 }
10552
10553 private:
10554 Handle<SeqAsciiString> string_;
10555 int from_;
10556 int length_;
10557 uint32_t hash_field_;
10558};
10559
10560
Steve Block9fac8402011-05-12 15:51:54 +010010561class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
10562 public:
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010563 explicit TwoByteSymbolKey(Vector<const uc16> str)
10564 : SequentialSymbolKey<uc16>(str) { }
Steve Block9fac8402011-05-12 15:51:54 +010010565
10566 bool IsMatch(Object* string) {
10567 return String::cast(string)->IsTwoByteEqualTo(string_);
10568 }
10569
10570 MaybeObject* AsObject() {
10571 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +010010572 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +010010573 }
10574};
10575
10576
Steve Blocka7e24c12009-10-30 11:49:00 +000010577// SymbolKey carries a string/symbol object as key.
10578class SymbolKey : public HashTableKey {
10579 public:
Steve Block44f0eee2011-05-26 01:26:41 +010010580 explicit SymbolKey(String* string)
10581 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000010582
10583 bool IsMatch(Object* string) {
10584 return String::cast(string)->Equals(string_);
10585 }
10586
10587 uint32_t Hash() { return string_->Hash(); }
10588
10589 uint32_t HashForObject(Object* other) {
10590 return String::cast(other)->Hash();
10591 }
10592
John Reck59135872010-11-02 12:39:01 -070010593 MaybeObject* AsObject() {
Leon Clarkef7060e22010-06-03 12:02:55 +010010594 // Attempt to flatten the string, so that symbols will most often
10595 // be flat strings.
10596 string_ = string_->TryFlattenGetString();
Steve Block44f0eee2011-05-26 01:26:41 +010010597 Heap* heap = string_->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010598 // Transform string to symbol if possible.
Steve Block44f0eee2011-05-26 01:26:41 +010010599 Map* map = heap->SymbolMapForString(string_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010600 if (map != NULL) {
10601 string_->set_map(map);
10602 ASSERT(string_->IsSymbol());
10603 return string_;
10604 }
10605 // Otherwise allocate a new symbol.
10606 StringInputBuffer buffer(string_);
Steve Block44f0eee2011-05-26 01:26:41 +010010607 return heap->AllocateInternalSymbol(&buffer,
Steve Blocka7e24c12009-10-30 11:49:00 +000010608 string_->length(),
Steve Blockd0582a62009-12-15 09:54:21 +000010609 string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +000010610 }
10611
10612 static uint32_t StringHash(Object* obj) {
10613 return String::cast(obj)->Hash();
10614 }
10615
10616 String* string_;
10617};
10618
10619
10620template<typename Shape, typename Key>
10621void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
10622 IteratePointers(v, 0, kElementsStartOffset);
10623}
10624
10625
10626template<typename Shape, typename Key>
10627void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
10628 IteratePointers(v,
10629 kElementsStartOffset,
10630 kHeaderSize + length() * kPointerSize);
10631}
10632
10633
10634template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010635MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
10636 PretenureFlag pretenure) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010637 int capacity = ComputeCapacity(at_least_space_for);
10638 if (capacity > HashTable::kMaxCapacity) {
Leon Clarkee46be812010-01-19 14:06:41 +000010639 return Failure::OutOfMemoryException();
10640 }
10641
John Reck59135872010-11-02 12:39:01 -070010642 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +010010643 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
10644 AllocateHashTable(EntryToIndex(capacity), pretenure);
John Reck59135872010-11-02 12:39:01 -070010645 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000010646 }
John Reck59135872010-11-02 12:39:01 -070010647 HashTable::cast(obj)->SetNumberOfElements(0);
10648 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
10649 HashTable::cast(obj)->SetCapacity(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000010650 return obj;
10651}
10652
10653
Leon Clarkee46be812010-01-19 14:06:41 +000010654// Find entry for key otherwise return kNotFound.
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010655int StringDictionary::FindEntry(String* key) {
10656 if (!key->IsSymbol()) {
10657 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
10658 }
10659
10660 // Optimized for symbol key. Knowledge of the key type allows:
10661 // 1. Move the check if the key is a symbol out of the loop.
10662 // 2. Avoid comparing hash codes in symbol to symbol comparision.
10663 // 3. Detect a case when a dictionary key is not a symbol but the key is.
10664 // In case of positive result the dictionary key may be replaced by
10665 // the symbol with minimal performance penalty. It gives a chance to
10666 // perform further lookups in code stubs (and significant performance boost
10667 // a certain style of code).
10668
10669 // EnsureCapacity will guarantee the hash table is never full.
10670 uint32_t capacity = Capacity();
10671 uint32_t entry = FirstProbe(key->Hash(), capacity);
10672 uint32_t count = 1;
10673
10674 while (true) {
10675 int index = EntryToIndex(entry);
10676 Object* element = get(index);
10677 if (element->IsUndefined()) break; // Empty entry.
10678 if (key == element) return entry;
10679 if (!element->IsSymbol() &&
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010680 !element->IsTheHole() &&
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010681 String::cast(element)->Equals(key)) {
10682 // Replace a non-symbol key by the equivalent symbol for faster further
10683 // lookups.
10684 set(index, key);
10685 return entry;
10686 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010687 ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key));
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010688 entry = NextProbe(entry, count++, capacity);
10689 }
10690 return kNotFound;
10691}
10692
10693
Steve Blocka7e24c12009-10-30 11:49:00 +000010694template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010695MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
10696 ASSERT(NumberOfElements() < new_table->Capacity());
10697
10698 AssertNoAllocation no_gc;
10699 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
10700
10701 // Copy prefix to new array.
10702 for (int i = kPrefixStartIndex;
10703 i < kPrefixStartIndex + Shape::kPrefixSize;
10704 i++) {
10705 new_table->set(i, get(i), mode);
10706 }
10707
10708 // Rehash the elements.
10709 int capacity = Capacity();
10710 for (int i = 0; i < capacity; i++) {
10711 uint32_t from_index = EntryToIndex(i);
10712 Object* k = get(from_index);
10713 if (IsKey(k)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010714 uint32_t hash = Shape::HashForObject(key, k);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010715 uint32_t insertion_index =
10716 EntryToIndex(new_table->FindInsertionEntry(hash));
10717 for (int j = 0; j < Shape::kEntrySize; j++) {
10718 new_table->set(insertion_index + j, get(from_index + j), mode);
10719 }
10720 }
10721 }
10722 new_table->SetNumberOfElements(NumberOfElements());
10723 new_table->SetNumberOfDeletedElements(0);
10724 return new_table;
10725}
10726
10727
10728template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010729MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010730 int capacity = Capacity();
10731 int nof = NumberOfElements() + n;
Leon Clarkee46be812010-01-19 14:06:41 +000010732 int nod = NumberOfDeletedElements();
10733 // Return if:
10734 // 50% is still free after adding n elements and
10735 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +010010736 if (nod <= (capacity - nof) >> 1) {
10737 int needed_free = nof >> 1;
10738 if (nof + needed_free <= capacity) return this;
10739 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010740
Steve Block6ded16b2010-05-10 14:33:55 +010010741 const int kMinCapacityForPretenure = 256;
10742 bool pretenure =
Ben Murdoch8b112d22011-06-08 16:22:53 +010010743 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
John Reck59135872010-11-02 12:39:01 -070010744 Object* obj;
10745 { MaybeObject* maybe_obj =
10746 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
10747 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10748 }
Leon Clarke4515c472010-02-03 11:58:03 +000010749
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010750 return Rehash(HashTable::cast(obj), key);
10751}
Steve Blocka7e24c12009-10-30 11:49:00 +000010752
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010753
10754template<typename Shape, typename Key>
10755MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
10756 int capacity = Capacity();
10757 int nof = NumberOfElements();
10758
10759 // Shrink to fit the number of elements if only a quarter of the
10760 // capacity is filled with elements.
10761 if (nof > (capacity >> 2)) return this;
10762 // Allocate a new dictionary with room for at least the current
10763 // number of elements. The allocation method will make sure that
10764 // there is extra room in the dictionary for additions. Don't go
10765 // lower than room for 16 elements.
10766 int at_least_room_for = nof;
10767 if (at_least_room_for < 16) return this;
10768
10769 const int kMinCapacityForPretenure = 256;
10770 bool pretenure =
10771 (at_least_room_for > kMinCapacityForPretenure) &&
10772 !GetHeap()->InNewSpace(this);
10773 Object* obj;
10774 { MaybeObject* maybe_obj =
10775 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
10776 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000010777 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010778
10779 return Rehash(HashTable::cast(obj), key);
Steve Blocka7e24c12009-10-30 11:49:00 +000010780}
10781
10782
10783template<typename Shape, typename Key>
10784uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
10785 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +000010786 uint32_t entry = FirstProbe(hash, capacity);
10787 uint32_t count = 1;
10788 // EnsureCapacity will guarantee the hash table is never full.
10789 while (true) {
10790 Object* element = KeyAt(entry);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010791 if (element->IsUndefined() || element->IsTheHole()) break;
Leon Clarkee46be812010-01-19 14:06:41 +000010792 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000010793 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010794 return entry;
10795}
10796
10797// Force instantiation of template instances class.
10798// Please note this list is compiler dependent.
10799
10800template class HashTable<SymbolTableShape, HashTableKey*>;
10801
10802template class HashTable<CompilationCacheShape, HashTableKey*>;
10803
10804template class HashTable<MapCacheShape, HashTableKey*>;
10805
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010806template class HashTable<ObjectHashTableShape<1>, Object*>;
10807
10808template class HashTable<ObjectHashTableShape<2>, Object*>;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010809
Steve Blocka7e24c12009-10-30 11:49:00 +000010810template class Dictionary<StringDictionaryShape, String*>;
10811
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010812template class Dictionary<NumberDictionaryShape, uint32_t>;
Steve Blocka7e24c12009-10-30 11:49:00 +000010813
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010814template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
10815 int);
Steve Blocka7e24c12009-10-30 11:49:00 +000010816
John Reck59135872010-11-02 12:39:01 -070010817template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +000010818 int);
10819
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010820template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
Steve Blocka7e24c12009-10-30 11:49:00 +000010821 uint32_t, Object*);
10822
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010823template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
10824 Object*);
Steve Blocka7e24c12009-10-30 11:49:00 +000010825
10826template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
10827 Object*);
10828
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010829template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010830 FixedArray*,
10831 PropertyAttributes,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010832 Dictionary<NumberDictionaryShape, uint32_t>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010833
10834template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
10835 int, JSObject::DeleteMode);
10836
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010837template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
10838 int, JSObject::DeleteMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010839
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010840template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
10841 String*);
10842
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010843template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010844 uint32_t);
10845
Steve Blocka7e24c12009-10-30 11:49:00 +000010846template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010847 FixedArray*,
10848 int,
10849 Dictionary<StringDictionaryShape, String*>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010850
10851template int
10852Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
10853 PropertyAttributes);
10854
John Reck59135872010-11-02 12:39:01 -070010855template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000010856 String*, Object*, PropertyDetails);
10857
John Reck59135872010-11-02 12:39:01 -070010858template MaybeObject*
Steve Blocka7e24c12009-10-30 11:49:00 +000010859Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
10860
10861template int
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010862Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
10863 PropertyAttributes);
Steve Blocka7e24c12009-10-30 11:49:00 +000010864
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010865template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000010866 uint32_t, Object*, PropertyDetails);
10867
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010868template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
John Reck59135872010-11-02 12:39:01 -070010869 EnsureCapacity(int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000010870
John Reck59135872010-11-02 12:39:01 -070010871template MaybeObject* Dictionary<StringDictionaryShape, String*>::
10872 EnsureCapacity(int, String*);
Steve Blocka7e24c12009-10-30 11:49:00 +000010873
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010874template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
10875 uint32_t, Object*, PropertyDetails, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000010876
John Reck59135872010-11-02 12:39:01 -070010877template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +000010878 String*, Object*, PropertyDetails, uint32_t);
10879
10880template
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010881int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000010882
10883template
10884int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
10885
Leon Clarkee46be812010-01-19 14:06:41 +000010886template
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010887int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
Leon Clarkee46be812010-01-19 14:06:41 +000010888
10889
Steve Blocka7e24c12009-10-30 11:49:00 +000010890// Collates undefined and unexisting elements below limit from position
10891// zero of the elements. The object stays in Dictionary mode.
John Reck59135872010-11-02 12:39:01 -070010892MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010893 ASSERT(HasDictionaryElements());
10894 // Must stay in dictionary mode, either because of requires_slow_elements,
10895 // or because we are not going to sort (and therefore compact) all of the
10896 // elements.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010897 NumberDictionary* dict = element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +000010898 HeapNumber* result_double = NULL;
10899 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10900 // Allocate space for result before we start mutating the object.
John Reck59135872010-11-02 12:39:01 -070010901 Object* new_double;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010902 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070010903 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10904 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010905 result_double = HeapNumber::cast(new_double);
10906 }
10907
John Reck59135872010-11-02 12:39:01 -070010908 Object* obj;
10909 { MaybeObject* maybe_obj =
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010910 NumberDictionary::Allocate(dict->NumberOfElements());
John Reck59135872010-11-02 12:39:01 -070010911 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10912 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010913 NumberDictionary* new_dict = NumberDictionary::cast(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +000010914
10915 AssertNoAllocation no_alloc;
10916
10917 uint32_t pos = 0;
10918 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010010919 int capacity = dict->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000010920 for (int i = 0; i < capacity; i++) {
10921 Object* k = dict->KeyAt(i);
10922 if (dict->IsKey(k)) {
10923 ASSERT(k->IsNumber());
10924 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
10925 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
10926 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
10927 Object* value = dict->ValueAt(i);
10928 PropertyDetails details = dict->DetailsAt(i);
10929 if (details.type() == CALLBACKS) {
10930 // Bail out and do the sorting of undefineds and array holes in JS.
10931 return Smi::FromInt(-1);
10932 }
10933 uint32_t key = NumberToUint32(k);
John Reck59135872010-11-02 12:39:01 -070010934 // In the following we assert that adding the entry to the new dictionary
10935 // does not cause GC. This is the case because we made sure to allocate
10936 // the dictionary big enough above, so it need not grow.
Steve Blocka7e24c12009-10-30 11:49:00 +000010937 if (key < limit) {
10938 if (value->IsUndefined()) {
10939 undefs++;
10940 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010010941 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10942 // Adding an entry with the key beyond smi-range requires
10943 // allocation. Bailout.
10944 return Smi::FromInt(-1);
10945 }
John Reck59135872010-11-02 12:39:01 -070010946 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010947 pos++;
10948 }
10949 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010010950 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
10951 // Adding an entry with the key beyond smi-range requires
10952 // allocation. Bailout.
10953 return Smi::FromInt(-1);
10954 }
John Reck59135872010-11-02 12:39:01 -070010955 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010956 }
10957 }
10958 }
10959
10960 uint32_t result = pos;
10961 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010962 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010963 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010010964 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10965 // Adding an entry with the key beyond smi-range requires
10966 // allocation. Bailout.
10967 return Smi::FromInt(-1);
10968 }
Steve Block44f0eee2011-05-26 01:26:41 +010010969 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
John Reck59135872010-11-02 12:39:01 -070010970 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010971 pos++;
10972 undefs--;
10973 }
10974
10975 set_elements(new_dict);
10976
10977 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10978 return Smi::FromInt(static_cast<int>(result));
10979 }
10980
10981 ASSERT_NE(NULL, result_double);
10982 result_double->set_value(static_cast<double>(result));
10983 return result_double;
10984}
10985
10986
10987// Collects all defined (non-hole) and non-undefined (array) elements at
10988// the start of the elements array.
10989// If the object is in dictionary mode, it is converted to fast elements
10990// mode.
John Reck59135872010-11-02 12:39:01 -070010991MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010992 Heap* heap = GetHeap();
10993
Steve Blocka7e24c12009-10-30 11:49:00 +000010994 if (HasDictionaryElements()) {
10995 // Convert to fast elements containing only the existing properties.
10996 // Ordering is irrelevant, since we are going to sort anyway.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010997 NumberDictionary* dict = element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +000010998 if (IsJSArray() || dict->requires_slow_elements() ||
10999 dict->max_number_key() >= limit) {
11000 return PrepareSlowElementsForSort(limit);
11001 }
11002 // Convert to fast elements.
11003
John Reck59135872010-11-02 12:39:01 -070011004 Object* obj;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011005 { MaybeObject* maybe_obj = GetElementsTransitionMap(FAST_ELEMENTS);
John Reck59135872010-11-02 12:39:01 -070011006 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11007 }
Steve Block8defd9f2010-07-08 12:39:36 +010011008 Map* new_map = Map::cast(obj);
11009
Steve Block44f0eee2011-05-26 01:26:41 +010011010 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
John Reck59135872010-11-02 12:39:01 -070011011 Object* new_array;
11012 { MaybeObject* maybe_new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010011013 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
John Reck59135872010-11-02 12:39:01 -070011014 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
11015 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011016 FixedArray* fast_elements = FixedArray::cast(new_array);
11017 dict->CopyValuesTo(fast_elements);
Steve Block8defd9f2010-07-08 12:39:36 +010011018
11019 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +000011020 set_elements(fast_elements);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011021 } else if (HasExternalArrayElements()) {
11022 // External arrays cannot have holes or undefined elements.
11023 return Smi::FromInt(ExternalArray::cast(elements())->length());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011024 } else if (!HasFastDoubleElements()) {
John Reck59135872010-11-02 12:39:01 -070011025 Object* obj;
11026 { MaybeObject* maybe_obj = EnsureWritableFastElements();
11027 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11028 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011029 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011030 ASSERT(HasFastTypeElements() || HasFastDoubleElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000011031
11032 // Collect holes at the end, undefined before that and the rest at the
11033 // start, and return the number of non-hole, non-undefined values.
11034
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011035 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
11036 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000011037 if (limit > elements_length) {
11038 limit = elements_length ;
11039 }
11040 if (limit == 0) {
11041 return Smi::FromInt(0);
11042 }
11043
11044 HeapNumber* result_double = NULL;
11045 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11046 // Pessimistically allocate space for return value before
11047 // we start mutating the array.
John Reck59135872010-11-02 12:39:01 -070011048 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +010011049 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070011050 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11051 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011052 result_double = HeapNumber::cast(new_double);
11053 }
11054
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011055 uint32_t result = 0;
11056 if (elements_base->map() == heap->fixed_double_array_map()) {
11057 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
11058 // Split elements into defined and the_hole, in that order.
11059 unsigned int holes = limit;
11060 // Assume most arrays contain no holes and undefined values, so minimize the
11061 // number of stores of non-undefined, non-the-hole values.
11062 for (unsigned int i = 0; i < holes; i++) {
11063 if (elements->is_the_hole(i)) {
11064 holes--;
11065 } else {
11066 continue;
11067 }
11068 // Position i needs to be filled.
11069 while (holes > i) {
11070 if (elements->is_the_hole(holes)) {
11071 holes--;
11072 } else {
11073 elements->set(i, elements->get_scalar(holes));
11074 break;
11075 }
11076 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011077 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011078 result = holes;
11079 while (holes < limit) {
11080 elements->set_the_hole(holes);
11081 holes++;
11082 }
11083 } else {
11084 FixedArray* elements = FixedArray::cast(elements_base);
11085 AssertNoAllocation no_alloc;
11086
11087 // Split elements into defined, undefined and the_hole, in that order. Only
11088 // count locations for undefined and the hole, and fill them afterwards.
11089 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
11090 unsigned int undefs = limit;
11091 unsigned int holes = limit;
11092 // Assume most arrays contain no holes and undefined values, so minimize the
11093 // number of stores of non-undefined, non-the-hole values.
11094 for (unsigned int i = 0; i < undefs; i++) {
11095 Object* current = elements->get(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000011096 if (current->IsTheHole()) {
11097 holes--;
11098 undefs--;
11099 } else if (current->IsUndefined()) {
11100 undefs--;
11101 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011102 continue;
11103 }
11104 // Position i needs to be filled.
11105 while (undefs > i) {
11106 current = elements->get(undefs);
11107 if (current->IsTheHole()) {
11108 holes--;
11109 undefs--;
11110 } else if (current->IsUndefined()) {
11111 undefs--;
11112 } else {
11113 elements->set(i, current, write_barrier);
11114 break;
11115 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011116 }
11117 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011118 result = undefs;
11119 while (undefs < holes) {
11120 elements->set_undefined(undefs);
11121 undefs++;
11122 }
11123 while (holes < limit) {
11124 elements->set_the_hole(holes);
11125 holes++;
11126 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011127 }
11128
11129 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11130 return Smi::FromInt(static_cast<int>(result));
11131 }
11132 ASSERT_NE(NULL, result_double);
11133 result_double->set_value(static_cast<double>(result));
11134 return result_double;
11135}
11136
11137
Steve Block44f0eee2011-05-26 01:26:41 +010011138Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011139 uint8_t clamped_value = 0;
11140 if (index < static_cast<uint32_t>(length())) {
11141 if (value->IsSmi()) {
11142 int int_value = Smi::cast(value)->value();
11143 if (int_value < 0) {
11144 clamped_value = 0;
11145 } else if (int_value > 255) {
11146 clamped_value = 255;
11147 } else {
11148 clamped_value = static_cast<uint8_t>(int_value);
11149 }
11150 } else if (value->IsHeapNumber()) {
11151 double double_value = HeapNumber::cast(value)->value();
11152 if (!(double_value > 0)) {
11153 // NaN and less than zero clamp to zero.
11154 clamped_value = 0;
11155 } else if (double_value > 255) {
11156 // Greater than 255 clamp to 255.
11157 clamped_value = 255;
11158 } else {
11159 // Other doubles are rounded to the nearest integer.
11160 clamped_value = static_cast<uint8_t>(double_value + 0.5);
11161 }
11162 } else {
11163 // Clamp undefined to zero (default). All other types have been
11164 // converted to a number type further up in the call chain.
11165 ASSERT(value->IsUndefined());
11166 }
11167 set(index, clamped_value);
11168 }
11169 return Smi::FromInt(clamped_value);
11170}
11171
11172
Steve Block3ce2e202009-11-05 08:53:23 +000011173template<typename ExternalArrayClass, typename ValueType>
Steve Block44f0eee2011-05-26 01:26:41 +010011174static MaybeObject* ExternalArrayIntSetter(Heap* heap,
11175 ExternalArrayClass* receiver,
John Reck59135872010-11-02 12:39:01 -070011176 uint32_t index,
11177 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011178 ValueType cast_value = 0;
11179 if (index < static_cast<uint32_t>(receiver->length())) {
11180 if (value->IsSmi()) {
11181 int int_value = Smi::cast(value)->value();
11182 cast_value = static_cast<ValueType>(int_value);
11183 } else if (value->IsHeapNumber()) {
11184 double double_value = HeapNumber::cast(value)->value();
11185 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
11186 } else {
11187 // Clamp undefined to zero (default). All other types have been
11188 // converted to a number type further up in the call chain.
11189 ASSERT(value->IsUndefined());
11190 }
11191 receiver->set(index, cast_value);
11192 }
Steve Block44f0eee2011-05-26 01:26:41 +010011193 return heap->NumberFromInt32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000011194}
11195
11196
John Reck59135872010-11-02 12:39:01 -070011197MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011198 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011199 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011200}
11201
11202
John Reck59135872010-11-02 12:39:01 -070011203MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
11204 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011205 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011206 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011207}
11208
11209
John Reck59135872010-11-02 12:39:01 -070011210MaybeObject* ExternalShortArray::SetValue(uint32_t index,
11211 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011212 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011213 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011214}
11215
11216
John Reck59135872010-11-02 12:39:01 -070011217MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
11218 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011219 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011220 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011221}
11222
11223
John Reck59135872010-11-02 12:39:01 -070011224MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011225 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011226 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011227}
11228
11229
John Reck59135872010-11-02 12:39:01 -070011230MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011231 uint32_t cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010011232 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000011233 if (index < static_cast<uint32_t>(length())) {
11234 if (value->IsSmi()) {
11235 int int_value = Smi::cast(value)->value();
11236 cast_value = static_cast<uint32_t>(int_value);
11237 } else if (value->IsHeapNumber()) {
11238 double double_value = HeapNumber::cast(value)->value();
11239 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
11240 } else {
11241 // Clamp undefined to zero (default). All other types have been
11242 // converted to a number type further up in the call chain.
11243 ASSERT(value->IsUndefined());
11244 }
11245 set(index, cast_value);
11246 }
Steve Block44f0eee2011-05-26 01:26:41 +010011247 return heap->NumberFromUint32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000011248}
11249
11250
John Reck59135872010-11-02 12:39:01 -070011251MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011252 float cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010011253 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000011254 if (index < static_cast<uint32_t>(length())) {
11255 if (value->IsSmi()) {
11256 int int_value = Smi::cast(value)->value();
11257 cast_value = static_cast<float>(int_value);
11258 } else if (value->IsHeapNumber()) {
11259 double double_value = HeapNumber::cast(value)->value();
11260 cast_value = static_cast<float>(double_value);
11261 } else {
11262 // Clamp undefined to zero (default). All other types have been
11263 // converted to a number type further up in the call chain.
11264 ASSERT(value->IsUndefined());
11265 }
11266 set(index, cast_value);
11267 }
Steve Block44f0eee2011-05-26 01:26:41 +010011268 return heap->AllocateHeapNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000011269}
11270
11271
Ben Murdoch257744e2011-11-30 15:57:28 +000011272MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
11273 double double_value = 0;
11274 Heap* heap = GetHeap();
11275 if (index < static_cast<uint32_t>(length())) {
11276 if (value->IsSmi()) {
11277 int int_value = Smi::cast(value)->value();
11278 double_value = static_cast<double>(int_value);
11279 } else if (value->IsHeapNumber()) {
11280 double_value = HeapNumber::cast(value)->value();
11281 } else {
11282 // Clamp undefined to zero (default). All other types have been
11283 // converted to a number type further up in the call chain.
11284 ASSERT(value->IsUndefined());
11285 }
11286 set(index, double_value);
11287 }
11288 return heap->AllocateHeapNumber(double_value);
11289}
11290
11291
Ben Murdochb0fe1622011-05-05 13:52:32 +010011292JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011293 ASSERT(!HasFastProperties());
11294 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011295 return JSGlobalPropertyCell::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000011296}
11297
11298
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011299Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
11300 Handle<GlobalObject> global,
11301 Handle<String> name) {
11302 Isolate* isolate = global->GetIsolate();
11303 CALL_HEAP_FUNCTION(isolate,
11304 global->EnsurePropertyCell(*name),
11305 JSGlobalPropertyCell);
11306}
11307
11308
John Reck59135872010-11-02 12:39:01 -070011309MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011310 ASSERT(!HasFastProperties());
11311 int entry = property_dictionary()->FindEntry(name);
11312 if (entry == StringDictionary::kNotFound) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011313 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -070011314 Object* cell;
11315 { MaybeObject* maybe_cell =
Steve Block44f0eee2011-05-26 01:26:41 +010011316 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
John Reck59135872010-11-02 12:39:01 -070011317 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
11318 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011319 PropertyDetails details(NONE, NORMAL);
11320 details = details.AsDeleted();
John Reck59135872010-11-02 12:39:01 -070011321 Object* dictionary;
11322 { MaybeObject* maybe_dictionary =
11323 property_dictionary()->Add(name, cell, details);
11324 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
11325 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011326 set_properties(StringDictionary::cast(dictionary));
11327 return cell;
11328 } else {
11329 Object* value = property_dictionary()->ValueAt(entry);
11330 ASSERT(value->IsJSGlobalPropertyCell());
11331 return value;
11332 }
11333}
11334
11335
John Reck59135872010-11-02 12:39:01 -070011336MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011337 SymbolKey key(string);
11338 return LookupKey(&key, s);
11339}
11340
11341
Steve Blockd0582a62009-12-15 09:54:21 +000011342// This class is used for looking up two character strings in the symbol table.
11343// If we don't have a hit we don't want to waste much time so we unroll the
11344// string hash calculation loop here for speed. Doesn't work if the two
11345// characters form a decimal integer, since such strings have a different hash
11346// algorithm.
11347class TwoCharHashTableKey : public HashTableKey {
11348 public:
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011349 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
Steve Blockd0582a62009-12-15 09:54:21 +000011350 : c1_(c1), c2_(c2) {
11351 // Char 1.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011352 uint32_t hash = c1 + (c1 << 10);
Steve Blockd0582a62009-12-15 09:54:21 +000011353 hash ^= hash >> 6;
11354 // Char 2.
11355 hash += c2;
11356 hash += hash << 10;
11357 hash ^= hash >> 6;
11358 // GetHash.
11359 hash += hash << 3;
11360 hash ^= hash >> 11;
11361 hash += hash << 15;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011362 if (hash == 0) hash = 27;
Steve Blockd0582a62009-12-15 09:54:21 +000011363#ifdef DEBUG
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011364 StringHasher hasher(2);
Steve Blockd0582a62009-12-15 09:54:21 +000011365 hasher.AddCharacter(c1);
11366 hasher.AddCharacter(c2);
11367 // If this assert fails then we failed to reproduce the two-character
11368 // version of the string hashing algorithm above. One reason could be
11369 // that we were passed two digits as characters, since the hash
11370 // algorithm is different in that case.
11371 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
11372#endif
11373 hash_ = hash;
11374 }
11375
11376 bool IsMatch(Object* o) {
11377 if (!o->IsString()) return false;
11378 String* other = String::cast(o);
11379 if (other->length() != 2) return false;
11380 if (other->Get(0) != c1_) return false;
11381 return other->Get(1) == c2_;
11382 }
11383
11384 uint32_t Hash() { return hash_; }
11385 uint32_t HashForObject(Object* key) {
11386 if (!key->IsString()) return 0;
11387 return String::cast(key)->Hash();
11388 }
11389
11390 Object* AsObject() {
11391 // The TwoCharHashTableKey is only used for looking in the symbol
11392 // table, not for adding to it.
11393 UNREACHABLE();
11394 return NULL;
11395 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011396
Steve Blockd0582a62009-12-15 09:54:21 +000011397 private:
11398 uint32_t c1_;
11399 uint32_t c2_;
11400 uint32_t hash_;
11401};
11402
11403
Steve Blocka7e24c12009-10-30 11:49:00 +000011404bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
11405 SymbolKey key(string);
11406 int entry = FindEntry(&key);
11407 if (entry == kNotFound) {
11408 return false;
11409 } else {
11410 String* result = String::cast(KeyAt(entry));
11411 ASSERT(StringShape(result).IsSymbol());
11412 *symbol = result;
11413 return true;
11414 }
11415}
11416
11417
Steve Blockd0582a62009-12-15 09:54:21 +000011418bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
11419 uint32_t c2,
11420 String** symbol) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011421 TwoCharHashTableKey key(c1, c2);
Steve Blockd0582a62009-12-15 09:54:21 +000011422 int entry = FindEntry(&key);
11423 if (entry == kNotFound) {
11424 return false;
11425 } else {
11426 String* result = String::cast(KeyAt(entry));
11427 ASSERT(StringShape(result).IsSymbol());
11428 *symbol = result;
11429 return true;
11430 }
11431}
11432
11433
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011434MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
11435 Utf8SymbolKey key(str);
Steve Blocka7e24c12009-10-30 11:49:00 +000011436 return LookupKey(&key, s);
11437}
11438
11439
Steve Block9fac8402011-05-12 15:51:54 +010011440MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
11441 Object** s) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011442 AsciiSymbolKey key(str);
Steve Block9fac8402011-05-12 15:51:54 +010011443 return LookupKey(&key, s);
11444}
11445
11446
Ben Murdoch257744e2011-11-30 15:57:28 +000011447MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
11448 int from,
11449 int length,
11450 Object** s) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011451 SubStringAsciiSymbolKey key(str, from, length);
Ben Murdoch257744e2011-11-30 15:57:28 +000011452 return LookupKey(&key, s);
11453}
11454
11455
Steve Block9fac8402011-05-12 15:51:54 +010011456MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
11457 Object** s) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011458 TwoByteSymbolKey key(str);
Steve Block9fac8402011-05-12 15:51:54 +010011459 return LookupKey(&key, s);
11460}
11461
John Reck59135872010-11-02 12:39:01 -070011462MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011463 int entry = FindEntry(key);
11464
11465 // Symbol already in table.
11466 if (entry != kNotFound) {
11467 *s = KeyAt(entry);
11468 return this;
11469 }
11470
11471 // Adding new symbol. Grow table if needed.
John Reck59135872010-11-02 12:39:01 -070011472 Object* obj;
11473 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11474 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11475 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011476
11477 // Create symbol object.
John Reck59135872010-11-02 12:39:01 -070011478 Object* symbol;
11479 { MaybeObject* maybe_symbol = key->AsObject();
11480 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
11481 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011482
11483 // If the symbol table grew as part of EnsureCapacity, obj is not
11484 // the current symbol table and therefore we cannot use
11485 // SymbolTable::cast here.
11486 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
11487
11488 // Add the new symbol and return it along with the symbol table.
11489 entry = table->FindInsertionEntry(key->Hash());
11490 table->set(EntryToIndex(entry), symbol);
11491 table->ElementAdded();
11492 *s = symbol;
11493 return table;
11494}
11495
11496
11497Object* CompilationCacheTable::Lookup(String* src) {
11498 StringKey key(src);
11499 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011500 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011501 return get(EntryToIndex(entry) + 1);
11502}
11503
11504
Steve Block1e0659c2011-05-24 12:43:12 +010011505Object* CompilationCacheTable::LookupEval(String* src,
11506 Context* context,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011507 LanguageMode language_mode,
11508 int scope_position) {
11509 StringSharedKey key(src,
11510 context->closure()->shared(),
11511 language_mode,
11512 scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000011513 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +010011514 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011515 return get(EntryToIndex(entry) + 1);
11516}
11517
11518
11519Object* CompilationCacheTable::LookupRegExp(String* src,
11520 JSRegExp::Flags flags) {
11521 RegExpKey key(src, flags);
11522 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011523 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011524 return get(EntryToIndex(entry) + 1);
11525}
11526
11527
John Reck59135872010-11-02 12:39:01 -070011528MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011529 StringKey key(src);
John Reck59135872010-11-02 12:39:01 -070011530 Object* obj;
11531 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11532 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11533 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011534
11535 CompilationCacheTable* cache =
11536 reinterpret_cast<CompilationCacheTable*>(obj);
11537 int entry = cache->FindInsertionEntry(key.Hash());
11538 cache->set(EntryToIndex(entry), src);
11539 cache->set(EntryToIndex(entry) + 1, value);
11540 cache->ElementAdded();
11541 return cache;
11542}
11543
11544
John Reck59135872010-11-02 12:39:01 -070011545MaybeObject* CompilationCacheTable::PutEval(String* src,
11546 Context* context,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011547 SharedFunctionInfo* value,
11548 int scope_position) {
Steve Block1e0659c2011-05-24 12:43:12 +010011549 StringSharedKey key(src,
11550 context->closure()->shared(),
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011551 value->language_mode(),
11552 scope_position);
John Reck59135872010-11-02 12:39:01 -070011553 Object* obj;
11554 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11555 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11556 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011557
11558 CompilationCacheTable* cache =
11559 reinterpret_cast<CompilationCacheTable*>(obj);
11560 int entry = cache->FindInsertionEntry(key.Hash());
11561
John Reck59135872010-11-02 12:39:01 -070011562 Object* k;
11563 { MaybeObject* maybe_k = key.AsObject();
11564 if (!maybe_k->ToObject(&k)) return maybe_k;
11565 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011566
11567 cache->set(EntryToIndex(entry), k);
11568 cache->set(EntryToIndex(entry) + 1, value);
11569 cache->ElementAdded();
11570 return cache;
11571}
11572
11573
John Reck59135872010-11-02 12:39:01 -070011574MaybeObject* CompilationCacheTable::PutRegExp(String* src,
11575 JSRegExp::Flags flags,
11576 FixedArray* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011577 RegExpKey key(src, flags);
John Reck59135872010-11-02 12:39:01 -070011578 Object* obj;
11579 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11580 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11581 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011582
11583 CompilationCacheTable* cache =
11584 reinterpret_cast<CompilationCacheTable*>(obj);
11585 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000011586 // We store the value in the key slot, and compare the search key
11587 // to the stored value with a custon IsMatch function during lookups.
Steve Blocka7e24c12009-10-30 11:49:00 +000011588 cache->set(EntryToIndex(entry), value);
11589 cache->set(EntryToIndex(entry) + 1, value);
11590 cache->ElementAdded();
11591 return cache;
11592}
11593
11594
Ben Murdochb0fe1622011-05-05 13:52:32 +010011595void CompilationCacheTable::Remove(Object* value) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011596 Object* the_hole_value = GetHeap()->the_hole_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010011597 for (int entry = 0, size = Capacity(); entry < size; entry++) {
11598 int entry_index = EntryToIndex(entry);
11599 int value_index = entry_index + 1;
11600 if (get(value_index) == value) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011601 NoWriteBarrierSet(this, entry_index, the_hole_value);
11602 NoWriteBarrierSet(this, value_index, the_hole_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011603 ElementRemoved();
11604 }
11605 }
11606 return;
11607}
11608
11609
Steve Blocka7e24c12009-10-30 11:49:00 +000011610// SymbolsKey used for HashTable where key is array of symbols.
11611class SymbolsKey : public HashTableKey {
11612 public:
11613 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
11614
11615 bool IsMatch(Object* symbols) {
11616 FixedArray* o = FixedArray::cast(symbols);
11617 int len = symbols_->length();
11618 if (o->length() != len) return false;
11619 for (int i = 0; i < len; i++) {
11620 if (o->get(i) != symbols_->get(i)) return false;
11621 }
11622 return true;
11623 }
11624
11625 uint32_t Hash() { return HashForObject(symbols_); }
11626
11627 uint32_t HashForObject(Object* obj) {
11628 FixedArray* symbols = FixedArray::cast(obj);
11629 int len = symbols->length();
11630 uint32_t hash = 0;
11631 for (int i = 0; i < len; i++) {
11632 hash ^= String::cast(symbols->get(i))->Hash();
11633 }
11634 return hash;
11635 }
11636
11637 Object* AsObject() { return symbols_; }
11638
11639 private:
11640 FixedArray* symbols_;
11641};
11642
11643
11644Object* MapCache::Lookup(FixedArray* array) {
11645 SymbolsKey key(array);
11646 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011647 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011648 return get(EntryToIndex(entry) + 1);
11649}
11650
11651
John Reck59135872010-11-02 12:39:01 -070011652MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011653 SymbolsKey key(array);
John Reck59135872010-11-02 12:39:01 -070011654 Object* obj;
11655 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11656 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11657 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011658
11659 MapCache* cache = reinterpret_cast<MapCache*>(obj);
11660 int entry = cache->FindInsertionEntry(key.Hash());
11661 cache->set(EntryToIndex(entry), array);
11662 cache->set(EntryToIndex(entry) + 1, value);
11663 cache->ElementAdded();
11664 return cache;
11665}
11666
11667
11668template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011669MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
11670 Object* obj;
11671 { MaybeObject* maybe_obj =
11672 HashTable<Shape, Key>::Allocate(at_least_space_for);
11673 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000011674 }
John Reck59135872010-11-02 12:39:01 -070011675 // Initialize the next enumeration index.
11676 Dictionary<Shape, Key>::cast(obj)->
11677 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
Steve Blocka7e24c12009-10-30 11:49:00 +000011678 return obj;
11679}
11680
11681
11682template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011683MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Steve Block44f0eee2011-05-26 01:26:41 +010011684 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000011685 int length = HashTable<Shape, Key>::NumberOfElements();
11686
11687 // Allocate and initialize iteration order array.
John Reck59135872010-11-02 12:39:01 -070011688 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +010011689 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070011690 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11691 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011692 FixedArray* iteration_order = FixedArray::cast(obj);
11693 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000011694 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000011695 }
11696
11697 // Allocate array with enumeration order.
Steve Block44f0eee2011-05-26 01:26:41 +010011698 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070011699 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11700 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011701 FixedArray* enumeration_order = FixedArray::cast(obj);
11702
11703 // Fill the enumeration order array with property details.
11704 int capacity = HashTable<Shape, Key>::Capacity();
11705 int pos = 0;
11706 for (int i = 0; i < capacity; i++) {
11707 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
Leon Clarke4515c472010-02-03 11:58:03 +000011708 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011709 }
11710 }
11711
11712 // Sort the arrays wrt. enumeration order.
11713 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
11714
11715 // Overwrite the enumeration_order with the enumeration indices.
11716 for (int i = 0; i < length; i++) {
11717 int index = Smi::cast(iteration_order->get(i))->value();
11718 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +000011719 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +000011720 }
11721
11722 // Update the dictionary with new indices.
11723 capacity = HashTable<Shape, Key>::Capacity();
11724 pos = 0;
11725 for (int i = 0; i < capacity; i++) {
11726 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
11727 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
11728 PropertyDetails details = DetailsAt(i);
11729 PropertyDetails new_details =
11730 PropertyDetails(details.attributes(), details.type(), enum_index);
11731 DetailsAtPut(i, new_details);
11732 }
11733 }
11734
11735 // Set the next enumeration index.
11736 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
11737 return this;
11738}
11739
11740template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011741MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011742 // Check whether there are enough enumeration indices to add n elements.
11743 if (Shape::kIsEnumerable &&
11744 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
11745 // If not, we generate new indices for the properties.
John Reck59135872010-11-02 12:39:01 -070011746 Object* result;
11747 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
11748 if (!maybe_result->ToObject(&result)) return maybe_result;
11749 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011750 }
11751 return HashTable<Shape, Key>::EnsureCapacity(n, key);
11752}
11753
11754
Steve Blocka7e24c12009-10-30 11:49:00 +000011755template<typename Shape, typename Key>
11756Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011757 JSReceiver::DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +010011758 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000011759 PropertyDetails details = DetailsAt(entry);
11760 // Ignore attributes if forcing a deletion.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011761 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
Steve Block44f0eee2011-05-26 01:26:41 +010011762 return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011763 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011764 SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011765 HashTable<Shape, Key>::ElementRemoved();
Steve Block44f0eee2011-05-26 01:26:41 +010011766 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011767}
11768
11769
11770template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011771MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
11772 return HashTable<Shape, Key>::Shrink(key);
11773}
11774
11775
11776template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011777MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011778 int entry = this->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000011779
11780 // If the entry is present set the value;
11781 if (entry != Dictionary<Shape, Key>::kNotFound) {
11782 ValueAtPut(entry, value);
11783 return this;
11784 }
11785
11786 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070011787 Object* obj;
11788 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11789 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11790 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011791
John Reck59135872010-11-02 12:39:01 -070011792 Object* k;
11793 { MaybeObject* maybe_k = Shape::AsObject(key);
11794 if (!maybe_k->ToObject(&k)) return maybe_k;
11795 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011796 PropertyDetails details = PropertyDetails(NONE, NORMAL);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011797 return Dictionary<Shape, Key>::cast(obj)->
11798 AddEntry(key, value, details, Shape::Hash(key));
Steve Blocka7e24c12009-10-30 11:49:00 +000011799}
11800
11801
11802template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011803MaybeObject* Dictionary<Shape, Key>::Add(Key key,
11804 Object* value,
11805 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011806 // Valdate key is absent.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011807 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000011808 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070011809 Object* obj;
11810 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11811 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11812 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011813 return Dictionary<Shape, Key>::cast(obj)->
11814 AddEntry(key, value, details, Shape::Hash(key));
Steve Blocka7e24c12009-10-30 11:49:00 +000011815}
11816
11817
11818// Add a key, value pair to the dictionary.
11819template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011820MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
11821 Object* value,
11822 PropertyDetails details,
11823 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011824 // Compute the key object.
John Reck59135872010-11-02 12:39:01 -070011825 Object* k;
11826 { MaybeObject* maybe_k = Shape::AsObject(key);
11827 if (!maybe_k->ToObject(&k)) return maybe_k;
11828 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011829
11830 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
11831 // Insert element at empty or deleted entry
11832 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
11833 // Assign an enumeration index to the property and update
11834 // SetNextEnumerationIndex.
11835 int index = NextEnumerationIndex();
11836 details = PropertyDetails(details.attributes(), details.type(), index);
11837 SetNextEnumerationIndex(index + 1);
11838 }
11839 SetEntry(entry, k, value, details);
11840 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
11841 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
11842 HashTable<Shape, Key>::ElementAdded();
11843 return this;
11844}
11845
11846
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011847void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011848 // If the dictionary requires slow elements an element has already
11849 // been added at a high index.
11850 if (requires_slow_elements()) return;
11851 // Check if this index is high enough that we should require slow
11852 // elements.
11853 if (key > kRequiresSlowElementsLimit) {
11854 set_requires_slow_elements();
11855 return;
11856 }
11857 // Update max key value.
11858 Object* max_index_object = get(kMaxNumberKeyIndex);
11859 if (!max_index_object->IsSmi() || max_number_key() < key) {
11860 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000011861 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000011862 }
11863}
11864
11865
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011866MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
11867 Object* value,
11868 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011869 UpdateMaxNumberKey(key);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011870 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +000011871 return Add(key, value, details);
11872}
11873
11874
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011875MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011876 UpdateMaxNumberKey(key);
11877 return AtPut(key, value);
11878}
11879
11880
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011881MaybeObject* NumberDictionary::Set(uint32_t key,
11882 Object* value,
11883 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011884 int entry = FindEntry(key);
11885 if (entry == kNotFound) return AddNumberEntry(key, value, details);
11886 // Preserve enumeration index.
11887 details = PropertyDetails(details.attributes(),
11888 details.type(),
11889 DetailsAt(entry).index());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011890 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
John Reck59135872010-11-02 12:39:01 -070011891 Object* object_key;
11892 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
Ben Murdochf87a2032010-10-22 12:50:53 +010011893 SetEntry(entry, object_key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000011894 return this;
11895}
11896
11897
11898
11899template<typename Shape, typename Key>
11900int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
11901 PropertyAttributes filter) {
11902 int capacity = HashTable<Shape, Key>::Capacity();
11903 int result = 0;
11904 for (int i = 0; i < capacity; i++) {
11905 Object* k = HashTable<Shape, Key>::KeyAt(i);
11906 if (HashTable<Shape, Key>::IsKey(k)) {
11907 PropertyDetails details = DetailsAt(i);
11908 if (details.IsDeleted()) continue;
11909 PropertyAttributes attr = details.attributes();
11910 if ((attr & filter) == 0) result++;
11911 }
11912 }
11913 return result;
11914}
11915
11916
11917template<typename Shape, typename Key>
11918int Dictionary<Shape, Key>::NumberOfEnumElements() {
11919 return NumberOfElementsFilterAttributes(
11920 static_cast<PropertyAttributes>(DONT_ENUM));
11921}
11922
11923
11924template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011925void Dictionary<Shape, Key>::CopyKeysTo(
11926 FixedArray* storage,
11927 PropertyAttributes filter,
11928 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011929 ASSERT(storage->length() >= NumberOfEnumElements());
11930 int capacity = HashTable<Shape, Key>::Capacity();
11931 int index = 0;
11932 for (int i = 0; i < capacity; i++) {
11933 Object* k = HashTable<Shape, Key>::KeyAt(i);
11934 if (HashTable<Shape, Key>::IsKey(k)) {
11935 PropertyDetails details = DetailsAt(i);
11936 if (details.IsDeleted()) continue;
11937 PropertyAttributes attr = details.attributes();
11938 if ((attr & filter) == 0) storage->set(index++, k);
11939 }
11940 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011941 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11942 storage->SortPairs(storage, index);
11943 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011944 ASSERT(storage->length() >= index);
11945}
11946
11947
11948void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
11949 FixedArray* sort_array) {
11950 ASSERT(storage->length() >= NumberOfEnumElements());
11951 int capacity = Capacity();
11952 int index = 0;
11953 for (int i = 0; i < capacity; i++) {
11954 Object* k = KeyAt(i);
11955 if (IsKey(k)) {
11956 PropertyDetails details = DetailsAt(i);
11957 if (details.IsDeleted() || details.IsDontEnum()) continue;
11958 storage->set(index, k);
Leon Clarke4515c472010-02-03 11:58:03 +000011959 sort_array->set(index, Smi::FromInt(details.index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011960 index++;
11961 }
11962 }
11963 storage->SortPairs(sort_array, sort_array->length());
11964 ASSERT(storage->length() >= index);
11965}
11966
11967
11968template<typename Shape, typename Key>
Ben Murdoch6d7cb002011-08-04 19:25:22 +010011969void Dictionary<Shape, Key>::CopyKeysTo(
Ben Murdoch257744e2011-11-30 15:57:28 +000011970 FixedArray* storage,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011971 int index,
11972 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011973 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
11974 static_cast<PropertyAttributes>(NONE)));
11975 int capacity = HashTable<Shape, Key>::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000011976 for (int i = 0; i < capacity; i++) {
11977 Object* k = HashTable<Shape, Key>::KeyAt(i);
11978 if (HashTable<Shape, Key>::IsKey(k)) {
11979 PropertyDetails details = DetailsAt(i);
11980 if (details.IsDeleted()) continue;
11981 storage->set(index++, k);
11982 }
11983 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011984 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11985 storage->SortPairs(storage, index);
11986 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011987 ASSERT(storage->length() >= index);
11988}
11989
11990
11991// Backwards lookup (slow).
11992template<typename Shape, typename Key>
11993Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
11994 int capacity = HashTable<Shape, Key>::Capacity();
11995 for (int i = 0; i < capacity; i++) {
11996 Object* k = HashTable<Shape, Key>::KeyAt(i);
11997 if (Dictionary<Shape, Key>::IsKey(k)) {
11998 Object* e = ValueAt(i);
11999 if (e->IsJSGlobalPropertyCell()) {
12000 e = JSGlobalPropertyCell::cast(e)->value();
12001 }
12002 if (e == value) return k;
12003 }
12004 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010012005 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010012006 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012007}
12008
12009
John Reck59135872010-11-02 12:39:01 -070012010MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Steve Blocka7e24c12009-10-30 11:49:00 +000012011 JSObject* obj, int unused_property_fields) {
12012 // Make sure we preserve dictionary representation if there are too many
12013 // descriptors.
12014 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
12015
12016 // Figure out if it is necessary to generate new enumeration indices.
12017 int max_enumeration_index =
12018 NextEnumerationIndex() +
12019 (DescriptorArray::kMaxNumberOfDescriptors -
12020 NumberOfElements());
12021 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
John Reck59135872010-11-02 12:39:01 -070012022 Object* result;
12023 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12024 if (!maybe_result->ToObject(&result)) return maybe_result;
12025 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012026 }
12027
12028 int instance_descriptor_length = 0;
12029 int number_of_fields = 0;
12030
Ben Murdoch8b112d22011-06-08 16:22:53 +010012031 Heap* heap = GetHeap();
12032
Steve Blocka7e24c12009-10-30 11:49:00 +000012033 // Compute the length of the instance descriptor.
12034 int capacity = Capacity();
12035 for (int i = 0; i < capacity; i++) {
12036 Object* k = KeyAt(i);
12037 if (IsKey(k)) {
12038 Object* value = ValueAt(i);
12039 PropertyType type = DetailsAt(i).type();
12040 ASSERT(type != FIELD);
12041 instance_descriptor_length++;
Leon Clarkee46be812010-01-19 14:06:41 +000012042 if (type == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +010012043 (!value->IsJSFunction() || heap->InNewSpace(value))) {
Leon Clarkee46be812010-01-19 14:06:41 +000012044 number_of_fields += 1;
12045 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012046 }
12047 }
12048
12049 // Allocate the instance descriptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012050 DescriptorArray* descriptors;
12051 { MaybeObject* maybe_descriptors =
John Reck59135872010-11-02 12:39:01 -070012052 DescriptorArray::Allocate(instance_descriptor_length);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012053 if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) {
12054 return maybe_descriptors;
John Reck59135872010-11-02 12:39:01 -070012055 }
12056 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012057
12058 DescriptorArray::WhitenessWitness witness(descriptors);
Steve Blocka7e24c12009-10-30 11:49:00 +000012059
12060 int inobject_props = obj->map()->inobject_properties();
12061 int number_of_allocated_fields =
12062 number_of_fields + unused_property_fields - inobject_props;
Ben Murdochf87a2032010-10-22 12:50:53 +010012063 if (number_of_allocated_fields < 0) {
12064 // There is enough inobject space for all fields (including unused).
12065 number_of_allocated_fields = 0;
12066 unused_property_fields = inobject_props - number_of_fields;
12067 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012068
12069 // Allocate the fixed array for the fields.
John Reck59135872010-11-02 12:39:01 -070012070 Object* fields;
12071 { MaybeObject* maybe_fields =
Steve Block44f0eee2011-05-26 01:26:41 +010012072 heap->AllocateFixedArray(number_of_allocated_fields);
John Reck59135872010-11-02 12:39:01 -070012073 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
12074 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012075
12076 // Fill in the instance descriptor and the fields.
12077 int next_descriptor = 0;
12078 int current_offset = 0;
12079 for (int i = 0; i < capacity; i++) {
12080 Object* k = KeyAt(i);
12081 if (IsKey(k)) {
12082 Object* value = ValueAt(i);
12083 // Ensure the key is a symbol before writing into the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070012084 Object* key;
Steve Block44f0eee2011-05-26 01:26:41 +010012085 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
John Reck59135872010-11-02 12:39:01 -070012086 if (!maybe_key->ToObject(&key)) return maybe_key;
12087 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012088 PropertyDetails details = DetailsAt(i);
12089 PropertyType type = details.type();
12090
Steve Block44f0eee2011-05-26 01:26:41 +010012091 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012092 ConstantFunctionDescriptor d(String::cast(key),
12093 JSFunction::cast(value),
12094 details.attributes(),
12095 details.index());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012096 descriptors->Set(next_descriptor++, &d, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012097 } else if (type == NORMAL) {
12098 if (current_offset < inobject_props) {
12099 obj->InObjectPropertyAtPut(current_offset,
12100 value,
12101 UPDATE_WRITE_BARRIER);
12102 } else {
12103 int offset = current_offset - inobject_props;
12104 FixedArray::cast(fields)->set(offset, value);
12105 }
12106 FieldDescriptor d(String::cast(key),
12107 current_offset++,
12108 details.attributes(),
12109 details.index());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012110 descriptors->Set(next_descriptor++, &d, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012111 } else if (type == CALLBACKS) {
12112 CallbacksDescriptor d(String::cast(key),
12113 value,
12114 details.attributes(),
12115 details.index());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012116 descriptors->Set(next_descriptor++, &d, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012117 } else {
12118 UNREACHABLE();
12119 }
12120 }
12121 }
12122 ASSERT(current_offset == number_of_fields);
12123
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012124 descriptors->Sort(witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012125 // Allocate new map.
John Reck59135872010-11-02 12:39:01 -070012126 Object* new_map;
12127 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
12128 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
12129 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012130
12131 // Transform the object.
12132 obj->set_map(Map::cast(new_map));
12133 obj->map()->set_instance_descriptors(descriptors);
12134 obj->map()->set_unused_property_fields(unused_property_fields);
12135
12136 obj->set_properties(FixedArray::cast(fields));
12137 ASSERT(obj->IsJSObject());
12138
12139 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
12140 // Check that it really works.
12141 ASSERT(obj->HasFastProperties());
12142
12143 return obj;
12144}
12145
12146
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012147bool ObjectHashSet::Contains(Object* key) {
12148 ASSERT(IsKey(key));
12149
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012150 // If the object does not have an identity hash, it was never used as a key.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012151 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12152 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
12153 }
12154 return (FindEntry(key) != kNotFound);
12155}
12156
12157
12158MaybeObject* ObjectHashSet::Add(Object* key) {
12159 ASSERT(IsKey(key));
12160
12161 // Make sure the key object has an identity hash code.
12162 int hash;
12163 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12164 if (maybe_hash->IsFailure()) return maybe_hash;
12165 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12166 }
12167 int entry = FindEntry(key);
12168
12169 // Check whether key is already present.
12170 if (entry != kNotFound) return this;
12171
12172 // Check whether the hash set should be extended and add entry.
12173 Object* obj;
12174 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12175 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12176 }
12177 ObjectHashSet* table = ObjectHashSet::cast(obj);
12178 entry = table->FindInsertionEntry(hash);
12179 table->set(EntryToIndex(entry), key);
12180 table->ElementAdded();
12181 return table;
12182}
12183
12184
12185MaybeObject* ObjectHashSet::Remove(Object* key) {
12186 ASSERT(IsKey(key));
12187
12188 // If the object does not have an identity hash, it was never used as a key.
12189 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12190 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
12191 }
12192 int entry = FindEntry(key);
12193
12194 // Check whether key is actually present.
12195 if (entry == kNotFound) return this;
12196
12197 // Remove entry and try to shrink this hash set.
12198 set_the_hole(EntryToIndex(entry));
12199 ElementRemoved();
12200 return Shrink(key);
12201}
12202
12203
12204Object* ObjectHashTable::Lookup(Object* key) {
12205 ASSERT(IsKey(key));
12206
12207 // If the object does not have an identity hash, it was never used as a key.
12208 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12209 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
12210 return GetHeap()->undefined_value();
12211 }
12212 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012213 int entry = FindEntry(key);
12214 if (entry == kNotFound) return GetHeap()->undefined_value();
12215 return get(EntryToIndex(entry) + 1);
12216}
12217
12218
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012219MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
12220 ASSERT(IsKey(key));
12221
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012222 // Make sure the key object has an identity hash code.
12223 int hash;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012224 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012225 if (maybe_hash->IsFailure()) return maybe_hash;
12226 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12227 }
12228 int entry = FindEntry(key);
12229
12230 // Check whether to perform removal operation.
12231 if (value->IsUndefined()) {
12232 if (entry == kNotFound) return this;
12233 RemoveEntry(entry);
12234 return Shrink(key);
12235 }
12236
12237 // Key is already in table, just overwrite value.
12238 if (entry != kNotFound) {
12239 set(EntryToIndex(entry) + 1, value);
12240 return this;
12241 }
12242
12243 // Check whether the hash table should be extended.
12244 Object* obj;
12245 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12246 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12247 }
12248 ObjectHashTable* table = ObjectHashTable::cast(obj);
12249 table->AddEntry(table->FindInsertionEntry(hash), key, value);
12250 return table;
12251}
12252
12253
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012254void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012255 set(EntryToIndex(entry), key);
12256 set(EntryToIndex(entry) + 1, value);
12257 ElementAdded();
12258}
12259
12260
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012261void ObjectHashTable::RemoveEntry(int entry) {
12262 set_the_hole(EntryToIndex(entry));
12263 set_the_hole(EntryToIndex(entry) + 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012264 ElementRemoved();
12265}
12266
12267
Steve Blocka7e24c12009-10-30 11:49:00 +000012268#ifdef ENABLE_DEBUGGER_SUPPORT
12269// Check if there is a break point at this code position.
12270bool DebugInfo::HasBreakPoint(int code_position) {
12271 // Get the break point info object for this code position.
12272 Object* break_point_info = GetBreakPointInfo(code_position);
12273
12274 // If there is no break point info object or no break points in the break
12275 // point info object there is no break point at this code position.
12276 if (break_point_info->IsUndefined()) return false;
12277 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
12278}
12279
12280
12281// Get the break point info object for this code position.
12282Object* DebugInfo::GetBreakPointInfo(int code_position) {
12283 // Find the index of the break point info object for this code position.
12284 int index = GetBreakPointInfoIndex(code_position);
12285
12286 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012287 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012288 return BreakPointInfo::cast(break_points()->get(index));
12289}
12290
12291
12292// Clear a break point at the specified code position.
12293void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
12294 int code_position,
12295 Handle<Object> break_point_object) {
12296 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12297 if (break_point_info->IsUndefined()) return;
12298 BreakPointInfo::ClearBreakPoint(
12299 Handle<BreakPointInfo>::cast(break_point_info),
12300 break_point_object);
12301}
12302
12303
12304void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
12305 int code_position,
12306 int source_position,
12307 int statement_position,
12308 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010012309 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000012310 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12311 if (!break_point_info->IsUndefined()) {
12312 BreakPointInfo::SetBreakPoint(
12313 Handle<BreakPointInfo>::cast(break_point_info),
12314 break_point_object);
12315 return;
12316 }
12317
12318 // Adding a new break point for a code position which did not have any
12319 // break points before. Try to find a free slot.
12320 int index = kNoBreakPointInfo;
12321 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12322 if (debug_info->break_points()->get(i)->IsUndefined()) {
12323 index = i;
12324 break;
12325 }
12326 }
12327 if (index == kNoBreakPointInfo) {
12328 // No free slot - extend break point info array.
12329 Handle<FixedArray> old_break_points =
12330 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000012331 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010012332 isolate->factory()->NewFixedArray(
12333 old_break_points->length() +
12334 Debug::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010012335
12336 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000012337 for (int i = 0; i < old_break_points->length(); i++) {
12338 new_break_points->set(i, old_break_points->get(i));
12339 }
12340 index = old_break_points->length();
12341 }
12342 ASSERT(index != kNoBreakPointInfo);
12343
12344 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010012345 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
12346 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000012347 new_break_point_info->set_code_position(Smi::FromInt(code_position));
12348 new_break_point_info->set_source_position(Smi::FromInt(source_position));
12349 new_break_point_info->
12350 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010012351 new_break_point_info->set_break_point_objects(
12352 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012353 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
12354 debug_info->break_points()->set(index, *new_break_point_info);
12355}
12356
12357
12358// Get the break point objects for a code position.
12359Object* DebugInfo::GetBreakPointObjects(int code_position) {
12360 Object* break_point_info = GetBreakPointInfo(code_position);
12361 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010012362 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012363 }
12364 return BreakPointInfo::cast(break_point_info)->break_point_objects();
12365}
12366
12367
12368// Get the total number of break points.
12369int DebugInfo::GetBreakPointCount() {
12370 if (break_points()->IsUndefined()) return 0;
12371 int count = 0;
12372 for (int i = 0; i < break_points()->length(); i++) {
12373 if (!break_points()->get(i)->IsUndefined()) {
12374 BreakPointInfo* break_point_info =
12375 BreakPointInfo::cast(break_points()->get(i));
12376 count += break_point_info->GetBreakPointCount();
12377 }
12378 }
12379 return count;
12380}
12381
12382
12383Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
12384 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010012385 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010012386 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012387 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12388 if (!debug_info->break_points()->get(i)->IsUndefined()) {
12389 Handle<BreakPointInfo> break_point_info =
12390 Handle<BreakPointInfo>(BreakPointInfo::cast(
12391 debug_info->break_points()->get(i)));
12392 if (BreakPointInfo::HasBreakPointObject(break_point_info,
12393 break_point_object)) {
12394 return *break_point_info;
12395 }
12396 }
12397 }
Steve Block44f0eee2011-05-26 01:26:41 +010012398 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012399}
12400
12401
12402// Find the index of the break point info object for the specified code
12403// position.
12404int DebugInfo::GetBreakPointInfoIndex(int code_position) {
12405 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
12406 for (int i = 0; i < break_points()->length(); i++) {
12407 if (!break_points()->get(i)->IsUndefined()) {
12408 BreakPointInfo* break_point_info =
12409 BreakPointInfo::cast(break_points()->get(i));
12410 if (break_point_info->code_position()->value() == code_position) {
12411 return i;
12412 }
12413 }
12414 }
12415 return kNoBreakPointInfo;
12416}
12417
12418
12419// Remove the specified break point object.
12420void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
12421 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010012422 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000012423 // If there are no break points just ignore.
12424 if (break_point_info->break_point_objects()->IsUndefined()) return;
12425 // If there is a single break point clear it if it is the same.
12426 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12427 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010012428 break_point_info->set_break_point_objects(
12429 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012430 }
12431 return;
12432 }
12433 // If there are multiple break points shrink the array
12434 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
12435 Handle<FixedArray> old_array =
12436 Handle<FixedArray>(
12437 FixedArray::cast(break_point_info->break_point_objects()));
12438 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010012439 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000012440 int found_count = 0;
12441 for (int i = 0; i < old_array->length(); i++) {
12442 if (old_array->get(i) == *break_point_object) {
12443 ASSERT(found_count == 0);
12444 found_count++;
12445 } else {
12446 new_array->set(i - found_count, old_array->get(i));
12447 }
12448 }
12449 // If the break point was found in the list change it.
12450 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
12451}
12452
12453
12454// Add the specified break point object.
12455void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
12456 Handle<Object> break_point_object) {
12457 // If there was no break point objects before just set it.
12458 if (break_point_info->break_point_objects()->IsUndefined()) {
12459 break_point_info->set_break_point_objects(*break_point_object);
12460 return;
12461 }
12462 // If the break point object is the same as before just ignore.
12463 if (break_point_info->break_point_objects() == *break_point_object) return;
12464 // If there was one break point object before replace with array.
12465 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Steve Block44f0eee2011-05-26 01:26:41 +010012466 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000012467 array->set(0, break_point_info->break_point_objects());
12468 array->set(1, *break_point_object);
12469 break_point_info->set_break_point_objects(*array);
12470 return;
12471 }
12472 // If there was more than one break point before extend array.
12473 Handle<FixedArray> old_array =
12474 Handle<FixedArray>(
12475 FixedArray::cast(break_point_info->break_point_objects()));
12476 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010012477 FACTORY->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000012478 for (int i = 0; i < old_array->length(); i++) {
12479 // If the break point was there before just ignore.
12480 if (old_array->get(i) == *break_point_object) return;
12481 new_array->set(i, old_array->get(i));
12482 }
12483 // Add the new break point.
12484 new_array->set(old_array->length(), *break_point_object);
12485 break_point_info->set_break_point_objects(*new_array);
12486}
12487
12488
12489bool BreakPointInfo::HasBreakPointObject(
12490 Handle<BreakPointInfo> break_point_info,
12491 Handle<Object> break_point_object) {
12492 // No break point.
12493 if (break_point_info->break_point_objects()->IsUndefined()) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012494 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000012495 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12496 return break_point_info->break_point_objects() == *break_point_object;
12497 }
12498 // Multiple break points.
12499 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
12500 for (int i = 0; i < array->length(); i++) {
12501 if (array->get(i) == *break_point_object) {
12502 return true;
12503 }
12504 }
12505 return false;
12506}
12507
12508
12509// Get the number of break points.
12510int BreakPointInfo::GetBreakPointCount() {
12511 // No break point.
12512 if (break_point_objects()->IsUndefined()) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012513 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000012514 if (!break_point_objects()->IsFixedArray()) return 1;
12515 // Multiple break points.
12516 return FixedArray::cast(break_point_objects())->length();
12517}
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012518#endif // ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +000012519
12520
12521} } // namespace v8::internal