blob: 9f596c41a8554f9ff8698025872d15631654dd37 [file] [log] [blame]
Ben Murdochc7cc0282012-03-05 14:35:55 +00001// Copyright 2012 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
Ben Murdochc7cc0282012-03-05 14:35:55 +0000249 if (structure->IsAccessorPair()) {
250 Object* getter = AccessorPair::cast(structure)->getter();
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
Ben Murdochc7cc0282012-03-05 14:35:55 +0000488Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
489 Handle<String> key,
490 Handle<Object> value,
491 PropertyDetails details) {
492 CALL_HEAP_FUNCTION(object->GetIsolate(),
493 object->SetNormalizedProperty(*key, *value, details),
494 Object);
495}
496
497
John Reck59135872010-11-02 12:39:01 -0700498MaybeObject* JSObject::SetNormalizedProperty(String* name,
499 Object* value,
500 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000501 ASSERT(!HasFastProperties());
502 int entry = property_dictionary()->FindEntry(name);
503 if (entry == StringDictionary::kNotFound) {
504 Object* store_value = value;
505 if (IsGlobalObject()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100506 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100507 MaybeObject* maybe_store_value =
508 heap->AllocateJSGlobalPropertyCell(value);
509 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000510 }
John Reck59135872010-11-02 12:39:01 -0700511 Object* dict;
512 { MaybeObject* maybe_dict =
513 property_dictionary()->Add(name, store_value, details);
514 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
515 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000516 set_properties(StringDictionary::cast(dict));
517 return value;
518 }
519 // Preserve enumeration index.
520 details = PropertyDetails(details.attributes(),
521 details.type(),
522 property_dictionary()->DetailsAt(entry).index());
523 if (IsGlobalObject()) {
524 JSGlobalPropertyCell* cell =
525 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
526 cell->set_value(value);
527 // Please note we have to update the property details.
528 property_dictionary()->DetailsAtPut(entry, details);
529 } else {
530 property_dictionary()->SetEntry(entry, name, value, details);
531 }
532 return value;
533}
534
535
John Reck59135872010-11-02 12:39:01 -0700536MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000537 ASSERT(!HasFastProperties());
538 StringDictionary* dictionary = property_dictionary();
539 int entry = dictionary->FindEntry(name);
540 if (entry != StringDictionary::kNotFound) {
541 // If we have a global object set the cell to the hole.
542 if (IsGlobalObject()) {
543 PropertyDetails details = dictionary->DetailsAt(entry);
544 if (details.IsDontDelete()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100545 if (mode != FORCE_DELETION) return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000546 // When forced to delete global properties, we have to make a
547 // map change to invalidate any ICs that think they can load
548 // from the DontDelete cell without checking if it contains
549 // the hole value.
John Reck59135872010-11-02 12:39:01 -0700550 Object* new_map;
551 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
552 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
553 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000554 set_map(Map::cast(new_map));
555 }
556 JSGlobalPropertyCell* cell =
557 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000558 cell->set_value(cell->GetHeap()->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000559 dictionary->DetailsAtPut(entry, details.AsDeleted());
560 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000561 Object* deleted = dictionary->DeleteProperty(entry, mode);
562 if (deleted == GetHeap()->true_value()) {
563 FixedArray* new_properties = NULL;
564 MaybeObject* maybe_properties = dictionary->Shrink(name);
565 if (!maybe_properties->To(&new_properties)) {
566 return maybe_properties;
567 }
568 set_properties(new_properties);
569 }
570 return deleted;
Steve Blocka7e24c12009-10-30 11:49:00 +0000571 }
572 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100573 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000574}
575
576
577bool JSObject::IsDirty() {
578 Object* cons_obj = map()->constructor();
579 if (!cons_obj->IsJSFunction())
580 return true;
581 JSFunction* fun = JSFunction::cast(cons_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100582 if (!fun->shared()->IsApiFunction())
Steve Blocka7e24c12009-10-30 11:49:00 +0000583 return true;
584 // If the object is fully fast case and has the same map it was
585 // created with then no changes can have been made to it.
586 return map() != fun->initial_map()
587 || !HasFastElements()
588 || !HasFastProperties();
589}
590
591
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000592Handle<Object> Object::GetProperty(Handle<Object> object,
593 Handle<Object> receiver,
594 LookupResult* result,
595 Handle<String> key,
596 PropertyAttributes* attributes) {
597 Isolate* isolate = object->IsHeapObject()
598 ? Handle<HeapObject>::cast(object)->GetIsolate()
599 : Isolate::Current();
600 CALL_HEAP_FUNCTION(
601 isolate,
602 object->GetProperty(*receiver, result, *key, attributes),
603 Object);
604}
605
606
John Reck59135872010-11-02 12:39:01 -0700607MaybeObject* Object::GetProperty(Object* receiver,
608 LookupResult* result,
609 String* name,
610 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000611 // Make sure that the top context does not change when doing
612 // callbacks or interceptor calls.
613 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +0100614 Heap* heap = name->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000615
616 // Traverse the prototype chain from the current object (this) to
Ben Murdoch257744e2011-11-30 15:57:28 +0000617 // the holder and check for access rights. This avoids traversing the
Steve Blocka7e24c12009-10-30 11:49:00 +0000618 // objects more than once in case of interceptors, because the
619 // holder will always be the interceptor holder and the search may
620 // only continue with a current object just after the interceptor
621 // holder in the prototype chain.
Ben Murdoch257744e2011-11-30 15:57:28 +0000622 // Proxy handlers do not use the proxy's prototype, so we can skip this.
623 if (!result->IsHandler()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000624 Object* last = result->IsProperty()
625 ? result->holder()
626 : Object::cast(heap->null_value());
Ben Murdoch257744e2011-11-30 15:57:28 +0000627 ASSERT(this != this->GetPrototype());
628 for (Object* current = this; true; current = current->GetPrototype()) {
629 if (current->IsAccessCheckNeeded()) {
630 // Check if we're allowed to read from the current object. Note
631 // that even though we may not actually end up loading the named
632 // property from the current object, we still check that we have
633 // access to it.
634 JSObject* checked = JSObject::cast(current);
635 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
636 return checked->GetPropertyWithFailedAccessCheck(receiver,
637 result,
638 name,
639 attributes);
640 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000641 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000642 // Stop traversing the chain once we reach the last object in the
643 // chain; either the holder of the result or null in case of an
644 // absent property.
645 if (current == last) break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000646 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000647 }
648
649 if (!result->IsProperty()) {
650 *attributes = ABSENT;
Steve Block44f0eee2011-05-26 01:26:41 +0100651 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000652 }
653 *attributes = result->GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +0000654 Object* value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000655 switch (result->type()) {
656 case NORMAL:
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000657 value = result->holder()->GetNormalizedProperty(result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000658 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100659 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000660 case FIELD:
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000661 value = result->holder()->FastPropertyAt(result->GetFieldIndex());
Steve Blocka7e24c12009-10-30 11:49:00 +0000662 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100663 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000664 case CONSTANT_FUNCTION:
665 return result->GetConstantFunction();
666 case CALLBACKS:
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000667 return result->holder()->GetPropertyWithCallback(
668 receiver, result->GetCallbackObject(), name);
669 case HANDLER:
670 return result->proxy()->GetPropertyWithHandler(receiver, name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000671 case INTERCEPTOR: {
672 JSObject* recvr = JSObject::cast(receiver);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000673 return result->holder()->GetPropertyWithInterceptor(
674 recvr, name, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000675 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000676 case MAP_TRANSITION:
Ben Murdoch589d6972011-11-30 16:04:58 +0000677 case ELEMENTS_TRANSITION:
Ben Murdoch257744e2011-11-30 15:57:28 +0000678 case CONSTANT_TRANSITION:
679 case NULL_DESCRIPTOR:
680 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000681 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000682 UNREACHABLE();
683 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000684}
685
686
John Reck59135872010-11-02 12:39:01 -0700687MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000688 Heap* heap = IsSmi()
689 ? Isolate::Current()->heap()
690 : HeapObject::cast(this)->GetHeap();
691 Object* holder = this;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100692
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000693 // Iterate up the prototype chain until an element is found or the null
694 // prototype is encountered.
695 for (holder = this;
696 holder != heap->null_value();
697 holder = holder->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000698 if (!holder->IsJSObject()) {
699 Isolate* isolate = heap->isolate();
700 Context* global_context = isolate->context()->global_context();
701 if (holder->IsNumber()) {
702 holder = global_context->number_function()->instance_prototype();
703 } else if (holder->IsString()) {
704 holder = global_context->string_function()->instance_prototype();
705 } else if (holder->IsBoolean()) {
706 holder = global_context->boolean_function()->instance_prototype();
707 } else if (holder->IsJSProxy()) {
708 return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
709 } else {
710 // Undefined and null have no indexed properties.
711 ASSERT(holder->IsUndefined() || holder->IsNull());
712 return heap->undefined_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000713 }
714 }
715
716 // Inline the case for JSObjects. Doing so significantly improves the
717 // performance of fetching elements where checking the prototype chain is
718 // necessary.
719 JSObject* js_object = JSObject::cast(holder);
720
721 // Check access rights if needed.
722 if (js_object->IsAccessCheckNeeded()) {
723 Isolate* isolate = heap->isolate();
724 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
725 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
726 return heap->undefined_value();
727 }
728 }
729
730 if (js_object->HasIndexedInterceptor()) {
731 return js_object->GetElementWithInterceptor(receiver, index);
732 }
733
734 if (js_object->elements() != heap->empty_fixed_array()) {
735 MaybeObject* result = js_object->GetElementsAccessor()->Get(
736 js_object->elements(),
737 index,
738 js_object,
739 receiver);
740 if (result != heap->the_hole_value()) return result;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100741 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100742 }
743
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000744 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000745}
746
747
748Object* Object::GetPrototype() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100749 if (IsSmi()) {
750 Heap* heap = Isolate::Current()->heap();
751 Context* context = heap->isolate()->context()->global_context();
752 return context->number_function()->instance_prototype();
753 }
754
755 HeapObject* heap_object = HeapObject::cast(this);
756
Ben Murdoch257744e2011-11-30 15:57:28 +0000757 // The object is either a number, a string, a boolean,
758 // a real JS object, or a Harmony proxy.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000759 if (heap_object->IsJSReceiver()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000760 return heap_object->map()->prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100761 }
762 Heap* heap = heap_object->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100763 Context* context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000764
Ben Murdoch8b112d22011-06-08 16:22:53 +0100765 if (heap_object->IsHeapNumber()) {
766 return context->number_function()->instance_prototype();
767 }
768 if (heap_object->IsString()) {
769 return context->string_function()->instance_prototype();
770 }
771 if (heap_object->IsBoolean()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000772 return context->boolean_function()->instance_prototype();
773 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100774 return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000775 }
776}
777
778
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000779MaybeObject* Object::GetHash(CreationFlag flag) {
780 // The object is either a number, a string, an odd-ball,
781 // a real JS object, or a Harmony proxy.
782 if (IsNumber()) {
783 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
784 return Smi::FromInt(hash & Smi::kMaxValue);
785 }
786 if (IsString()) {
787 uint32_t hash = String::cast(this)->Hash();
788 return Smi::FromInt(hash);
789 }
790 if (IsOddball()) {
791 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
792 return Smi::FromInt(hash);
793 }
794 if (IsJSReceiver()) {
795 return JSReceiver::cast(this)->GetIdentityHash(flag);
796 }
797
798 UNREACHABLE();
799 return Smi::FromInt(0);
800}
801
802
803bool Object::SameValue(Object* other) {
804 if (other == this) return true;
805 if (!IsHeapObject() || !other->IsHeapObject()) return false;
806
807 // The object is either a number, a string, an odd-ball,
808 // a real JS object, or a Harmony proxy.
809 if (IsNumber() && other->IsNumber()) {
810 double this_value = Number();
811 double other_value = other->Number();
812 return (this_value == other_value) ||
813 (isnan(this_value) && isnan(other_value));
814 }
815 if (IsString() && other->IsString()) {
816 return String::cast(this)->Equals(String::cast(other));
817 }
818 return false;
819}
820
821
Ben Murdochb0fe1622011-05-05 13:52:32 +0100822void Object::ShortPrint(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000823 HeapStringAllocator allocator;
824 StringStream accumulator(&allocator);
825 ShortPrint(&accumulator);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100826 accumulator.OutputToFile(out);
Steve Blocka7e24c12009-10-30 11:49:00 +0000827}
828
829
830void Object::ShortPrint(StringStream* accumulator) {
831 if (IsSmi()) {
832 Smi::cast(this)->SmiPrint(accumulator);
833 } else if (IsFailure()) {
834 Failure::cast(this)->FailurePrint(accumulator);
835 } else {
836 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
837 }
838}
839
840
Ben Murdochb0fe1622011-05-05 13:52:32 +0100841void Smi::SmiPrint(FILE* out) {
842 PrintF(out, "%d", value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000843}
844
845
846void Smi::SmiPrint(StringStream* accumulator) {
847 accumulator->Add("%d", value());
848}
849
850
851void Failure::FailurePrint(StringStream* accumulator) {
Steve Block3ce2e202009-11-05 08:53:23 +0000852 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000853}
854
855
Ben Murdochb0fe1622011-05-05 13:52:32 +0100856void Failure::FailurePrint(FILE* out) {
857 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000858}
859
860
Steve Blocka7e24c12009-10-30 11:49:00 +0000861// Should a word be prefixed by 'a' or 'an' in order to read naturally in
862// English? Returns false for non-ASCII or words that don't start with
863// a capital letter. The a/an rule follows pronunciation in English.
864// We don't use the BBC's overcorrect "an historic occasion" though if
865// you speak a dialect you may well say "an 'istoric occasion".
866static bool AnWord(String* str) {
867 if (str->length() == 0) return false; // A nothing.
868 int c0 = str->Get(0);
869 int c1 = str->length() > 1 ? str->Get(1) : 0;
870 if (c0 == 'U') {
871 if (c1 > 'Z') {
872 return true; // An Umpire, but a UTF8String, a U.
873 }
874 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
875 return true; // An Ape, an ABCBook.
876 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
877 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
878 c0 == 'S' || c0 == 'X')) {
879 return true; // An MP3File, an M.
880 }
881 return false;
882}
883
884
John Reck59135872010-11-02 12:39:01 -0700885MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000886#ifdef DEBUG
887 // Do not attempt to flatten in debug mode when allocation is not
888 // allowed. This is to avoid an assertion failure when allocating.
889 // Flattening strings is the only case where we always allow
890 // allocation because no GC is performed if the allocation fails.
Steve Block44f0eee2011-05-26 01:26:41 +0100891 if (!HEAP->IsAllocationAllowed()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000892#endif
893
Steve Block44f0eee2011-05-26 01:26:41 +0100894 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000895 switch (StringShape(this).representation_tag()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000896 case kConsStringTag: {
897 ConsString* cs = ConsString::cast(this);
898 if (cs->second()->length() == 0) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100899 return cs->first();
Steve Blocka7e24c12009-10-30 11:49:00 +0000900 }
901 // There's little point in putting the flat string in new space if the
902 // cons string is in old space. It can never get GCed until there is
903 // an old space GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100904 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +0000905 int len = length();
906 Object* object;
907 String* result;
908 if (IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100909 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700910 if (!maybe_object->ToObject(&object)) return maybe_object;
911 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000912 result = String::cast(object);
913 String* first = cs->first();
914 int first_length = first->length();
915 char* dest = SeqAsciiString::cast(result)->GetChars();
916 WriteToFlat(first, dest, 0, first_length);
917 String* second = cs->second();
918 WriteToFlat(second,
919 dest + first_length,
920 0,
921 len - first_length);
922 } else {
John Reck59135872010-11-02 12:39:01 -0700923 { MaybeObject* maybe_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100924 heap->AllocateRawTwoByteString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700925 if (!maybe_object->ToObject(&object)) return maybe_object;
926 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000927 result = String::cast(object);
928 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
929 String* first = cs->first();
930 int first_length = first->length();
931 WriteToFlat(first, dest, 0, first_length);
932 String* second = cs->second();
933 WriteToFlat(second,
934 dest + first_length,
935 0,
936 len - first_length);
937 }
938 cs->set_first(result);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000939 cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
Leon Clarkef7060e22010-06-03 12:02:55 +0100940 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000941 }
942 default:
943 return this;
944 }
945}
946
947
948bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +0100949 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100950 // prohibited by the API.
951 ASSERT(!this->IsExternalString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000952#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000953 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000954 // Assert that the resource and the string are equivalent.
955 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100956 ScopedVector<uc16> smart_chars(this->length());
957 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
958 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000959 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100960 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000961 }
962#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100963 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000964 int size = this->Size(); // Byte size of the original string.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000965 if (size < ExternalString::kShortSize) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000966 return false;
967 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100968 bool is_ascii = this->IsAsciiRepresentation();
Steve Blocka7e24c12009-10-30 11:49:00 +0000969 bool is_symbol = this->IsSymbol();
Steve Blocka7e24c12009-10-30 11:49:00 +0000970
971 // Morph the object to an external string by adjusting the map and
972 // reinitializing the fields.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000973 if (size >= ExternalString::kSize) {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000974 this->set_map_no_write_barrier(
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000975 is_symbol
976 ? (is_ascii ? heap->external_symbol_with_ascii_data_map()
977 : heap->external_symbol_map())
978 : (is_ascii ? heap->external_string_with_ascii_data_map()
979 : heap->external_string_map()));
980 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000981 this->set_map_no_write_barrier(
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000982 is_symbol
983 ? (is_ascii ? heap->short_external_symbol_with_ascii_data_map()
984 : heap->short_external_symbol_map())
985 : (is_ascii ? heap->short_external_string_with_ascii_data_map()
986 : heap->short_external_string_map()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000987 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000988 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
989 self->set_resource(resource);
990 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
Steve Blocka7e24c12009-10-30 11:49:00 +0000991
992 // Fill the remainder of the string with dead wood.
993 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100994 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000995 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000996 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
997 new_size - size);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000998 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000999 return true;
1000}
1001
1002
1003bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
1004#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +00001005 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001006 // Assert that the resource and the string are equivalent.
1007 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +01001008 ScopedVector<char> smart_chars(this->length());
1009 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1010 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001011 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001012 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001013 }
1014#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +01001015 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001016 int size = this->Size(); // Byte size of the original string.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001017 if (size < ExternalString::kShortSize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001018 return false;
1019 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001020 bool is_symbol = this->IsSymbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001021
1022 // Morph the object to an external string by adjusting the map and
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001023 // reinitializing the fields. Use short version if space is limited.
1024 if (size >= ExternalString::kSize) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001025 this->set_map_no_write_barrier(
1026 is_symbol ? heap->external_ascii_symbol_map()
1027 : heap->external_ascii_string_map());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001028 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001029 this->set_map_no_write_barrier(
1030 is_symbol ? heap->short_external_ascii_symbol_map()
1031 : heap->short_external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001032 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001033 ExternalAsciiString* self = ExternalAsciiString::cast(this);
1034 self->set_resource(resource);
1035 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001036
1037 // Fill the remainder of the string with dead wood.
1038 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +01001039 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001040 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001041 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
1042 new_size - size);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001043 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001044 return true;
1045}
1046
1047
1048void String::StringShortPrint(StringStream* accumulator) {
1049 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +00001050 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001051 accumulator->Add("<Very long string[%u]>", len);
1052 return;
1053 }
1054
1055 if (!LooksValid()) {
1056 accumulator->Add("<Invalid String>");
1057 return;
1058 }
1059
1060 StringInputBuffer buf(this);
1061
1062 bool truncated = false;
1063 if (len > kMaxShortPrintLength) {
1064 len = kMaxShortPrintLength;
1065 truncated = true;
1066 }
1067 bool ascii = true;
1068 for (int i = 0; i < len; i++) {
1069 int c = buf.GetNext();
1070
1071 if (c < 32 || c >= 127) {
1072 ascii = false;
1073 }
1074 }
1075 buf.Reset(this);
1076 if (ascii) {
1077 accumulator->Add("<String[%u]: ", length());
1078 for (int i = 0; i < len; i++) {
1079 accumulator->Put(buf.GetNext());
1080 }
1081 accumulator->Put('>');
1082 } else {
1083 // Backslash indicates that the string contains control
1084 // characters and that backslashes are therefore escaped.
1085 accumulator->Add("<String[%u]\\: ", length());
1086 for (int i = 0; i < len; i++) {
1087 int c = buf.GetNext();
1088 if (c == '\n') {
1089 accumulator->Add("\\n");
1090 } else if (c == '\r') {
1091 accumulator->Add("\\r");
1092 } else if (c == '\\') {
1093 accumulator->Add("\\\\");
1094 } else if (c < 32 || c > 126) {
1095 accumulator->Add("\\x%02x", c);
1096 } else {
1097 accumulator->Put(c);
1098 }
1099 }
1100 if (truncated) {
1101 accumulator->Put('.');
1102 accumulator->Put('.');
1103 accumulator->Put('.');
1104 }
1105 accumulator->Put('>');
1106 }
1107 return;
1108}
1109
1110
1111void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1112 switch (map()->instance_type()) {
1113 case JS_ARRAY_TYPE: {
1114 double length = JSArray::cast(this)->length()->Number();
1115 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
1116 break;
1117 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001118 case JS_WEAK_MAP_TYPE: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001119 accumulator->Add("<JS WeakMap>");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001120 break;
1121 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001122 case JS_REGEXP_TYPE: {
1123 accumulator->Add("<JS RegExp>");
1124 break;
1125 }
1126 case JS_FUNCTION_TYPE: {
1127 Object* fun_name = JSFunction::cast(this)->shared()->name();
1128 bool printed = false;
1129 if (fun_name->IsString()) {
1130 String* str = String::cast(fun_name);
1131 if (str->length() > 0) {
1132 accumulator->Add("<JS Function ");
1133 accumulator->Put(str);
1134 accumulator->Put('>');
1135 printed = true;
1136 }
1137 }
1138 if (!printed) {
1139 accumulator->Add("<JS Function>");
1140 }
1141 break;
1142 }
1143 // All other JSObjects are rather similar to each other (JSObject,
1144 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1145 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001146 Map* map_of_this = map();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001147 Heap* heap = GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001148 Object* constructor = map_of_this->constructor();
Steve Blocka7e24c12009-10-30 11:49:00 +00001149 bool printed = false;
1150 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001151 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001152 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1153 } else {
1154 bool global_object = IsJSGlobalProxy();
1155 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001156 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001157 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1158 } else {
1159 Object* constructor_name =
1160 JSFunction::cast(constructor)->shared()->name();
1161 if (constructor_name->IsString()) {
1162 String* str = String::cast(constructor_name);
1163 if (str->length() > 0) {
1164 bool vowel = AnWord(str);
1165 accumulator->Add("<%sa%s ",
1166 global_object ? "Global Object: " : "",
1167 vowel ? "n" : "");
1168 accumulator->Put(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00001169 printed = true;
1170 }
1171 }
1172 }
1173 }
1174 if (!printed) {
1175 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1176 }
1177 }
1178 if (IsJSValue()) {
1179 accumulator->Add(" value = ");
1180 JSValue::cast(this)->value()->ShortPrint(accumulator);
1181 }
1182 accumulator->Put('>');
1183 break;
1184 }
1185 }
1186}
1187
1188
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001189void JSObject::PrintElementsTransition(
1190 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1191 ElementsKind to_kind, FixedArrayBase* to_elements) {
1192 if (from_kind != to_kind) {
1193 PrintF(file, "elements transition [");
1194 PrintElementsKind(file, from_kind);
1195 PrintF(file, " -> ");
1196 PrintElementsKind(file, to_kind);
1197 PrintF(file, "] in ");
1198 JavaScriptFrame::PrintTop(file, false, true);
1199 PrintF(file, " for ");
1200 ShortPrint(file);
1201 PrintF(file, " from ");
1202 from_elements->ShortPrint(file);
1203 PrintF(file, " to ");
1204 to_elements->ShortPrint(file);
1205 PrintF(file, "\n");
1206 }
1207}
1208
1209
Steve Blocka7e24c12009-10-30 11:49:00 +00001210void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
Steve Block44f0eee2011-05-26 01:26:41 +01001211 Heap* heap = GetHeap();
1212 if (!heap->Contains(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001213 accumulator->Add("!!!INVALID POINTER!!!");
1214 return;
1215 }
Steve Block44f0eee2011-05-26 01:26:41 +01001216 if (!heap->Contains(map())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001217 accumulator->Add("!!!INVALID MAP!!!");
1218 return;
1219 }
1220
1221 accumulator->Add("%p ", this);
1222
1223 if (IsString()) {
1224 String::cast(this)->StringShortPrint(accumulator);
1225 return;
1226 }
1227 if (IsJSObject()) {
1228 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1229 return;
1230 }
1231 switch (map()->instance_type()) {
1232 case MAP_TYPE:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001233 accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
Steve Blocka7e24c12009-10-30 11:49:00 +00001234 break;
1235 case FIXED_ARRAY_TYPE:
1236 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1237 break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001238 case FIXED_DOUBLE_ARRAY_TYPE:
1239 accumulator->Add("<FixedDoubleArray[%u]>",
1240 FixedDoubleArray::cast(this)->length());
1241 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001242 case BYTE_ARRAY_TYPE:
1243 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1244 break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001245 case FREE_SPACE_TYPE:
1246 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1247 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001248 case EXTERNAL_PIXEL_ARRAY_TYPE:
1249 accumulator->Add("<ExternalPixelArray[%u]>",
1250 ExternalPixelArray::cast(this)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00001251 break;
Steve Block3ce2e202009-11-05 08:53:23 +00001252 case EXTERNAL_BYTE_ARRAY_TYPE:
1253 accumulator->Add("<ExternalByteArray[%u]>",
1254 ExternalByteArray::cast(this)->length());
1255 break;
1256 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1257 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1258 ExternalUnsignedByteArray::cast(this)->length());
1259 break;
1260 case EXTERNAL_SHORT_ARRAY_TYPE:
1261 accumulator->Add("<ExternalShortArray[%u]>",
1262 ExternalShortArray::cast(this)->length());
1263 break;
1264 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1265 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1266 ExternalUnsignedShortArray::cast(this)->length());
1267 break;
1268 case EXTERNAL_INT_ARRAY_TYPE:
1269 accumulator->Add("<ExternalIntArray[%u]>",
1270 ExternalIntArray::cast(this)->length());
1271 break;
1272 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1273 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1274 ExternalUnsignedIntArray::cast(this)->length());
1275 break;
1276 case EXTERNAL_FLOAT_ARRAY_TYPE:
1277 accumulator->Add("<ExternalFloatArray[%u]>",
1278 ExternalFloatArray::cast(this)->length());
1279 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001280 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1281 accumulator->Add("<ExternalDoubleArray[%u]>",
1282 ExternalDoubleArray::cast(this)->length());
1283 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001284 case SHARED_FUNCTION_INFO_TYPE:
1285 accumulator->Add("<SharedFunctionInfo>");
1286 break;
Steve Block1e0659c2011-05-24 12:43:12 +01001287 case JS_MESSAGE_OBJECT_TYPE:
1288 accumulator->Add("<JSMessageObject>");
1289 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001290#define MAKE_STRUCT_CASE(NAME, Name, name) \
1291 case NAME##_TYPE: \
1292 accumulator->Put('<'); \
1293 accumulator->Add(#Name); \
1294 accumulator->Put('>'); \
1295 break;
1296 STRUCT_LIST(MAKE_STRUCT_CASE)
1297#undef MAKE_STRUCT_CASE
1298 case CODE_TYPE:
1299 accumulator->Add("<Code>");
1300 break;
1301 case ODDBALL_TYPE: {
1302 if (IsUndefined())
1303 accumulator->Add("<undefined>");
1304 else if (IsTheHole())
1305 accumulator->Add("<the hole>");
1306 else if (IsNull())
1307 accumulator->Add("<null>");
1308 else if (IsTrue())
1309 accumulator->Add("<true>");
1310 else if (IsFalse())
1311 accumulator->Add("<false>");
1312 else
1313 accumulator->Add("<Odd Oddball>");
1314 break;
1315 }
1316 case HEAP_NUMBER_TYPE:
1317 accumulator->Add("<Number: ");
1318 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1319 accumulator->Put('>');
1320 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00001321 case JS_PROXY_TYPE:
1322 accumulator->Add("<JSProxy>");
1323 break;
1324 case JS_FUNCTION_PROXY_TYPE:
1325 accumulator->Add("<JSFunctionProxy>");
1326 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001327 case FOREIGN_TYPE:
1328 accumulator->Add("<Foreign>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001329 break;
1330 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1331 accumulator->Add("Cell for ");
1332 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1333 break;
1334 default:
1335 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1336 break;
1337 }
1338}
1339
1340
Steve Blocka7e24c12009-10-30 11:49:00 +00001341void HeapObject::Iterate(ObjectVisitor* v) {
1342 // Handle header
1343 IteratePointer(v, kMapOffset);
1344 // Handle object body
1345 Map* m = map();
1346 IterateBody(m->instance_type(), SizeFromMap(m), v);
1347}
1348
1349
1350void HeapObject::IterateBody(InstanceType type, int object_size,
1351 ObjectVisitor* v) {
1352 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1353 // During GC, the map pointer field is encoded.
1354 if (type < FIRST_NONSTRING_TYPE) {
1355 switch (type & kStringRepresentationMask) {
1356 case kSeqStringTag:
1357 break;
1358 case kConsStringTag:
Iain Merrick75681382010-08-19 15:07:18 +01001359 ConsString::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001360 break;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001361 case kSlicedStringTag:
1362 SlicedString::BodyDescriptor::IterateBody(this, v);
1363 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001364 case kExternalStringTag:
1365 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1366 reinterpret_cast<ExternalAsciiString*>(this)->
1367 ExternalAsciiStringIterateBody(v);
1368 } else {
1369 reinterpret_cast<ExternalTwoByteString*>(this)->
1370 ExternalTwoByteStringIterateBody(v);
1371 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001372 break;
1373 }
1374 return;
1375 }
1376
1377 switch (type) {
1378 case FIXED_ARRAY_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001379 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001380 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001381 case FIXED_DOUBLE_ARRAY_TYPE:
1382 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001383 case JS_OBJECT_TYPE:
1384 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1385 case JS_VALUE_TYPE:
1386 case JS_ARRAY_TYPE:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001387 case JS_SET_TYPE:
1388 case JS_MAP_TYPE:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001389 case JS_WEAK_MAP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001390 case JS_REGEXP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001391 case JS_GLOBAL_PROXY_TYPE:
1392 case JS_GLOBAL_OBJECT_TYPE:
1393 case JS_BUILTINS_OBJECT_TYPE:
Steve Block1e0659c2011-05-24 12:43:12 +01001394 case JS_MESSAGE_OBJECT_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001395 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001396 break;
Steve Block791712a2010-08-27 10:21:07 +01001397 case JS_FUNCTION_TYPE:
1398 reinterpret_cast<JSFunction*>(this)
1399 ->JSFunctionIterateBody(object_size, v);
1400 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001401 case ODDBALL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001402 Oddball::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001403 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001404 case JS_PROXY_TYPE:
1405 JSProxy::BodyDescriptor::IterateBody(this, v);
1406 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00001407 case JS_FUNCTION_PROXY_TYPE:
1408 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1409 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001410 case FOREIGN_TYPE:
1411 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001412 break;
1413 case MAP_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001414 Map::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001415 break;
1416 case CODE_TYPE:
1417 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1418 break;
1419 case JS_GLOBAL_PROPERTY_CELL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001420 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001421 break;
1422 case HEAP_NUMBER_TYPE:
1423 case FILLER_TYPE:
1424 case BYTE_ARRAY_TYPE:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001425 case FREE_SPACE_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01001426 case EXTERNAL_PIXEL_ARRAY_TYPE:
Steve Block3ce2e202009-11-05 08:53:23 +00001427 case EXTERNAL_BYTE_ARRAY_TYPE:
1428 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1429 case EXTERNAL_SHORT_ARRAY_TYPE:
1430 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1431 case EXTERNAL_INT_ARRAY_TYPE:
1432 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1433 case EXTERNAL_FLOAT_ARRAY_TYPE:
Ben Murdoch257744e2011-11-30 15:57:28 +00001434 case EXTERNAL_DOUBLE_ARRAY_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001435 break;
Iain Merrick75681382010-08-19 15:07:18 +01001436 case SHARED_FUNCTION_INFO_TYPE:
1437 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001438 break;
Iain Merrick75681382010-08-19 15:07:18 +01001439
Steve Blocka7e24c12009-10-30 11:49:00 +00001440#define MAKE_STRUCT_CASE(NAME, Name, name) \
1441 case NAME##_TYPE:
1442 STRUCT_LIST(MAKE_STRUCT_CASE)
1443#undef MAKE_STRUCT_CASE
Iain Merrick75681382010-08-19 15:07:18 +01001444 StructBodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001445 break;
1446 default:
1447 PrintF("Unknown type: %d\n", type);
1448 UNREACHABLE();
1449 }
1450}
1451
1452
Steve Blocka7e24c12009-10-30 11:49:00 +00001453Object* HeapNumber::HeapNumberToBoolean() {
1454 // NaN, +0, and -0 should return the false object
Iain Merrick75681382010-08-19 15:07:18 +01001455#if __BYTE_ORDER == __LITTLE_ENDIAN
1456 union IeeeDoubleLittleEndianArchType u;
1457#elif __BYTE_ORDER == __BIG_ENDIAN
1458 union IeeeDoubleBigEndianArchType u;
1459#endif
1460 u.d = value();
1461 if (u.bits.exp == 2047) {
1462 // Detect NaN for IEEE double precision floating point.
1463 if ((u.bits.man_low | u.bits.man_high) != 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001464 return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001465 }
Iain Merrick75681382010-08-19 15:07:18 +01001466 if (u.bits.exp == 0) {
1467 // Detect +0, and -0 for IEEE double precision floating point.
1468 if ((u.bits.man_low | u.bits.man_high) == 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001469 return GetHeap()->false_value();
Iain Merrick75681382010-08-19 15:07:18 +01001470 }
Steve Block44f0eee2011-05-26 01:26:41 +01001471 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001472}
1473
1474
Ben Murdochb0fe1622011-05-05 13:52:32 +01001475void HeapNumber::HeapNumberPrint(FILE* out) {
1476 PrintF(out, "%.16g", Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00001477}
1478
1479
1480void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1481 // The Windows version of vsnprintf can allocate when printing a %g string
1482 // into a buffer that may not be big enough. We don't want random memory
1483 // allocation when producing post-crash stack traces, so we print into a
1484 // buffer that is plenty big enough for any floating point number, then
1485 // print that using vsnprintf (which may truncate but never allocate if
1486 // there is no more space in the buffer).
1487 EmbeddedVector<char, 100> buffer;
1488 OS::SNPrintF(buffer, "%.16g", Number());
1489 accumulator->Add("%s", buffer.start());
1490}
1491
1492
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001493String* JSReceiver::class_name() {
1494 if (IsJSFunction() && IsJSFunctionProxy()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001495 return GetHeap()->function_class_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001496 }
1497 if (map()->constructor()->IsJSFunction()) {
1498 JSFunction* constructor = JSFunction::cast(map()->constructor());
1499 return String::cast(constructor->shared()->instance_class_name());
1500 }
1501 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001502 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001503}
1504
1505
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001506String* JSReceiver::constructor_name() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001507 if (map()->constructor()->IsJSFunction()) {
1508 JSFunction* constructor = JSFunction::cast(map()->constructor());
1509 String* name = String::cast(constructor->shared()->name());
Ben Murdochf87a2032010-10-22 12:50:53 +01001510 if (name->length() > 0) return name;
1511 String* inferred_name = constructor->shared()->inferred_name();
1512 if (inferred_name->length() > 0) return inferred_name;
1513 Object* proto = GetPrototype();
1514 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001515 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001516 // TODO(rossberg): what about proxies?
Steve Blocka7e24c12009-10-30 11:49:00 +00001517 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001518 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001519}
1520
1521
John Reck59135872010-11-02 12:39:01 -07001522MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1523 String* name,
1524 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001525 int index = new_map->PropertyIndexFor(name);
1526 if (map()->unused_property_fields() == 0) {
1527 ASSERT(map()->unused_property_fields() == 0);
1528 int new_unused = new_map->unused_property_fields();
John Reck59135872010-11-02 12:39:01 -07001529 Object* values;
1530 { MaybeObject* maybe_values =
1531 properties()->CopySize(properties()->length() + new_unused + 1);
1532 if (!maybe_values->ToObject(&values)) return maybe_values;
1533 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001534 set_properties(FixedArray::cast(values));
1535 }
1536 set_map(new_map);
1537 return FastPropertyAtPut(index, value);
1538}
1539
1540
Ben Murdoch8b112d22011-06-08 16:22:53 +01001541static bool IsIdentifier(UnicodeCache* cache,
1542 unibrow::CharacterStream* buffer) {
1543 // Checks whether the buffer contains an identifier (no escape).
1544 if (!buffer->has_more()) return false;
1545 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1546 return false;
1547 }
1548 while (buffer->has_more()) {
1549 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1550 return false;
1551 }
1552 }
1553 return true;
1554}
1555
1556
John Reck59135872010-11-02 12:39:01 -07001557MaybeObject* JSObject::AddFastProperty(String* name,
1558 Object* value,
1559 PropertyAttributes attributes) {
Steve Block1e0659c2011-05-24 12:43:12 +01001560 ASSERT(!IsJSGlobalProxy());
1561
Steve Blocka7e24c12009-10-30 11:49:00 +00001562 // Normalize the object if the name is an actual string (not the
1563 // hidden symbols) and is not a real identifier.
Steve Block44f0eee2011-05-26 01:26:41 +01001564 Isolate* isolate = GetHeap()->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00001565 StringInputBuffer buffer(name);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001566 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
Steve Block44f0eee2011-05-26 01:26:41 +01001567 && name != isolate->heap()->hidden_symbol()) {
John Reck59135872010-11-02 12:39:01 -07001568 Object* obj;
1569 { MaybeObject* maybe_obj =
1570 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1571 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1572 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001573 return AddSlowProperty(name, value, attributes);
1574 }
1575
1576 DescriptorArray* old_descriptors = map()->instance_descriptors();
1577 // Compute the new index for new field.
1578 int index = map()->NextFreePropertyIndex();
1579
1580 // Allocate new instance descriptors with (name, index) added
1581 FieldDescriptor new_field(name, index, attributes);
John Reck59135872010-11-02 12:39:01 -07001582 Object* new_descriptors;
1583 { MaybeObject* maybe_new_descriptors =
1584 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1585 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1586 return maybe_new_descriptors;
1587 }
1588 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001589
Steve Block44f0eee2011-05-26 01:26:41 +01001590 // Only allow map transition if the object isn't the global object and there
1591 // is not a transition for the name, or there's a transition for the name but
1592 // it's unrelated to properties.
1593 int descriptor_index = old_descriptors->Search(name);
1594
Ben Murdoch589d6972011-11-30 16:04:58 +00001595 // Element transitions are stored in the descriptor for property "", which is
1596 // not a identifier and should have forced a switch to slow properties above.
Steve Block44f0eee2011-05-26 01:26:41 +01001597 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
Ben Murdoch589d6972011-11-30 16:04:58 +00001598 old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
Steve Block44f0eee2011-05-26 01:26:41 +01001599 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
Ben Murdoch589d6972011-11-30 16:04:58 +00001600 old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
Steve Blocka7e24c12009-10-30 11:49:00 +00001601 bool allow_map_transition =
Steve Block44f0eee2011-05-26 01:26:41 +01001602 can_insert_transition &&
1603 (isolate->context()->global_context()->object_function()->map() != map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001604
1605 ASSERT(index < map()->inobject_properties() ||
1606 (index - map()->inobject_properties()) < properties()->length() ||
1607 map()->unused_property_fields() == 0);
1608 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001609 Object* r;
1610 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1611 if (!maybe_r->ToObject(&r)) return maybe_r;
1612 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001613 Map* new_map = Map::cast(r);
1614 if (allow_map_transition) {
1615 // Allocate new instance descriptors for the old map with map transition.
1616 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
John Reck59135872010-11-02 12:39:01 -07001617 Object* r;
1618 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1619 if (!maybe_r->ToObject(&r)) return maybe_r;
1620 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001621 old_descriptors = DescriptorArray::cast(r);
1622 }
1623
1624 if (map()->unused_property_fields() == 0) {
Steve Block8defd9f2010-07-08 12:39:36 +01001625 if (properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001626 Object* obj;
1627 { MaybeObject* maybe_obj =
1628 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1629 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1630 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001631 return AddSlowProperty(name, value, attributes);
1632 }
1633 // Make room for the new value
John Reck59135872010-11-02 12:39:01 -07001634 Object* values;
1635 { MaybeObject* maybe_values =
1636 properties()->CopySize(properties()->length() + kFieldsAdded);
1637 if (!maybe_values->ToObject(&values)) return maybe_values;
1638 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001639 set_properties(FixedArray::cast(values));
1640 new_map->set_unused_property_fields(kFieldsAdded - 1);
1641 } else {
1642 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1643 }
1644 // We have now allocated all the necessary objects.
1645 // All the changes can be applied at once, so they are atomic.
1646 map()->set_instance_descriptors(old_descriptors);
1647 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1648 set_map(new_map);
1649 return FastPropertyAtPut(index, value);
1650}
1651
1652
John Reck59135872010-11-02 12:39:01 -07001653MaybeObject* JSObject::AddConstantFunctionProperty(
1654 String* name,
1655 JSFunction* function,
1656 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001657 // Allocate new instance descriptors with (name, function) added
1658 ConstantFunctionDescriptor d(name, function, attributes);
John Reck59135872010-11-02 12:39:01 -07001659 Object* new_descriptors;
1660 { MaybeObject* maybe_new_descriptors =
1661 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1662 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1663 return maybe_new_descriptors;
1664 }
1665 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001666
1667 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001668 Object* new_map;
1669 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1670 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1671 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001672
1673 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1674 Map::cast(new_map)->set_instance_descriptors(descriptors);
1675 Map* old_map = map();
1676 set_map(Map::cast(new_map));
1677
1678 // If the old map is the global object map (from new Object()),
1679 // then transitions are not added to it, so we are done.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001680 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01001681 if (old_map == heap->isolate()->context()->global_context()->
1682 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001683 return function;
1684 }
1685
1686 // Do not add CONSTANT_TRANSITIONS to global objects
1687 if (IsGlobalObject()) {
1688 return function;
1689 }
1690
1691 // Add a CONSTANT_TRANSITION descriptor to the old map,
1692 // so future assignments to this property on other objects
1693 // of the same type will create a normal field, not a constant function.
1694 // Don't do this for special properties, with non-trival attributes.
1695 if (attributes != NONE) {
1696 return function;
1697 }
Iain Merrick75681382010-08-19 15:07:18 +01001698 ConstTransitionDescriptor mark(name, Map::cast(new_map));
John Reck59135872010-11-02 12:39:01 -07001699 { MaybeObject* maybe_new_descriptors =
1700 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1701 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1702 // We have accomplished the main goal, so return success.
1703 return function;
1704 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001705 }
1706 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1707
1708 return function;
1709}
1710
1711
1712// Add property in slow mode
John Reck59135872010-11-02 12:39:01 -07001713MaybeObject* JSObject::AddSlowProperty(String* name,
1714 Object* value,
1715 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001716 ASSERT(!HasFastProperties());
1717 StringDictionary* dict = property_dictionary();
1718 Object* store_value = value;
1719 if (IsGlobalObject()) {
1720 // In case name is an orphaned property reuse the cell.
1721 int entry = dict->FindEntry(name);
1722 if (entry != StringDictionary::kNotFound) {
1723 store_value = dict->ValueAt(entry);
1724 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1725 // Assign an enumeration index to the property and update
1726 // SetNextEnumerationIndex.
1727 int index = dict->NextEnumerationIndex();
1728 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1729 dict->SetNextEnumerationIndex(index + 1);
1730 dict->SetEntry(entry, name, store_value, details);
1731 return value;
1732 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001733 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07001734 { MaybeObject* maybe_store_value =
Steve Block44f0eee2011-05-26 01:26:41 +01001735 heap->AllocateJSGlobalPropertyCell(value);
John Reck59135872010-11-02 12:39:01 -07001736 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1737 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001738 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1739 }
1740 PropertyDetails details = PropertyDetails(attributes, NORMAL);
John Reck59135872010-11-02 12:39:01 -07001741 Object* result;
1742 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1743 if (!maybe_result->ToObject(&result)) return maybe_result;
1744 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001745 if (dict != result) set_properties(StringDictionary::cast(result));
1746 return value;
1747}
1748
1749
John Reck59135872010-11-02 12:39:01 -07001750MaybeObject* JSObject::AddProperty(String* name,
1751 Object* value,
Steve Block44f0eee2011-05-26 01:26:41 +01001752 PropertyAttributes attributes,
1753 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001754 ASSERT(!IsJSGlobalProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001755 Map* map_of_this = map();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001756 Heap* heap = GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001757 if (!map_of_this->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001758 if (strict_mode == kNonStrictMode) {
1759 return heap->undefined_value();
1760 } else {
1761 Handle<Object> args[1] = {Handle<String>(name)};
1762 return heap->isolate()->Throw(
1763 *FACTORY->NewTypeError("object_not_extensible",
1764 HandleVector(args, 1)));
1765 }
Steve Block8defd9f2010-07-08 12:39:36 +01001766 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001767 if (HasFastProperties()) {
1768 // Ensure the descriptor array does not get too big.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001769 if (map_of_this->instance_descriptors()->number_of_descriptors() <
Steve Blocka7e24c12009-10-30 11:49:00 +00001770 DescriptorArray::kMaxNumberOfDescriptors) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00001771 if (value->IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001772 return AddConstantFunctionProperty(name,
1773 JSFunction::cast(value),
1774 attributes);
1775 } else {
1776 return AddFastProperty(name, value, attributes);
1777 }
1778 } else {
1779 // Normalize the object to prevent very large instance descriptors.
1780 // This eliminates unwanted N^2 allocation and lookup behavior.
John Reck59135872010-11-02 12:39:01 -07001781 Object* obj;
1782 { MaybeObject* maybe_obj =
1783 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1784 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1785 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001786 }
1787 }
1788 return AddSlowProperty(name, value, attributes);
1789}
1790
1791
John Reck59135872010-11-02 12:39:01 -07001792MaybeObject* JSObject::SetPropertyPostInterceptor(
1793 String* name,
1794 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001795 PropertyAttributes attributes,
1796 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001797 // Check local property, ignore interceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001798 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001799 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001800 if (result.IsFound()) {
1801 // An existing property, a map transition or a null descriptor was
1802 // found. Use set property to handle all these cases.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001803 return SetProperty(&result, name, value, attributes, strict_mode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001804 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001805 bool found = false;
1806 MaybeObject* result_object;
1807 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
1808 value,
1809 attributes,
1810 &found,
1811 strict_mode);
1812 if (found) return result_object;
Andrei Popescu402d9372010-02-26 13:31:12 +00001813 // Add a new real property.
Steve Block44f0eee2011-05-26 01:26:41 +01001814 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001815}
1816
1817
John Reck59135872010-11-02 12:39:01 -07001818MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1819 Object* value,
1820 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001821 StringDictionary* dictionary = property_dictionary();
1822 int old_index = dictionary->FindEntry(name);
1823 int new_enumeration_index = 0; // 0 means "Use the next available index."
1824 if (old_index != -1) {
1825 // All calls to ReplaceSlowProperty have had all transitions removed.
1826 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1827 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1828 }
1829
1830 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1831 return SetNormalizedProperty(name, value, new_details);
1832}
1833
Steve Blockd0582a62009-12-15 09:54:21 +00001834
John Reck59135872010-11-02 12:39:01 -07001835MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
Steve Blocka7e24c12009-10-30 11:49:00 +00001836 String* name,
1837 Object* new_value,
1838 PropertyAttributes attributes) {
1839 Map* old_map = map();
John Reck59135872010-11-02 12:39:01 -07001840 Object* result;
1841 { MaybeObject* maybe_result =
1842 ConvertDescriptorToField(name, new_value, attributes);
1843 if (!maybe_result->ToObject(&result)) return maybe_result;
1844 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001845 // If we get to this point we have succeeded - do not return failure
1846 // after this point. Later stuff is optional.
1847 if (!HasFastProperties()) {
1848 return result;
1849 }
1850 // Do not add transitions to the map of "new Object()".
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001851 if (map() == GetIsolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01001852 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001853 return result;
1854 }
1855
1856 MapTransitionDescriptor transition(name,
1857 map(),
1858 attributes);
John Reck59135872010-11-02 12:39:01 -07001859 Object* new_descriptors;
1860 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1861 CopyInsert(&transition, KEEP_TRANSITIONS);
1862 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1863 return result; // Yes, return _result_.
1864 }
1865 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001866 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1867 return result;
1868}
1869
1870
John Reck59135872010-11-02 12:39:01 -07001871MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1872 Object* new_value,
1873 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001874 if (map()->unused_property_fields() == 0 &&
Steve Block8defd9f2010-07-08 12:39:36 +01001875 properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001876 Object* obj;
1877 { MaybeObject* maybe_obj =
1878 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1879 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1880 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001881 return ReplaceSlowProperty(name, new_value, attributes);
1882 }
1883
1884 int index = map()->NextFreePropertyIndex();
1885 FieldDescriptor new_field(name, index, attributes);
1886 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
John Reck59135872010-11-02 12:39:01 -07001887 Object* descriptors_unchecked;
1888 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1889 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1890 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1891 return maybe_descriptors_unchecked;
1892 }
1893 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001894 DescriptorArray* new_descriptors =
1895 DescriptorArray::cast(descriptors_unchecked);
1896
1897 // Make a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001898 Object* new_map_unchecked;
1899 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1900 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1901 return maybe_new_map_unchecked;
1902 }
1903 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001904 Map* new_map = Map::cast(new_map_unchecked);
1905 new_map->set_instance_descriptors(new_descriptors);
1906
1907 // Make new properties array if necessary.
1908 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1909 int new_unused_property_fields = map()->unused_property_fields() - 1;
1910 if (map()->unused_property_fields() == 0) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001911 new_unused_property_fields = kFieldsAdded - 1;
John Reck59135872010-11-02 12:39:01 -07001912 Object* new_properties_object;
1913 { MaybeObject* maybe_new_properties_object =
1914 properties()->CopySize(properties()->length() + kFieldsAdded);
1915 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1916 return maybe_new_properties_object;
1917 }
1918 }
1919 new_properties = FixedArray::cast(new_properties_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001920 }
1921
1922 // Update pointers to commit changes.
1923 // Object points to the new map.
1924 new_map->set_unused_property_fields(new_unused_property_fields);
1925 set_map(new_map);
1926 if (new_properties) {
1927 set_properties(FixedArray::cast(new_properties));
1928 }
1929 return FastPropertyAtPut(index, new_value);
1930}
1931
1932
1933
John Reck59135872010-11-02 12:39:01 -07001934MaybeObject* JSObject::SetPropertyWithInterceptor(
1935 String* name,
1936 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001937 PropertyAttributes attributes,
1938 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001939 Isolate* isolate = GetIsolate();
1940 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001941 Handle<JSObject> this_handle(this);
1942 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001943 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001944 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1945 if (!interceptor->setter()->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001946 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1947 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001948 v8::AccessorInfo info(args.end());
1949 v8::NamedPropertySetter setter =
1950 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1951 v8::Handle<v8::Value> result;
1952 {
1953 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001954 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001955 Handle<Object> value_unhole(value->IsTheHole() ?
Steve Block44f0eee2011-05-26 01:26:41 +01001956 isolate->heap()->undefined_value() :
1957 value,
1958 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001959 result = setter(v8::Utils::ToLocal(name_handle),
1960 v8::Utils::ToLocal(value_unhole),
1961 info);
1962 }
Steve Block44f0eee2011-05-26 01:26:41 +01001963 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001964 if (!result.IsEmpty()) return *value_handle;
1965 }
John Reck59135872010-11-02 12:39:01 -07001966 MaybeObject* raw_result =
1967 this_handle->SetPropertyPostInterceptor(*name_handle,
1968 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001969 attributes,
1970 strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001971 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001972 return raw_result;
1973}
1974
1975
Ben Murdochc7cc0282012-03-05 14:35:55 +00001976Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
1977 Handle<String> key,
1978 Handle<Object> value,
1979 PropertyAttributes attributes,
1980 StrictModeFlag strict_mode) {
1981 CALL_HEAP_FUNCTION(object->GetIsolate(),
1982 object->SetProperty(*key, *value, attributes, strict_mode),
1983 Object);
1984}
1985
1986
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001987MaybeObject* JSReceiver::SetProperty(String* name,
1988 Object* value,
1989 PropertyAttributes attributes,
1990 StrictModeFlag strict_mode) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001991 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001992 LocalLookup(name, &result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001993 return SetProperty(&result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001994}
1995
1996
John Reck59135872010-11-02 12:39:01 -07001997MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1998 String* name,
1999 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002000 JSObject* holder,
2001 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002002 Isolate* isolate = GetIsolate();
2003 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002004
2005 // We should never get here to initialize a const with the hole
2006 // value since a const declaration would conflict with the setter.
2007 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01002008 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002009
2010 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00002011 // data structure used to store the callbacks. Eventually foreign
Steve Blocka7e24c12009-10-30 11:49:00 +00002012 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00002013 if (structure->IsForeign()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002014 AccessorDescriptor* callback =
Ben Murdoch257744e2011-11-30 15:57:28 +00002015 reinterpret_cast<AccessorDescriptor*>(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002016 Foreign::cast(structure)->foreign_address());
John Reck59135872010-11-02 12:39:01 -07002017 MaybeObject* obj = (callback->setter)(this, value, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +01002018 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002019 if (obj->IsFailure()) return obj;
2020 return *value_handle;
2021 }
2022
2023 if (structure->IsAccessorInfo()) {
2024 // api style callbacks
2025 AccessorInfo* data = AccessorInfo::cast(structure);
2026 Object* call_obj = data->setter();
2027 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
2028 if (call_fun == NULL) return value;
2029 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002030 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
2031 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Steve Blocka7e24c12009-10-30 11:49:00 +00002032 v8::AccessorInfo info(args.end());
2033 {
2034 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002035 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002036 call_fun(v8::Utils::ToLocal(key),
2037 v8::Utils::ToLocal(value_handle),
2038 info);
2039 }
Steve Block44f0eee2011-05-26 01:26:41 +01002040 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002041 return *value_handle;
2042 }
2043
Ben Murdochc7cc0282012-03-05 14:35:55 +00002044 if (structure->IsAccessorPair()) {
2045 Object* setter = AccessorPair::cast(structure)->setter();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002046 if (setter->IsSpecFunction()) {
2047 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2048 return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002049 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002050 if (strict_mode == kNonStrictMode) {
2051 return value;
2052 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002053 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002054 Handle<Object> holder_handle(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002055 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01002056 return isolate->Throw(
2057 *isolate->factory()->NewTypeError("no_setter_in_callback",
2058 HandleVector(args, 2)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002059 }
2060 }
2061
2062 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +01002063 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00002064}
2065
2066
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002067MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
2068 Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01002069 Isolate* isolate = GetIsolate();
2070 Handle<Object> value_handle(value, isolate);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002071 Handle<JSReceiver> fun(setter, isolate);
2072 Handle<JSReceiver> self(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002073#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01002074 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00002075 // Handle stepping into a setter if step into is active.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002076 // TODO(rossberg): should this apply to getters that are function proxies?
2077 if (debug->StepInActive() && fun->IsJSFunction()) {
2078 debug->HandleStepIn(
2079 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00002080 }
2081#endif
2082 bool has_pending_exception;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002083 Handle<Object> argv[] = { value_handle };
2084 Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +00002085 // Check for pending exception and return the result.
2086 if (has_pending_exception) return Failure::Exception();
2087 return *value_handle;
2088}
2089
2090
2091void JSObject::LookupCallbackSetterInPrototypes(String* name,
2092 LookupResult* result) {
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 return result->HandlerResult(JSProxy::cast(pt));
2099 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002100 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002101 if (result->IsProperty()) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01002102 if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
2103 // Found non-callback or read-only callback, stop looking.
2104 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002105 }
2106 }
2107 result->NotFound();
2108}
2109
2110
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002111MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
2112 uint32_t index,
2113 Object* value,
2114 bool* found,
2115 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002116 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002117 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002118 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002119 pt = pt->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002120 if (pt->IsJSProxy()) {
2121 String* name;
2122 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
2123 if (!maybe->To<String>(&name)) {
2124 *found = true; // Force abort
2125 return maybe;
2126 }
2127 return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
2128 name, value, NONE, strict_mode, found);
2129 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002130 if (!JSObject::cast(pt)->HasDictionaryElements()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002131 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00002132 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00002133 SeededNumberDictionary* dictionary =
2134 JSObject::cast(pt)->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +00002135 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00002136 if (entry != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002137 PropertyDetails details = dictionary->DetailsAt(entry);
2138 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01002139 *found = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002140 return SetElementWithCallback(dictionary->ValueAt(entry),
2141 index,
2142 value,
2143 JSObject::cast(pt),
2144 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002145 }
2146 }
2147 }
Steve Block1e0659c2011-05-24 12:43:12 +01002148 *found = false;
Steve Block44f0eee2011-05-26 01:26:41 +01002149 return heap->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002150}
2151
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002152MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
2153 String* name,
2154 Object* value,
2155 PropertyAttributes attributes,
2156 bool* found,
2157 StrictModeFlag strict_mode) {
2158 Heap* heap = GetHeap();
2159 // We could not find a local property so let's check whether there is an
2160 // accessor that wants to handle the property.
2161 LookupResult accessor_result(heap->isolate());
2162 LookupCallbackSetterInPrototypes(name, &accessor_result);
2163 if (accessor_result.IsFound()) {
2164 *found = true;
2165 if (accessor_result.type() == CALLBACKS) {
2166 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2167 name,
2168 value,
2169 accessor_result.holder(),
2170 strict_mode);
2171 } else if (accessor_result.type() == HANDLER) {
2172 // There is a proxy in the prototype chain. Invoke its
2173 // getPropertyDescriptor trap.
2174 bool found = false;
2175 // SetPropertyWithHandlerIfDefiningSetter can cause GC,
2176 // make sure to use the handlified references after calling
2177 // the function.
2178 Handle<JSObject> self(this);
2179 Handle<String> hname(name);
2180 Handle<Object> hvalue(value);
2181 MaybeObject* result =
2182 accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
2183 name, value, attributes, strict_mode, &found);
2184 if (found) return result;
2185 // The proxy does not define the property as an accessor.
2186 // Consequently, it has no effect on setting the receiver.
2187 return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
2188 }
2189 }
2190 *found = false;
2191 return heap->the_hole_value();
2192}
2193
Steve Blocka7e24c12009-10-30 11:49:00 +00002194
2195void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
2196 DescriptorArray* descriptors = map()->instance_descriptors();
Iain Merrick75681382010-08-19 15:07:18 +01002197 int number = descriptors->SearchWithCache(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00002198 if (number != DescriptorArray::kNotFound) {
2199 result->DescriptorResult(this, descriptors->GetDetails(number), number);
2200 } else {
2201 result->NotFound();
2202 }
2203}
2204
2205
Ben Murdochb0fe1622011-05-05 13:52:32 +01002206void Map::LookupInDescriptors(JSObject* holder,
2207 String* name,
2208 LookupResult* result) {
2209 DescriptorArray* descriptors = instance_descriptors();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002210 DescriptorLookupCache* cache =
2211 GetHeap()->isolate()->descriptor_lookup_cache();
Steve Block44f0eee2011-05-26 01:26:41 +01002212 int number = cache->Lookup(descriptors, name);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002213 if (number == DescriptorLookupCache::kAbsent) {
2214 number = descriptors->Search(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002215 cache->Update(descriptors, name, number);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002216 }
2217 if (number != DescriptorArray::kNotFound) {
2218 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
2219 } else {
2220 result->NotFound();
2221 }
2222}
2223
2224
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002225static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2226 ASSERT(!map.is_null());
2227 for (int i = 0; i < maps->length(); ++i) {
2228 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2229 }
2230 return false;
2231}
Steve Block44f0eee2011-05-26 01:26:41 +01002232
Steve Block44f0eee2011-05-26 01:26:41 +01002233
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002234template <class T>
2235static Handle<T> MaybeNull(T* p) {
2236 if (p == NULL) return Handle<T>::null();
2237 return Handle<T>(p);
2238}
2239
2240
2241Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
2242 ElementsKind elms_kind = elements_kind();
2243 if (elms_kind == FAST_DOUBLE_ELEMENTS) {
2244 bool dummy = true;
2245 Handle<Map> fast_map =
2246 MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
2247 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2248 return fast_map;
Steve Block44f0eee2011-05-26 01:26:41 +01002249 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002250 return Handle<Map>::null();
2251 }
2252 if (elms_kind == FAST_SMI_ONLY_ELEMENTS) {
2253 bool dummy = true;
2254 Handle<Map> double_map =
2255 MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy));
2256 // In the current implementation, if the DOUBLE map doesn't exist, the
2257 // FAST map can't exist either.
2258 if (double_map.is_null()) return Handle<Map>::null();
2259 Handle<Map> fast_map =
2260 MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2261 &dummy));
2262 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2263 return fast_map;
2264 }
2265 if (ContainsMap(candidates, double_map)) return double_map;
2266 }
2267 return Handle<Map>::null();
2268}
Steve Block44f0eee2011-05-26 01:26:41 +01002269
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002270static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
2271 ElementsKind elements_kind) {
2272 if (descriptor_contents->IsMap()) {
2273 Map* map = Map::cast(descriptor_contents);
2274 if (map->elements_kind() == elements_kind) {
2275 return map;
2276 }
2277 return NULL;
2278 }
2279
2280 FixedArray* map_array = FixedArray::cast(descriptor_contents);
2281 for (int i = 0; i < map_array->length(); ++i) {
2282 Object* current = map_array->get(i);
2283 // Skip undefined slots, they are sentinels for reclaimed maps.
2284 if (!current->IsUndefined()) {
2285 Map* current_map = Map::cast(map_array->get(i));
2286 if (current_map->elements_kind() == elements_kind) {
2287 return current_map;
Steve Block44f0eee2011-05-26 01:26:41 +01002288 }
2289 }
2290 }
2291
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002292 return NULL;
2293}
2294
2295
2296static MaybeObject* AddElementsTransitionMapToDescriptor(
2297 Object* descriptor_contents,
2298 Map* new_map) {
2299 // Nothing was in the descriptor for an ELEMENTS_TRANSITION,
2300 // simply add the map.
2301 if (descriptor_contents == NULL) {
2302 return new_map;
2303 }
2304
2305 // There was already a map in the descriptor, create a 2-element FixedArray
2306 // to contain the existing map plus the new one.
2307 FixedArray* new_array;
2308 Heap* heap = new_map->GetHeap();
2309 if (descriptor_contents->IsMap()) {
2310 // Must tenure, DescriptorArray expects no new-space objects.
2311 MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED);
2312 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2313 return maybe_new_array;
2314 }
2315 new_array->set(0, descriptor_contents);
2316 new_array->set(1, new_map);
2317 return new_array;
2318 }
2319
2320 // The descriptor already contained a list of maps for different ElementKinds
2321 // of ELEMENTS_TRANSITION, first check the existing array for an undefined
2322 // slot, and if that's not available, create a FixedArray to hold the existing
2323 // maps plus the new one and fill it in.
2324 FixedArray* array = FixedArray::cast(descriptor_contents);
2325 for (int i = 0; i < array->length(); ++i) {
2326 if (array->get(i)->IsUndefined()) {
2327 array->set(i, new_map);
2328 return array;
2329 }
2330 }
2331
2332 // Must tenure, DescriptorArray expects no new-space objects.
2333 MaybeObject* maybe_new_array =
2334 heap->AllocateFixedArray(array->length() + 1, TENURED);
2335 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2336 return maybe_new_array;
2337 }
2338 int i = 0;
2339 while (i < array->length()) {
2340 new_array->set(i, array->get(i));
2341 ++i;
2342 }
2343 new_array->set(i, new_map);
2344 return new_array;
2345}
2346
2347
2348String* Map::elements_transition_sentinel_name() {
2349 return GetHeap()->empty_symbol();
2350}
2351
2352
2353Object* Map::GetDescriptorContents(String* sentinel_name,
2354 bool* safe_to_add_transition) {
2355 // Get the cached index for the descriptors lookup, or find and cache it.
2356 DescriptorArray* descriptors = instance_descriptors();
2357 DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache();
2358 int index = cache->Lookup(descriptors, sentinel_name);
2359 if (index == DescriptorLookupCache::kAbsent) {
2360 index = descriptors->Search(sentinel_name);
2361 cache->Update(descriptors, sentinel_name, index);
2362 }
2363 // If the transition already exists, return its descriptor.
2364 if (index != DescriptorArray::kNotFound) {
2365 PropertyDetails details(descriptors->GetDetails(index));
2366 if (details.type() == ELEMENTS_TRANSITION) {
2367 return descriptors->GetValue(index);
2368 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00002369 if (safe_to_add_transition != NULL) {
2370 *safe_to_add_transition = false;
2371 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002372 }
2373 }
2374 return NULL;
2375}
2376
2377
2378Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
2379 bool* safe_to_add_transition) {
2380 // Special case: indirect SMI->FAST transition (cf. comment in
2381 // AddElementsTransition()).
2382 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2383 elements_kind == FAST_ELEMENTS) {
2384 Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
2385 safe_to_add_transition);
2386 if (double_map == NULL) return double_map;
2387 return double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2388 safe_to_add_transition);
2389 }
2390 Object* descriptor_contents = GetDescriptorContents(
2391 elements_transition_sentinel_name(), safe_to_add_transition);
2392 if (descriptor_contents != NULL) {
2393 Map* maybe_transition_map =
2394 GetElementsTransitionMapFromDescriptor(descriptor_contents,
2395 elements_kind);
2396 ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
2397 return maybe_transition_map;
2398 }
2399 return NULL;
2400}
2401
2402
2403MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
2404 Map* transitioned_map) {
2405 // The map transition graph should be a tree, therefore the transition
2406 // from SMI to FAST elements is not done directly, but by going through
2407 // DOUBLE elements first.
2408 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2409 elements_kind == FAST_ELEMENTS) {
2410 bool safe_to_add = true;
2411 Map* double_map = this->LookupElementsTransitionMap(
2412 FAST_DOUBLE_ELEMENTS, &safe_to_add);
2413 // This method is only called when safe_to_add_transition has been found
2414 // to be true earlier.
2415 ASSERT(safe_to_add);
2416
2417 if (double_map == NULL) {
2418 MaybeObject* maybe_map = this->CopyDropTransitions();
2419 if (!maybe_map->To(&double_map)) return maybe_map;
2420 double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
2421 MaybeObject* maybe_double_transition = this->AddElementsTransition(
2422 FAST_DOUBLE_ELEMENTS, double_map);
2423 if (maybe_double_transition->IsFailure()) return maybe_double_transition;
2424 }
2425 return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map);
2426 }
2427
2428 bool safe_to_add_transition = true;
2429 Object* descriptor_contents = GetDescriptorContents(
2430 elements_transition_sentinel_name(), &safe_to_add_transition);
2431 // This method is only called when safe_to_add_transition has been found
2432 // to be true earlier.
2433 ASSERT(safe_to_add_transition);
2434 MaybeObject* maybe_new_contents =
2435 AddElementsTransitionMapToDescriptor(descriptor_contents,
2436 transitioned_map);
2437 Object* new_contents;
2438 if (!maybe_new_contents->ToObject(&new_contents)) {
2439 return maybe_new_contents;
2440 }
2441
2442 ElementsTransitionDescriptor desc(elements_transition_sentinel_name(),
2443 new_contents);
2444 Object* new_descriptors;
2445 MaybeObject* maybe_new_descriptors =
2446 instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS);
2447 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2448 return maybe_new_descriptors;
2449 }
2450 set_instance_descriptors(DescriptorArray::cast(new_descriptors));
2451 return this;
2452}
2453
2454
2455Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
2456 ElementsKind to_kind) {
2457 Isolate* isolate = object->GetIsolate();
2458 CALL_HEAP_FUNCTION(isolate,
2459 object->GetElementsTransitionMap(to_kind),
2460 Map);
2461}
2462
2463
2464MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind to_kind) {
2465 Map* current_map = map();
2466 ElementsKind from_kind = current_map->elements_kind();
2467
2468 if (from_kind == to_kind) return current_map;
2469
2470 // Only objects with FastProperties can have DescriptorArrays and can track
2471 // element-related maps. Also don't add descriptors to maps that are shared.
2472 bool safe_to_add_transition = HasFastProperties() &&
2473 !current_map->IsUndefined() &&
2474 !current_map->is_shared();
2475
2476 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
2477 // with elements that switch back and forth between dictionary and fast
2478 // element mode.
2479 if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
2480 safe_to_add_transition = false;
2481 }
2482
2483 if (safe_to_add_transition) {
2484 // It's only safe to manipulate the descriptor array if it would be
2485 // safe to add a transition.
2486 Map* maybe_transition_map = current_map->LookupElementsTransitionMap(
2487 to_kind, &safe_to_add_transition);
2488 if (maybe_transition_map != NULL) {
2489 return maybe_transition_map;
2490 }
2491 }
2492
2493 Map* new_map = NULL;
2494
Ben Murdoch589d6972011-11-30 16:04:58 +00002495 // No transition to an existing map for the given ElementsKind. Make a new
2496 // one.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002497 { MaybeObject* maybe_map = current_map->CopyDropTransitions();
2498 if (!maybe_map->To(&new_map)) return maybe_map;
Steve Block44f0eee2011-05-26 01:26:41 +01002499 }
Steve Block44f0eee2011-05-26 01:26:41 +01002500
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002501 new_map->set_elements_kind(to_kind);
Steve Block44f0eee2011-05-26 01:26:41 +01002502
2503 // Only remember the map transition if the object's map is NOT equal to the
2504 // global object_function's map and there is not an already existing
Ben Murdoch589d6972011-11-30 16:04:58 +00002505 // non-matching element transition.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002506 bool allow_map_transition = safe_to_add_transition &&
Steve Block44f0eee2011-05-26 01:26:41 +01002507 (GetIsolate()->context()->global_context()->object_function()->map() !=
2508 map());
2509 if (allow_map_transition) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002510 MaybeObject* maybe_transition =
2511 current_map->AddElementsTransition(to_kind, new_map);
2512 if (maybe_transition->IsFailure()) return maybe_transition;
Steve Block44f0eee2011-05-26 01:26:41 +01002513 }
Steve Block44f0eee2011-05-26 01:26:41 +01002514 return new_map;
2515}
2516
2517
Steve Blocka7e24c12009-10-30 11:49:00 +00002518void JSObject::LocalLookupRealNamedProperty(String* name,
2519 LookupResult* result) {
2520 if (IsJSGlobalProxy()) {
2521 Object* proto = GetPrototype();
2522 if (proto->IsNull()) return result->NotFound();
2523 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002524 // A GlobalProxy's prototype should always be a proper JSObject.
Steve Blocka7e24c12009-10-30 11:49:00 +00002525 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2526 }
2527
2528 if (HasFastProperties()) {
2529 LookupInDescriptor(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002530 if (result->IsFound()) {
2531 // A property, a map transition or a null descriptor was found.
2532 // We return all of these result types because
2533 // LocalLookupRealNamedProperty is used when setting properties
2534 // where map transitions and null descriptors are handled.
Steve Blocka7e24c12009-10-30 11:49:00 +00002535 ASSERT(result->holder() == this && result->type() != NORMAL);
2536 // Disallow caching for uninitialized constants. These can only
2537 // occur as fields.
2538 if (result->IsReadOnly() && result->type() == FIELD &&
2539 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2540 result->DisallowCaching();
2541 }
2542 return;
2543 }
2544 } else {
2545 int entry = property_dictionary()->FindEntry(name);
2546 if (entry != StringDictionary::kNotFound) {
2547 Object* value = property_dictionary()->ValueAt(entry);
2548 if (IsGlobalObject()) {
2549 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2550 if (d.IsDeleted()) {
2551 result->NotFound();
2552 return;
2553 }
2554 value = JSGlobalPropertyCell::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002555 }
2556 // Make sure to disallow caching for uninitialized constants
2557 // found in the dictionary-mode objects.
2558 if (value->IsTheHole()) result->DisallowCaching();
2559 result->DictionaryResult(this, entry);
2560 return;
2561 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002562 }
2563 result->NotFound();
2564}
2565
2566
2567void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2568 LocalLookupRealNamedProperty(name, result);
2569 if (result->IsProperty()) return;
2570
2571 LookupRealNamedPropertyInPrototypes(name, result);
2572}
2573
2574
2575void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2576 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01002577 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002578 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002579 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002580 pt = JSObject::cast(pt)->GetPrototype()) {
2581 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002582 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002583 }
2584 result->NotFound();
2585}
2586
2587
2588// We only need to deal with CALLBACKS and INTERCEPTORS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002589MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2590 LookupResult* result,
2591 String* name,
2592 Object* value,
2593 bool check_prototype,
2594 StrictModeFlag strict_mode) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002595 if (check_prototype && !result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002596 LookupCallbackSetterInPrototypes(name, result);
2597 }
2598
2599 if (result->IsProperty()) {
2600 if (!result->IsReadOnly()) {
2601 switch (result->type()) {
2602 case CALLBACKS: {
2603 Object* obj = result->GetCallbackObject();
2604 if (obj->IsAccessorInfo()) {
2605 AccessorInfo* info = AccessorInfo::cast(obj);
2606 if (info->all_can_write()) {
2607 return SetPropertyWithCallback(result->GetCallbackObject(),
2608 name,
2609 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002610 result->holder(),
2611 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002612 }
2613 }
2614 break;
2615 }
2616 case INTERCEPTOR: {
2617 // Try lookup real named properties. Note that only property can be
2618 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002619 LookupResult r(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002620 LookupRealNamedProperty(name, &r);
2621 if (r.IsProperty()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002622 return SetPropertyWithFailedAccessCheck(&r,
2623 name,
2624 value,
2625 check_prototype,
2626 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002627 }
2628 break;
2629 }
2630 default: {
2631 break;
2632 }
2633 }
2634 }
2635 }
2636
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002637 Isolate* isolate = GetIsolate();
2638 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002639 Handle<Object> value_handle(value);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002640 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
Iain Merrick75681382010-08-19 15:07:18 +01002641 return *value_handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00002642}
2643
2644
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002645MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2646 String* key,
2647 Object* value,
2648 PropertyAttributes attributes,
2649 StrictModeFlag strict_mode) {
2650 if (result->IsFound() && result->type() == HANDLER) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002651 return result->proxy()->SetPropertyWithHandler(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002652 key, value, attributes, strict_mode);
2653 } else {
2654 return JSObject::cast(this)->SetPropertyForResult(
2655 result, key, value, attributes, strict_mode);
2656 }
2657}
2658
2659
2660bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2661 Isolate* isolate = GetIsolate();
2662 HandleScope scope(isolate);
2663 Handle<Object> receiver(this);
2664 Handle<Object> name(name_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002665
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002666 Handle<Object> args[] = { name };
2667 Handle<Object> result = CallTrap(
2668 "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002669 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002670
2671 return result->ToBoolean()->IsTrue();
2672}
2673
2674
2675MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2676 String* name_raw,
2677 Object* value_raw,
2678 PropertyAttributes attributes,
2679 StrictModeFlag strict_mode) {
2680 Isolate* isolate = GetIsolate();
2681 HandleScope scope(isolate);
2682 Handle<Object> receiver(this);
2683 Handle<Object> name(name_raw);
2684 Handle<Object> value(value_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002685
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002686 Handle<Object> args[] = { receiver, name, value };
2687 CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002688 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002689
2690 return *value;
2691}
2692
2693
2694MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
2695 String* name_raw,
2696 Object* value_raw,
2697 PropertyAttributes attributes,
2698 StrictModeFlag strict_mode,
2699 bool* found) {
2700 *found = true; // except where defined otherwise...
2701 Isolate* isolate = GetHeap()->isolate();
2702 Handle<JSProxy> proxy(this);
2703 Handle<Object> handler(this->handler()); // Trap might morph proxy.
2704 Handle<String> name(name_raw);
2705 Handle<Object> value(value_raw);
2706 Handle<Object> args[] = { name };
2707 Handle<Object> result = proxy->CallTrap(
2708 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
2709 if (isolate->has_pending_exception()) return Failure::Exception();
2710
2711 if (!result->IsUndefined()) {
2712 // The proxy handler cares about this property.
2713 // Check whether it is virtualized as an accessor.
2714 // Emulate [[GetProperty]] semantics for proxies.
2715 bool has_pending_exception;
2716 Handle<Object> argv[] = { result };
2717 Handle<Object> desc =
2718 Execution::Call(isolate->to_complete_property_descriptor(), result,
2719 ARRAY_SIZE(argv), argv, &has_pending_exception);
2720 if (has_pending_exception) return Failure::Exception();
2721
2722 Handle<String> conf_name =
2723 isolate->factory()->LookupAsciiSymbol("configurable_");
2724 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
2725 ASSERT(!isolate->has_pending_exception());
2726 if (configurable->IsFalse()) {
2727 Handle<String> trap =
2728 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2729 Handle<Object> args[] = { handler, trap, name };
2730 Handle<Object> error = isolate->factory()->NewTypeError(
2731 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2732 return isolate->Throw(*error);
2733 }
2734 ASSERT(configurable->IsTrue());
2735
2736 // Check for AccessorDescriptor.
2737 Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
2738 Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
2739 ASSERT(!isolate->has_pending_exception());
2740 if (!setter->IsUndefined()) {
2741 // We have a setter -- invoke it.
2742 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2743 return proxy->SetPropertyWithDefinedSetter(
2744 JSReceiver::cast(*setter), *value);
2745 } else {
2746 Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
2747 Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
2748 ASSERT(!isolate->has_pending_exception());
2749 if (!getter->IsUndefined()) {
2750 // We have a getter but no setter -- the property may not be
2751 // written. In strict mode, throw an error.
2752 if (strict_mode == kNonStrictMode) return *value;
2753 Handle<Object> args[] = { name, proxy };
2754 Handle<Object> error = isolate->factory()->NewTypeError(
2755 "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
2756 return isolate->Throw(*error);
2757 }
2758 }
2759 // Fall-through.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002760 }
2761
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002762 // The proxy does not define the property as an accessor.
2763 *found = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002764 return *value;
2765}
2766
2767
2768MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2769 String* name_raw, DeleteMode mode) {
2770 Isolate* isolate = GetIsolate();
2771 HandleScope scope(isolate);
2772 Handle<Object> receiver(this);
2773 Handle<Object> name(name_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002774
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002775 Handle<Object> args[] = { name };
2776 Handle<Object> result = CallTrap(
2777 "delete", Handle<Object>(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002778 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002779
2780 Object* bool_result = result->ToBoolean();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002781 if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
2782 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2783 Handle<Object> args[] = { Handle<Object>(handler()), trap_name };
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002784 Handle<Object> error = isolate->factory()->NewTypeError(
2785 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2786 isolate->Throw(*error);
2787 return Failure::Exception();
2788 }
2789 return bool_result;
2790}
2791
2792
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002793MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
2794 uint32_t index,
2795 DeleteMode mode) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002796 Isolate* isolate = GetIsolate();
2797 HandleScope scope(isolate);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002798 Handle<String> name = isolate->factory()->Uint32ToString(index);
2799 return JSProxy::DeletePropertyWithHandler(*name, mode);
2800}
2801
2802
2803MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2804 JSReceiver* receiver_raw,
2805 String* name_raw) {
2806 Isolate* isolate = GetIsolate();
2807 HandleScope scope(isolate);
2808 Handle<JSProxy> proxy(this);
2809 Handle<Object> handler(this->handler()); // Trap might morph proxy.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002810 Handle<JSReceiver> receiver(receiver_raw);
2811 Handle<Object> name(name_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002812
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002813 Handle<Object> args[] = { name };
2814 Handle<Object> result = CallTrap(
2815 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002816 if (isolate->has_pending_exception()) return NONE;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002817
2818 if (result->IsUndefined()) return ABSENT;
2819
2820 bool has_pending_exception;
2821 Handle<Object> argv[] = { result };
2822 Handle<Object> desc =
2823 Execution::Call(isolate->to_complete_property_descriptor(), result,
2824 ARRAY_SIZE(argv), argv, &has_pending_exception);
2825 if (has_pending_exception) return NONE;
2826
2827 // Convert result to PropertyAttributes.
2828 Handle<String> enum_n = isolate->factory()->LookupAsciiSymbol("enumerable");
2829 Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_n));
2830 if (isolate->has_pending_exception()) return NONE;
2831 Handle<String> conf_n = isolate->factory()->LookupAsciiSymbol("configurable");
2832 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_n));
2833 if (isolate->has_pending_exception()) return NONE;
2834 Handle<String> writ_n = isolate->factory()->LookupAsciiSymbol("writable");
2835 Handle<Object> writable(v8::internal::GetProperty(desc, writ_n));
2836 if (isolate->has_pending_exception()) return NONE;
2837
2838 if (configurable->IsFalse()) {
2839 Handle<String> trap =
2840 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2841 Handle<Object> args[] = { handler, trap, name };
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002842 Handle<Object> error = isolate->factory()->NewTypeError(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002843 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002844 isolate->Throw(*error);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002845 return NONE;
2846 }
2847
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002848 int attributes = NONE;
2849 if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM;
2850 if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE;
2851 if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY;
2852 return static_cast<PropertyAttributes>(attributes);
2853}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002854
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002855
2856MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
2857 JSReceiver* receiver,
2858 uint32_t index) {
2859 Isolate* isolate = GetIsolate();
2860 HandleScope scope(isolate);
2861 Handle<String> name = isolate->factory()->Uint32ToString(index);
2862 return GetPropertyAttributeWithHandler(receiver, *name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002863}
2864
2865
2866void JSProxy::Fix() {
2867 Isolate* isolate = GetIsolate();
2868 HandleScope scope(isolate);
2869 Handle<JSProxy> self(this);
2870
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002871 // Save identity hash.
2872 MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
2873
Ben Murdoch589d6972011-11-30 16:04:58 +00002874 if (IsJSFunctionProxy()) {
2875 isolate->factory()->BecomeJSFunction(self);
2876 // Code will be set on the JavaScript side.
2877 } else {
2878 isolate->factory()->BecomeJSObject(self);
2879 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002880 ASSERT(self->IsJSObject());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002881
2882 // Inherit identity, if it was present.
2883 Object* hash;
2884 if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
2885 Handle<JSObject> new_self(JSObject::cast(*self));
2886 isolate->factory()->SetIdentityHash(new_self, hash);
2887 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002888}
2889
2890
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002891MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
2892 Handle<Object> derived,
2893 int argc,
2894 Handle<Object> argv[]) {
2895 Isolate* isolate = GetIsolate();
2896 Handle<Object> handler(this->handler());
2897
2898 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol(name);
2899 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2900 if (isolate->has_pending_exception()) return trap;
2901
2902 if (trap->IsUndefined()) {
2903 if (derived.is_null()) {
2904 Handle<Object> args[] = { handler, trap_name };
2905 Handle<Object> error = isolate->factory()->NewTypeError(
2906 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2907 isolate->Throw(*error);
2908 return Handle<Object>();
2909 }
2910 trap = Handle<Object>(derived);
2911 }
2912
2913 bool threw;
2914 return Execution::Call(trap, handler, argc, argv, &threw);
2915}
2916
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002917
2918MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
2919 String* name,
2920 Object* value,
2921 PropertyAttributes attributes,
2922 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002923 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002924 // Make sure that the top context does not change when doing callbacks or
2925 // interceptor calls.
2926 AssertNoContextChange ncc;
2927
Steve Blockd0582a62009-12-15 09:54:21 +00002928 // Optimization for 2-byte strings often used as keys in a decompression
2929 // dictionary. We make these short keys into symbols to avoid constantly
2930 // reallocating them.
2931 if (!name->IsSymbol() && name->length() <= 2) {
John Reck59135872010-11-02 12:39:01 -07002932 Object* symbol_version;
Steve Block44f0eee2011-05-26 01:26:41 +01002933 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
John Reck59135872010-11-02 12:39:01 -07002934 if (maybe_symbol_version->ToObject(&symbol_version)) {
2935 name = String::cast(symbol_version);
2936 }
2937 }
Steve Blockd0582a62009-12-15 09:54:21 +00002938 }
2939
Steve Blocka7e24c12009-10-30 11:49:00 +00002940 // Check access rights if needed.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002941 if (IsAccessCheckNeeded()) {
2942 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
2943 return SetPropertyWithFailedAccessCheck(
2944 result, name, value, true, strict_mode);
2945 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002946 }
2947
2948 if (IsJSGlobalProxy()) {
2949 Object* proto = GetPrototype();
2950 if (proto->IsNull()) return value;
2951 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002952 return JSObject::cast(proto)->SetPropertyForResult(
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002953 result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002954 }
2955
2956 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002957 bool found = false;
2958 MaybeObject* result_object;
2959 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
2960 value,
2961 attributes,
2962 &found,
2963 strict_mode);
2964 if (found) return result_object;
Steve Blocka7e24c12009-10-30 11:49:00 +00002965 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002966
2967 // At this point, no GC should have happened, as this would invalidate
2968 // 'result', which we cannot handlify!
2969
Andrei Popescu402d9372010-02-26 13:31:12 +00002970 if (!result->IsFound()) {
2971 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002972 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002973 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002974 if (result->IsReadOnly() && result->IsProperty()) {
2975 if (strict_mode == kStrictMode) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002976 Handle<JSObject> self(this);
2977 Handle<String> hname(name);
2978 Handle<Object> args[] = { hname, self };
Steve Block44f0eee2011-05-26 01:26:41 +01002979 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002980 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002981 } else {
2982 return value;
2983 }
2984 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002985 // This is a real property that is not read-only, or it is a
2986 // transition or null descriptor and there are no setters in the prototypes.
2987 switch (result->type()) {
2988 case NORMAL:
2989 return SetNormalizedProperty(result, value);
2990 case FIELD:
2991 return FastPropertyAtPut(result->GetFieldIndex(), value);
2992 case MAP_TRANSITION:
2993 if (attributes == result->GetAttributes()) {
2994 // Only use map transition if the attributes match.
2995 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2996 name,
2997 value);
2998 }
2999 return ConvertDescriptorToField(name, value, attributes);
3000 case CONSTANT_FUNCTION:
3001 // Only replace the function if necessary.
3002 if (value == result->GetConstantFunction()) return value;
3003 // Preserve the attributes of this existing property.
3004 attributes = result->GetAttributes();
3005 return ConvertDescriptorToField(name, value, attributes);
3006 case CALLBACKS:
3007 return SetPropertyWithCallback(result->GetCallbackObject(),
3008 name,
3009 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003010 result->holder(),
3011 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003012 case INTERCEPTOR:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003013 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
Iain Merrick75681382010-08-19 15:07:18 +01003014 case CONSTANT_TRANSITION: {
3015 // If the same constant function is being added we can simply
3016 // transition to the target map.
3017 Map* target_map = result->GetTransitionMap();
3018 DescriptorArray* target_descriptors = target_map->instance_descriptors();
3019 int number = target_descriptors->SearchWithCache(name);
3020 ASSERT(number != DescriptorArray::kNotFound);
3021 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
3022 JSFunction* function =
3023 JSFunction::cast(target_descriptors->GetValue(number));
Iain Merrick75681382010-08-19 15:07:18 +01003024 if (value == function) {
3025 set_map(target_map);
3026 return value;
3027 }
3028 // Otherwise, replace with a MAP_TRANSITION to a new map with a
3029 // FIELD, even if the value is a constant function.
Steve Blocka7e24c12009-10-30 11:49:00 +00003030 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Iain Merrick75681382010-08-19 15:07:18 +01003031 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003032 case NULL_DESCRIPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00003033 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00003034 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003035 case HANDLER:
Steve Blocka7e24c12009-10-30 11:49:00 +00003036 UNREACHABLE();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003037 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00003038 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003039 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +00003040 return value;
3041}
3042
3043
3044// Set a real local property, even if it is READ_ONLY. If the property is not
3045// present, add it with attributes NONE. This code is an exact clone of
3046// SetProperty, with the check for IsReadOnly and the check for a
3047// callback setter removed. The two lines looking up the LookupResult
3048// result are also added. If one of the functions is changed, the other
3049// should be.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003050// Note that this method cannot be used to set the prototype of a function
3051// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
3052// doesn't handle function prototypes correctly.
Ben Murdochc7cc0282012-03-05 14:35:55 +00003053Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
3054 Handle<JSObject> object,
3055 Handle<String> key,
3056 Handle<Object> value,
3057 PropertyAttributes attributes) {
3058 CALL_HEAP_FUNCTION(
3059 object->GetIsolate(),
3060 object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
3061 Object);
3062}
3063
3064
Ben Murdoch086aeea2011-05-13 15:57:08 +01003065MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00003066 String* name,
3067 Object* value,
3068 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01003069
Steve Blocka7e24c12009-10-30 11:49:00 +00003070 // Make sure that the top context does not change when doing callbacks or
3071 // interceptor calls.
3072 AssertNoContextChange ncc;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003073 Isolate* isolate = GetIsolate();
3074 LookupResult result(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00003075 LocalLookup(name, &result);
Steve Blocka7e24c12009-10-30 11:49:00 +00003076 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003077 if (IsAccessCheckNeeded()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003078 if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003079 return SetPropertyWithFailedAccessCheck(&result,
3080 name,
3081 value,
3082 false,
3083 kNonStrictMode);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003084 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003085 }
3086
3087 if (IsJSGlobalProxy()) {
3088 Object* proto = GetPrototype();
3089 if (proto->IsNull()) return value;
3090 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch086aeea2011-05-13 15:57:08 +01003091 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00003092 name,
3093 value,
3094 attributes);
3095 }
3096
3097 // Check for accessor in prototype chain removed here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00003098 if (!result.IsFound()) {
3099 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01003100 return AddProperty(name, value, attributes, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003101 }
Steve Block6ded16b2010-05-10 14:33:55 +01003102
Andrei Popescu402d9372010-02-26 13:31:12 +00003103 PropertyDetails details = PropertyDetails(attributes, NORMAL);
3104
Steve Blocka7e24c12009-10-30 11:49:00 +00003105 // Check of IsReadOnly removed from here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00003106 switch (result.type()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003107 case NORMAL:
Andrei Popescu402d9372010-02-26 13:31:12 +00003108 return SetNormalizedProperty(name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00003109 case FIELD:
Andrei Popescu402d9372010-02-26 13:31:12 +00003110 return FastPropertyAtPut(result.GetFieldIndex(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00003111 case MAP_TRANSITION:
Andrei Popescu402d9372010-02-26 13:31:12 +00003112 if (attributes == result.GetAttributes()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003113 // Only use map transition if the attributes match.
Andrei Popescu402d9372010-02-26 13:31:12 +00003114 return AddFastPropertyUsingMap(result.GetTransitionMap(),
Steve Blocka7e24c12009-10-30 11:49:00 +00003115 name,
3116 value);
3117 }
3118 return ConvertDescriptorToField(name, value, attributes);
3119 case CONSTANT_FUNCTION:
3120 // Only replace the function if necessary.
Andrei Popescu402d9372010-02-26 13:31:12 +00003121 if (value == result.GetConstantFunction()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00003122 // Preserve the attributes of this existing property.
Andrei Popescu402d9372010-02-26 13:31:12 +00003123 attributes = result.GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +00003124 return ConvertDescriptorToField(name, value, attributes);
3125 case CALLBACKS:
3126 case INTERCEPTOR:
3127 // Override callback in clone
3128 return ConvertDescriptorToField(name, value, attributes);
3129 case CONSTANT_TRANSITION:
3130 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
3131 // if the value is a function.
3132 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
3133 case NULL_DESCRIPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00003134 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00003135 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003136 case HANDLER:
Steve Blocka7e24c12009-10-30 11:49:00 +00003137 UNREACHABLE();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003138 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00003139 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003140 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +00003141 return value;
3142}
3143
3144
3145PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
3146 JSObject* receiver,
3147 String* name,
3148 bool continue_search) {
3149 // Check local property, ignore interceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003150 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003151 LocalLookupRealNamedProperty(name, &result);
3152 if (result.IsProperty()) return result.GetAttributes();
3153
3154 if (continue_search) {
3155 // Continue searching via the prototype chain.
3156 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003157 if (!pt->IsNull()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003158 return JSObject::cast(pt)->
3159 GetPropertyAttributeWithReceiver(receiver, name);
3160 }
3161 }
3162 return ABSENT;
3163}
3164
3165
3166PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
3167 JSObject* receiver,
3168 String* name,
3169 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +01003170 Isolate* isolate = GetIsolate();
3171
Steve Blocka7e24c12009-10-30 11:49:00 +00003172 // Make sure that the top context does not change when doing
3173 // callbacks or interceptor calls.
3174 AssertNoContextChange ncc;
3175
Steve Block44f0eee2011-05-26 01:26:41 +01003176 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003177 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3178 Handle<JSObject> receiver_handle(receiver);
3179 Handle<JSObject> holder_handle(this);
3180 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01003181 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003182 v8::AccessorInfo info(args.end());
3183 if (!interceptor->query()->IsUndefined()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003184 v8::NamedPropertyQuery query =
3185 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01003186 LOG(isolate,
3187 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003188 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003189 {
3190 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003191 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003192 result = query(v8::Utils::ToLocal(name_handle), info);
3193 }
3194 if (!result.IsEmpty()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003195 ASSERT(result->IsInt32());
3196 return static_cast<PropertyAttributes>(result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00003197 }
3198 } else if (!interceptor->getter()->IsUndefined()) {
3199 v8::NamedPropertyGetter getter =
3200 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01003201 LOG(isolate,
3202 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
Steve Blocka7e24c12009-10-30 11:49:00 +00003203 v8::Handle<v8::Value> result;
3204 {
3205 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003206 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003207 result = getter(v8::Utils::ToLocal(name_handle), info);
3208 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003209 if (!result.IsEmpty()) return DONT_ENUM;
Steve Blocka7e24c12009-10-30 11:49:00 +00003210 }
3211 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
3212 *name_handle,
3213 continue_search);
3214}
3215
3216
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003217PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
3218 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00003219 String* key) {
3220 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003221 if (IsJSObject() && key->AsArrayIndex(&index)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003222 return JSObject::cast(this)->HasElementWithReceiver(receiver, index)
3223 ? NONE : ABSENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00003224 }
3225 // Named property.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003226 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003227 Lookup(key, &result);
3228 return GetPropertyAttribute(receiver, &result, key, true);
3229}
3230
3231
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003232PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
3233 LookupResult* result,
3234 String* name,
3235 bool continue_search) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003236 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003237 if (IsAccessCheckNeeded()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003238 JSObject* this_obj = JSObject::cast(this);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003239 Heap* heap = GetHeap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003240 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
3241 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
3242 receiver, result, name, continue_search);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003243 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003244 }
Andrei Popescu402d9372010-02-26 13:31:12 +00003245 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003246 switch (result->type()) {
3247 case NORMAL: // fall through
3248 case FIELD:
3249 case CONSTANT_FUNCTION:
3250 case CALLBACKS:
3251 return result->GetAttributes();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003252 case HANDLER: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003253 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler(
3254 receiver, name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003255 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003256 case INTERCEPTOR:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003257 return result->holder()->GetPropertyAttributeWithInterceptor(
3258 JSObject::cast(receiver), name, continue_search);
Steve Blocka7e24c12009-10-30 11:49:00 +00003259 default:
3260 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00003261 }
3262 }
3263 return ABSENT;
3264}
3265
3266
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003267PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003268 // Check whether the name is an array index.
3269 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003270 if (IsJSObject() && name->AsArrayIndex(&index)) {
3271 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
Steve Blocka7e24c12009-10-30 11:49:00 +00003272 return ABSENT;
3273 }
3274 // Named property.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003275 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003276 LocalLookup(name, &result);
3277 return GetPropertyAttribute(this, &result, name, false);
3278}
3279
3280
John Reck59135872010-11-02 12:39:01 -07003281MaybeObject* NormalizedMapCache::Get(JSObject* obj,
3282 PropertyNormalizationMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003283 Isolate* isolate = obj->GetIsolate();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003284 Map* fast = obj->map();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003285 int index = fast->Hash() % kEntries;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003286 Object* result = get(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003287 if (result->IsMap() &&
3288 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003289#ifdef DEBUG
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003290 if (FLAG_verify_heap) {
3291 Map::cast(result)->SharedMapVerify();
3292 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003293 if (FLAG_enable_slow_asserts) {
3294 // The cached map should match newly created normalized map bit-by-bit.
John Reck59135872010-11-02 12:39:01 -07003295 Object* fresh;
3296 { MaybeObject* maybe_fresh =
3297 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3298 if (maybe_fresh->ToObject(&fresh)) {
3299 ASSERT(memcmp(Map::cast(fresh)->address(),
3300 Map::cast(result)->address(),
3301 Map::kSize) == 0);
3302 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003303 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003304 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003305#endif
3306 return result;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003307 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003308
John Reck59135872010-11-02 12:39:01 -07003309 { MaybeObject* maybe_result =
3310 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3311 if (!maybe_result->ToObject(&result)) return maybe_result;
3312 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003313 set(index, result);
Steve Block44f0eee2011-05-26 01:26:41 +01003314 isolate->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003315
3316 return result;
3317}
3318
3319
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003320void NormalizedMapCache::Clear() {
3321 int entries = length();
3322 for (int i = 0; i != entries; i++) {
3323 set_undefined(i);
3324 }
3325}
3326
3327
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003328void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
3329 Handle<String> name,
3330 Handle<Code> code) {
3331 Isolate* isolate = object->GetIsolate();
3332 CALL_HEAP_FUNCTION_VOID(isolate,
3333 object->UpdateMapCodeCache(*name, *code));
3334}
3335
3336
John Reck59135872010-11-02 12:39:01 -07003337MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003338 if (map()->is_shared()) {
3339 // Fast case maps are never marked as shared.
3340 ASSERT(!HasFastProperties());
3341 // Replace the map with an identical copy that can be safely modified.
John Reck59135872010-11-02 12:39:01 -07003342 Object* obj;
3343 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
3344 UNIQUE_NORMALIZED_MAP);
3345 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3346 }
Steve Block44f0eee2011-05-26 01:26:41 +01003347 GetIsolate()->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003348
3349 set_map(Map::cast(obj));
3350 }
3351 return map()->UpdateCodeCache(name, code);
3352}
3353
3354
Ben Murdochc7cc0282012-03-05 14:35:55 +00003355void JSObject::NormalizeProperties(Handle<JSObject> object,
3356 PropertyNormalizationMode mode,
3357 int expected_additional_properties) {
3358 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
3359 object->NormalizeProperties(
3360 mode, expected_additional_properties));
3361}
3362
3363
John Reck59135872010-11-02 12:39:01 -07003364MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
3365 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003366 if (!HasFastProperties()) return this;
3367
3368 // The global object is always normalized.
3369 ASSERT(!IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01003370 // JSGlobalProxy must never be normalized
3371 ASSERT(!IsJSGlobalProxy());
3372
Ben Murdoch8b112d22011-06-08 16:22:53 +01003373 Map* map_of_this = map();
Steve Block44f0eee2011-05-26 01:26:41 +01003374
Steve Blocka7e24c12009-10-30 11:49:00 +00003375 // Allocate new content.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003376 int property_count = map_of_this->NumberOfDescribedProperties();
Steve Blocka7e24c12009-10-30 11:49:00 +00003377 if (expected_additional_properties > 0) {
3378 property_count += expected_additional_properties;
3379 } else {
3380 property_count += 2; // Make space for two more properties.
3381 }
John Reck59135872010-11-02 12:39:01 -07003382 Object* obj;
3383 { MaybeObject* maybe_obj =
3384 StringDictionary::Allocate(property_count);
3385 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3386 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003387 StringDictionary* dictionary = StringDictionary::cast(obj);
3388
Ben Murdoch8b112d22011-06-08 16:22:53 +01003389 DescriptorArray* descs = map_of_this->instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00003390 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01003391 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00003392 switch (details.type()) {
3393 case CONSTANT_FUNCTION: {
3394 PropertyDetails d =
3395 PropertyDetails(details.attributes(), NORMAL, details.index());
3396 Object* value = descs->GetConstantFunction(i);
John Reck59135872010-11-02 12:39:01 -07003397 Object* result;
3398 { MaybeObject* maybe_result =
3399 dictionary->Add(descs->GetKey(i), value, d);
3400 if (!maybe_result->ToObject(&result)) return maybe_result;
3401 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003402 dictionary = StringDictionary::cast(result);
3403 break;
3404 }
3405 case FIELD: {
3406 PropertyDetails d =
3407 PropertyDetails(details.attributes(), NORMAL, details.index());
3408 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
John Reck59135872010-11-02 12:39:01 -07003409 Object* result;
3410 { MaybeObject* maybe_result =
3411 dictionary->Add(descs->GetKey(i), value, d);
3412 if (!maybe_result->ToObject(&result)) return maybe_result;
3413 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003414 dictionary = StringDictionary::cast(result);
3415 break;
3416 }
3417 case CALLBACKS: {
3418 PropertyDetails d =
3419 PropertyDetails(details.attributes(), CALLBACKS, details.index());
3420 Object* value = descs->GetCallbacksObject(i);
John Reck59135872010-11-02 12:39:01 -07003421 Object* result;
3422 { MaybeObject* maybe_result =
3423 dictionary->Add(descs->GetKey(i), value, d);
3424 if (!maybe_result->ToObject(&result)) return maybe_result;
3425 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003426 dictionary = StringDictionary::cast(result);
3427 break;
3428 }
3429 case MAP_TRANSITION:
3430 case CONSTANT_TRANSITION:
3431 case NULL_DESCRIPTOR:
3432 case INTERCEPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00003433 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00003434 break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003435 case HANDLER:
3436 case NORMAL:
Steve Blocka7e24c12009-10-30 11:49:00 +00003437 UNREACHABLE();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003438 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00003439 }
3440 }
3441
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003442 Heap* current_heap = GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01003443
Steve Blocka7e24c12009-10-30 11:49:00 +00003444 // Copy the next enumeration index from instance descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003445 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00003446 dictionary->SetNextEnumerationIndex(index);
3447
Ben Murdoch8b112d22011-06-08 16:22:53 +01003448 { MaybeObject* maybe_obj =
3449 current_heap->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01003450 normalized_map_cache()->Get(this, mode);
John Reck59135872010-11-02 12:39:01 -07003451 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3452 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003453 Map* new_map = Map::cast(obj);
3454
Steve Blocka7e24c12009-10-30 11:49:00 +00003455 // We have now successfully allocated all the necessary objects.
3456 // Changes can now be made with the guarantee that all of them take effect.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003457
3458 // Resize the object in the heap if necessary.
3459 int new_instance_size = new_map->instance_size();
Ben Murdoch8b112d22011-06-08 16:22:53 +01003460 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003461 ASSERT(instance_size_delta >= 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003462 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
3463 instance_size_delta);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003464 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00003465 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
3466 -instance_size_delta);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003467 }
3468
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003469
Steve Blocka7e24c12009-10-30 11:49:00 +00003470 set_map(new_map);
Ben Murdoch257744e2011-11-30 15:57:28 +00003471 new_map->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00003472
3473 set_properties(dictionary);
3474
Ben Murdoch8b112d22011-06-08 16:22:53 +01003475 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00003476
3477#ifdef DEBUG
3478 if (FLAG_trace_normalization) {
3479 PrintF("Object properties have been normalized:\n");
3480 Print();
3481 }
3482#endif
3483 return this;
3484}
3485
3486
Ben Murdochc7cc0282012-03-05 14:35:55 +00003487void JSObject::TransformToFastProperties(Handle<JSObject> object,
3488 int unused_property_fields) {
3489 CALL_HEAP_FUNCTION_VOID(
3490 object->GetIsolate(),
3491 object->TransformToFastProperties(unused_property_fields));
3492}
3493
3494
John Reck59135872010-11-02 12:39:01 -07003495MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003496 if (HasFastProperties()) return this;
3497 ASSERT(!IsGlobalObject());
3498 return property_dictionary()->
3499 TransformPropertiesToFastFor(this, unused_property_fields);
3500}
3501
3502
Ben Murdochc7cc0282012-03-05 14:35:55 +00003503Handle<SeededNumberDictionary> JSObject::NormalizeElements(
3504 Handle<JSObject> object) {
3505 CALL_HEAP_FUNCTION(object->GetIsolate(),
3506 object->NormalizeElements(),
3507 SeededNumberDictionary);
3508}
3509
3510
John Reck59135872010-11-02 12:39:01 -07003511MaybeObject* JSObject::NormalizeElements() {
Steve Block44f0eee2011-05-26 01:26:41 +01003512 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01003513
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003514 // Find the backing store.
3515 FixedArrayBase* array = FixedArrayBase::cast(elements());
3516 Map* old_map = array->map();
3517 bool is_arguments =
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003518 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003519 if (is_arguments) {
3520 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
John Reck59135872010-11-02 12:39:01 -07003521 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003522 if (array->IsDictionary()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00003523
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003524 ASSERT(HasFastElements() ||
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003525 HasFastSmiOnlyElements() ||
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003526 HasFastDoubleElements() ||
3527 HasFastArgumentsElements());
3528 // Compute the effective length and allocate a new backing store.
3529 int length = IsJSArray()
3530 ? Smi::cast(JSArray::cast(this)->length())->value()
3531 : array->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003532 int old_capacity = 0;
3533 int used_elements = 0;
3534 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdochc7cc0282012-03-05 14:35:55 +00003535 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003536 { Object* object;
Ben Murdochc7cc0282012-03-05 14:35:55 +00003537 MaybeObject* maybe = SeededNumberDictionary::Allocate(used_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003538 if (!maybe->ToObject(&object)) return maybe;
Ben Murdochc7cc0282012-03-05 14:35:55 +00003539 dictionary = SeededNumberDictionary::cast(object);
John Reck59135872010-11-02 12:39:01 -07003540 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003541
3542 // Copy the elements to the new backing store.
3543 bool has_double_elements = array->IsFixedDoubleArray();
Steve Blocka7e24c12009-10-30 11:49:00 +00003544 for (int i = 0; i < length; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003545 Object* value = NULL;
3546 if (has_double_elements) {
3547 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
3548 if (double_array->is_the_hole(i)) {
3549 value = GetIsolate()->heap()->the_hole_value();
3550 } else {
3551 // Objects must be allocated in the old object space, since the
3552 // overall number of HeapNumbers needed for the conversion might
3553 // exceed the capacity of new space, and we would fail repeatedly
3554 // trying to convert the FixedDoubleArray.
3555 MaybeObject* maybe_value_object =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003556 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003557 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
John Reck59135872010-11-02 12:39:01 -07003558 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003559 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003560 ASSERT(old_map->has_fast_elements() ||
3561 old_map->has_fast_smi_only_elements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003562 value = FixedArray::cast(array)->get(i);
3563 }
3564 PropertyDetails details = PropertyDetails(NONE, NORMAL);
3565 if (!value->IsTheHole()) {
3566 Object* result;
3567 MaybeObject* maybe_result =
3568 dictionary->AddNumberEntry(i, value, details);
3569 if (!maybe_result->ToObject(&result)) return maybe_result;
Ben Murdochc7cc0282012-03-05 14:35:55 +00003570 dictionary = SeededNumberDictionary::cast(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00003571 }
3572 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003573
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003574 // Switch to using the dictionary as the backing storage for elements.
3575 if (is_arguments) {
3576 FixedArray::cast(elements())->set(1, dictionary);
3577 } else {
3578 // Set the new map first to satify the elements type assert in
3579 // set_elements().
3580 Object* new_map;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003581 MaybeObject* maybe = GetElementsTransitionMap(DICTIONARY_ELEMENTS);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003582 if (!maybe->ToObject(&new_map)) return maybe;
3583 set_map(Map::cast(new_map));
3584 set_elements(dictionary);
3585 }
3586
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003587 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
3588 Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00003589
3590#ifdef DEBUG
3591 if (FLAG_trace_normalization) {
3592 PrintF("Object elements have been normalized:\n");
3593 Print();
3594 }
3595#endif
3596
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003597 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
3598 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00003599}
3600
3601
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003602Smi* JSReceiver::GenerateIdentityHash() {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003603 Isolate* isolate = GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003604
3605 int hash_value;
3606 int attempts = 0;
3607 do {
3608 // Generate a random 32-bit hash value but limit range to fit
3609 // within a smi.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003610 hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003611 attempts++;
3612 } while (hash_value == 0 && attempts < 30);
3613 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
3614
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003615 return Smi::FromInt(hash_value);
3616}
3617
3618
3619MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
3620 MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3621 hash);
3622 if (maybe->IsFailure()) return maybe;
3623 return this;
3624}
3625
3626
Ben Murdochc7cc0282012-03-05 14:35:55 +00003627int JSObject::GetIdentityHash(Handle<JSObject> obj) {
3628 CALL_AND_RETRY(obj->GetIsolate(),
3629 obj->GetIdentityHash(ALLOW_CREATION),
3630 return Smi::cast(__object__)->value(),
3631 return 0);
3632}
3633
3634
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003635MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
3636 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
3637 if (stored_value->IsSmi()) return stored_value;
3638
3639 // Do not generate permanent identity hash code if not requested.
3640 if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
3641
3642 Smi* hash = GenerateIdentityHash();
3643 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3644 hash);
3645 if (result->IsFailure()) return result;
3646 if (result->ToObjectUnchecked()->IsUndefined()) {
3647 // Trying to get hash of detached proxy.
3648 return Smi::FromInt(0);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003649 }
3650 return hash;
3651}
3652
3653
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003654MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
3655 Object* hash = this->hash();
3656 if (!hash->IsSmi() && flag == ALLOW_CREATION) {
3657 hash = GenerateIdentityHash();
3658 set_hash(hash);
3659 }
3660 return hash;
3661}
3662
3663
3664Object* JSObject::GetHiddenProperty(String* key) {
3665 if (IsJSGlobalProxy()) {
3666 // For a proxy, use the prototype as target object.
3667 Object* proxy_parent = GetPrototype();
3668 // If the proxy is detached, return undefined.
3669 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3670 ASSERT(proxy_parent->IsJSGlobalObject());
3671 return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
3672 }
3673 ASSERT(!IsJSGlobalProxy());
3674 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3675 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3676 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
3677 return GetHeap()->undefined_value();
3678 }
3679 StringDictionary* dictionary =
3680 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3681 int entry = dictionary->FindEntry(key);
3682 if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
3683 return dictionary->ValueAt(entry);
3684}
3685
3686
Ben Murdochc7cc0282012-03-05 14:35:55 +00003687Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
3688 Handle<String> key,
3689 Handle<Object> value) {
3690 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3691 obj->SetHiddenProperty(*key, *value),
3692 Object);
3693}
3694
3695
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003696MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
3697 if (IsJSGlobalProxy()) {
3698 // For a proxy, use the prototype as target object.
3699 Object* proxy_parent = GetPrototype();
3700 // If the proxy is detached, return undefined.
3701 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3702 ASSERT(proxy_parent->IsJSGlobalObject());
3703 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
3704 }
3705 ASSERT(!IsJSGlobalProxy());
3706 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
3707 StringDictionary* dictionary;
3708 if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
3709
3710 // If it was found, check if the key is already in the dictionary.
3711 int entry = dictionary->FindEntry(key);
3712 if (entry != StringDictionary::kNotFound) {
3713 // If key was found, just update the value.
3714 dictionary->ValueAtPut(entry, value);
3715 return this;
3716 }
3717 // Key was not already in the dictionary, so add the entry.
3718 MaybeObject* insert_result = dictionary->Add(key,
3719 value,
3720 PropertyDetails(NONE, NORMAL));
3721 StringDictionary* new_dict;
3722 if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
3723 if (new_dict != dictionary) {
3724 // If adding the key expanded the dictionary (i.e., Add returned a new
3725 // dictionary), store it back to the object.
3726 MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
3727 if (store_result->IsFailure()) return store_result;
3728 }
3729 // Return this to mark success.
3730 return this;
3731}
3732
3733
3734void JSObject::DeleteHiddenProperty(String* key) {
3735 if (IsJSGlobalProxy()) {
3736 // For a proxy, use the prototype as target object.
3737 Object* proxy_parent = GetPrototype();
3738 // If the proxy is detached, return immediately.
3739 if (proxy_parent->IsNull()) return;
3740 ASSERT(proxy_parent->IsJSGlobalObject());
3741 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
3742 return;
3743 }
3744 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3745 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3746 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
3747 StringDictionary* dictionary =
3748 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3749 int entry = dictionary->FindEntry(key);
3750 if (entry == StringDictionary::kNotFound) {
3751 // Key wasn't in dictionary. Deletion is a success.
3752 return;
3753 }
3754 // Key was in the dictionary. Remove it.
3755 dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
3756}
3757
3758
3759bool JSObject::HasHiddenProperties() {
3760 return GetPropertyAttributePostInterceptor(this,
3761 GetHeap()->hidden_symbol(),
3762 false) != ABSENT;
3763}
3764
3765
3766MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
3767 ASSERT(!IsJSGlobalProxy());
3768 if (HasFastProperties()) {
3769 // If the object has fast properties, check whether the first slot
3770 // in the descriptor array matches the hidden symbol. Since the
3771 // hidden symbols hash code is zero (and no other string has hash
3772 // code zero) it will always occupy the first entry if present.
3773 DescriptorArray* descriptors = this->map()->instance_descriptors();
3774 if ((descriptors->number_of_descriptors() > 0) &&
3775 (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) &&
3776 descriptors->IsProperty(0)) {
3777 ASSERT(descriptors->GetType(0) == FIELD);
3778 Object* hidden_store =
3779 this->FastPropertyAt(descriptors->GetFieldIndex(0));
3780 return StringDictionary::cast(hidden_store);
3781 }
3782 } else {
3783 PropertyAttributes attributes;
3784 // You can't install a getter on a property indexed by the hidden symbol,
3785 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
3786 // object.
3787 Object* lookup =
3788 GetLocalPropertyPostInterceptor(this,
3789 GetHeap()->hidden_symbol(),
3790 &attributes)->ToObjectUnchecked();
3791 if (!lookup->IsUndefined()) {
3792 return StringDictionary::cast(lookup);
3793 }
3794 }
3795 if (!create_if_absent) return GetHeap()->undefined_value();
3796 const int kInitialSize = 5;
3797 MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
3798 StringDictionary* dictionary;
3799 if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
3800 MaybeObject* store_result =
3801 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3802 dictionary,
3803 DONT_ENUM,
3804 kNonStrictMode);
3805 if (store_result->IsFailure()) return store_result;
3806 return dictionary;
3807}
3808
3809
3810MaybeObject* JSObject::SetHiddenPropertiesDictionary(
3811 StringDictionary* dictionary) {
3812 ASSERT(!IsJSGlobalProxy());
3813 ASSERT(HasHiddenProperties());
3814 if (HasFastProperties()) {
3815 // If the object has fast properties, check whether the first slot
3816 // in the descriptor array matches the hidden symbol. Since the
3817 // hidden symbols hash code is zero (and no other string has hash
3818 // code zero) it will always occupy the first entry if present.
3819 DescriptorArray* descriptors = this->map()->instance_descriptors();
3820 if ((descriptors->number_of_descriptors() > 0) &&
3821 (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) &&
3822 descriptors->IsProperty(0)) {
3823 ASSERT(descriptors->GetType(0) == FIELD);
3824 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
3825 return this;
3826 }
3827 }
3828 MaybeObject* store_result =
3829 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3830 dictionary,
3831 DONT_ENUM,
3832 kNonStrictMode);
3833 if (store_result->IsFailure()) return store_result;
3834 return this;
3835}
3836
3837
John Reck59135872010-11-02 12:39:01 -07003838MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3839 DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003840 // Check local property, ignore interceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003841 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003842 LocalLookupRealNamedProperty(name, &result);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003843 if (!result.IsProperty()) return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003844
3845 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003846 Object* obj;
3847 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3848 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3849 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003850
3851 return DeleteNormalizedProperty(name, mode);
3852}
3853
3854
John Reck59135872010-11-02 12:39:01 -07003855MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +01003856 Isolate* isolate = GetIsolate();
3857 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003858 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3859 Handle<String> name_handle(name);
3860 Handle<JSObject> this_handle(this);
3861 if (!interceptor->deleter()->IsUndefined()) {
3862 v8::NamedPropertyDeleter deleter =
3863 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
Steve Block44f0eee2011-05-26 01:26:41 +01003864 LOG(isolate,
3865 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3866 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003867 v8::AccessorInfo info(args.end());
3868 v8::Handle<v8::Boolean> result;
3869 {
3870 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003871 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003872 result = deleter(v8::Utils::ToLocal(name_handle), info);
3873 }
Steve Block44f0eee2011-05-26 01:26:41 +01003874 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003875 if (!result.IsEmpty()) {
3876 ASSERT(result->IsBoolean());
3877 return *v8::Utils::OpenHandle(*result);
3878 }
3879 }
John Reck59135872010-11-02 12:39:01 -07003880 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00003881 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003882 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003883 return raw_result;
3884}
3885
3886
John Reck59135872010-11-02 12:39:01 -07003887MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01003888 Isolate* isolate = GetIsolate();
3889 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003890 // Make sure that the top context does not change when doing
3891 // callbacks or interceptor calls.
3892 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01003893 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003894 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Steve Block44f0eee2011-05-26 01:26:41 +01003895 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003896 v8::IndexedPropertyDeleter deleter =
3897 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3898 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01003899 LOG(isolate,
3900 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3901 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003902 v8::AccessorInfo info(args.end());
3903 v8::Handle<v8::Boolean> result;
3904 {
3905 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003906 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003907 result = deleter(index, info);
3908 }
Steve Block44f0eee2011-05-26 01:26:41 +01003909 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003910 if (!result.IsEmpty()) {
3911 ASSERT(result->IsBoolean());
3912 return *v8::Utils::OpenHandle(*result);
3913 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003914 MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3915 *this_handle,
3916 index,
3917 NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003918 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003919 return raw_result;
3920}
3921
3922
Ben Murdochc7cc0282012-03-05 14:35:55 +00003923Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
3924 uint32_t index) {
3925 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3926 obj->DeleteElement(index, JSObject::NORMAL_DELETION),
3927 Object);
3928}
3929
3930
John Reck59135872010-11-02 12:39:01 -07003931MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003932 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003933 // Check access rights if needed.
3934 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003935 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3936 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3937 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003938 }
3939
3940 if (IsJSGlobalProxy()) {
3941 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003942 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003943 ASSERT(proto->IsJSGlobalObject());
3944 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
3945 }
3946
3947 if (HasIndexedInterceptor()) {
3948 // Skip interceptor if forcing deletion.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003949 if (mode != FORCE_DELETION) {
3950 return DeleteElementWithInterceptor(index);
3951 }
3952 mode = JSReceiver::FORCE_DELETION;
Steve Blocka7e24c12009-10-30 11:49:00 +00003953 }
3954
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003955 return GetElementsAccessor()->Delete(this, index, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003956}
3957
3958
Ben Murdochc7cc0282012-03-05 14:35:55 +00003959Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj,
3960 Handle<String> prop) {
3961 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3962 obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
3963 Object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003964}
3965
3966
John Reck59135872010-11-02 12:39:01 -07003967MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003968 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003969 // ECMA-262, 3rd, 8.6.2.5
3970 ASSERT(name->IsString());
3971
3972 // Check access rights if needed.
3973 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003974 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3975 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3976 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003977 }
3978
3979 if (IsJSGlobalProxy()) {
3980 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003981 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003982 ASSERT(proto->IsJSGlobalObject());
3983 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
3984 }
3985
3986 uint32_t index = 0;
3987 if (name->AsArrayIndex(&index)) {
3988 return DeleteElement(index, mode);
3989 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003990 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003991 LocalLookup(name, &result);
Steve Block44f0eee2011-05-26 01:26:41 +01003992 if (!result.IsProperty()) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003993 // Ignore attributes if forcing a deletion.
3994 if (result.IsDontDelete() && mode != FORCE_DELETION) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003995 if (mode == STRICT_DELETION) {
3996 // Deleting a non-configurable property in strict mode.
Steve Block44f0eee2011-05-26 01:26:41 +01003997 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003998 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01003999 return isolate->Throw(*isolate->factory()->NewTypeError(
4000 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004001 }
Steve Block44f0eee2011-05-26 01:26:41 +01004002 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004003 }
4004 // Check for interceptor.
4005 if (result.type() == INTERCEPTOR) {
4006 // Skip interceptor if forcing a deletion.
4007 if (mode == FORCE_DELETION) {
4008 return DeletePropertyPostInterceptor(name, mode);
4009 }
4010 return DeletePropertyWithInterceptor(name);
4011 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004012 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07004013 Object* obj;
4014 { MaybeObject* maybe_obj =
4015 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
4016 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4017 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004018 // Make sure the properties are normalized before removing the entry.
4019 return DeleteNormalizedProperty(name, mode);
4020 }
4021}
4022
4023
Ben Murdochc7cc0282012-03-05 14:35:55 +00004024MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
4025 if (IsJSProxy()) {
4026 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
4027 }
4028 return JSObject::cast(this)->DeleteElement(index, mode);
4029}
4030
4031
4032MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
4033 if (IsJSProxy()) {
4034 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
4035 }
4036 return JSObject::cast(this)->DeleteProperty(name, mode);
4037}
4038
4039
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004040bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
4041 ElementsKind kind,
4042 Object* object) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004043 ASSERT(kind == FAST_ELEMENTS ||
4044 kind == DICTIONARY_ELEMENTS);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004045 if (kind == FAST_ELEMENTS) {
4046 int length = IsJSArray()
4047 ? Smi::cast(JSArray::cast(this)->length())->value()
4048 : elements->length();
4049 for (int i = 0; i < length; ++i) {
4050 Object* element = elements->get(i);
4051 if (!element->IsTheHole() && element == object) return true;
4052 }
4053 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004054 Object* key =
4055 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004056 if (!key->IsUndefined()) return true;
4057 }
4058 return false;
4059}
4060
4061
Steve Blocka7e24c12009-10-30 11:49:00 +00004062// Check whether this object references another object.
4063bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01004064 Map* map_of_this = map();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004065 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004066 AssertNoAllocation no_alloc;
4067
4068 // Is the object the constructor for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01004069 if (map_of_this->constructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004070 return true;
4071 }
4072
4073 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01004074 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004075 return true;
4076 }
4077
4078 // Check if the object is among the named properties.
4079 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01004080 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004081 return true;
4082 }
4083
4084 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004085 ElementsKind kind = GetElementsKind();
4086 switch (kind) {
Steve Block44f0eee2011-05-26 01:26:41 +01004087 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00004088 case EXTERNAL_BYTE_ELEMENTS:
4089 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4090 case EXTERNAL_SHORT_ELEMENTS:
4091 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4092 case EXTERNAL_INT_ELEMENTS:
4093 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4094 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00004095 case EXTERNAL_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004096 case FAST_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00004097 // Raw pixels and external arrays do not reference other
4098 // objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00004099 break;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004100 case FAST_SMI_ONLY_ELEMENTS:
4101 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004102 case FAST_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00004103 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004104 FixedArray* elements = FixedArray::cast(this->elements());
4105 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00004106 break;
4107 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004108 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4109 FixedArray* parameter_map = FixedArray::cast(elements());
4110 // Check the mapped parameters.
4111 int length = parameter_map->length();
4112 for (int i = 2; i < length; ++i) {
4113 Object* value = parameter_map->get(i);
4114 if (!value->IsTheHole() && value == obj) return true;
4115 }
4116 // Check the arguments.
4117 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4118 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
4119 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00004120 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004121 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004122 }
4123
Steve Block6ded16b2010-05-10 14:33:55 +01004124 // For functions check the context.
4125 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004126 // Get the constructor function for arguments array.
4127 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +01004128 heap->isolate()->context()->global_context()->
4129 arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +00004130 JSFunction* arguments_function =
4131 JSFunction::cast(arguments_boilerplate->map()->constructor());
4132
4133 // Get the context and don't check if it is the global context.
4134 JSFunction* f = JSFunction::cast(this);
4135 Context* context = f->context();
4136 if (context->IsGlobalContext()) {
4137 return false;
4138 }
4139
4140 // Check the non-special context slots.
4141 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
4142 // Only check JS objects.
4143 if (context->get(i)->IsJSObject()) {
4144 JSObject* ctxobj = JSObject::cast(context->get(i));
4145 // If it is an arguments array check the content.
4146 if (ctxobj->map()->constructor() == arguments_function) {
4147 if (ctxobj->ReferencesObject(obj)) {
4148 return true;
4149 }
4150 } else if (ctxobj == obj) {
4151 return true;
4152 }
4153 }
4154 }
4155
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004156 // Check the context extension (if any) if it can have references.
4157 if (context->has_extension() && !context->IsCatchContext()) {
4158 return JSObject::cast(context->extension())->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00004159 }
4160 }
4161
4162 // No references to object.
4163 return false;
4164}
4165
4166
Ben Murdochc7cc0282012-03-05 14:35:55 +00004167Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
4168 CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
4169}
4170
4171
John Reck59135872010-11-02 12:39:01 -07004172MaybeObject* JSObject::PreventExtensions() {
Steve Block44f0eee2011-05-26 01:26:41 +01004173 Isolate* isolate = GetIsolate();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004174 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004175 !isolate->MayNamedAccess(this,
4176 isolate->heap()->undefined_value(),
4177 v8::ACCESS_KEYS)) {
4178 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
4179 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004180 }
4181
Steve Block1e0659c2011-05-24 12:43:12 +01004182 if (IsJSGlobalProxy()) {
4183 Object* proto = GetPrototype();
4184 if (proto->IsNull()) return this;
4185 ASSERT(proto->IsJSGlobalObject());
4186 return JSObject::cast(proto)->PreventExtensions();
4187 }
4188
Ben Murdoch257744e2011-11-30 15:57:28 +00004189 // It's not possible to seal objects with external array elements
4190 if (HasExternalArrayElements()) {
4191 HandleScope scope(isolate);
4192 Handle<Object> object(this);
4193 Handle<Object> error =
4194 isolate->factory()->NewTypeError(
4195 "cant_prevent_ext_external_array_elements",
4196 HandleVector(&object, 1));
4197 return isolate->Throw(*error);
4198 }
4199
Steve Block8defd9f2010-07-08 12:39:36 +01004200 // If there are fast elements we normalize.
Ben Murdochc7cc0282012-03-05 14:35:55 +00004201 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004202 { MaybeObject* maybe = NormalizeElements();
Ben Murdochc7cc0282012-03-05 14:35:55 +00004203 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
Steve Block8defd9f2010-07-08 12:39:36 +01004204 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004205 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Block8defd9f2010-07-08 12:39:36 +01004206 // Make sure that we never go back to fast case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004207 dictionary->set_requires_slow_elements();
Steve Block8defd9f2010-07-08 12:39:36 +01004208
4209 // Do a map transition, other objects with this map may still
4210 // be extensible.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004211 Map* new_map;
4212 { MaybeObject* maybe = map()->CopyDropTransitions();
4213 if (!maybe->To<Map>(&new_map)) return maybe;
John Reck59135872010-11-02 12:39:01 -07004214 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004215 new_map->set_is_extensible(false);
4216 set_map(new_map);
Steve Block8defd9f2010-07-08 12:39:36 +01004217 ASSERT(!map()->is_extensible());
4218 return new_map;
4219}
4220
4221
Steve Blocka7e24c12009-10-30 11:49:00 +00004222// Tests for the fast common case for property enumeration:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004223// - This object and all prototypes has an enum cache (which means that
4224// it is no proxy, has no interceptors and needs no access checks).
Steve Blockd0582a62009-12-15 09:54:21 +00004225// - This object has no elements.
4226// - No prototype has enumerable properties/elements.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004227bool JSReceiver::IsSimpleEnum() {
Steve Block44f0eee2011-05-26 01:26:41 +01004228 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004229 for (Object* o = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004230 o != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004231 o = JSObject::cast(o)->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004232 if (!o->IsJSObject()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004233 JSObject* curr = JSObject::cast(o);
Steve Blocka7e24c12009-10-30 11:49:00 +00004234 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00004235 ASSERT(!curr->HasNamedInterceptor());
4236 ASSERT(!curr->HasIndexedInterceptor());
4237 ASSERT(!curr->IsAccessCheckNeeded());
Steve Blocka7e24c12009-10-30 11:49:00 +00004238 if (curr->NumberOfEnumElements() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004239 if (curr != this) {
4240 FixedArray* curr_fixed_array =
4241 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
Steve Blockd0582a62009-12-15 09:54:21 +00004242 if (curr_fixed_array->length() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004243 }
4244 }
4245 return true;
4246}
4247
4248
4249int Map::NumberOfDescribedProperties() {
4250 int result = 0;
4251 DescriptorArray* descs = instance_descriptors();
4252 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4253 if (descs->IsProperty(i)) result++;
4254 }
4255 return result;
4256}
4257
4258
4259int Map::PropertyIndexFor(String* name) {
4260 DescriptorArray* descs = instance_descriptors();
4261 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4262 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
4263 return descs->GetFieldIndex(i);
4264 }
4265 }
4266 return -1;
4267}
4268
4269
4270int Map::NextFreePropertyIndex() {
4271 int max_index = -1;
4272 DescriptorArray* descs = instance_descriptors();
4273 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4274 if (descs->GetType(i) == FIELD) {
4275 int current_index = descs->GetFieldIndex(i);
4276 if (current_index > max_index) max_index = current_index;
4277 }
4278 }
4279 return max_index + 1;
4280}
4281
4282
4283AccessorDescriptor* Map::FindAccessor(String* name) {
4284 DescriptorArray* descs = instance_descriptors();
4285 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4286 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
4287 return descs->GetCallbacks(i);
4288 }
4289 }
4290 return NULL;
4291}
4292
4293
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004294void JSReceiver::LocalLookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004295 ASSERT(name->IsString());
4296
Steve Block44f0eee2011-05-26 01:26:41 +01004297 Heap* heap = GetHeap();
4298
Steve Blocka7e24c12009-10-30 11:49:00 +00004299 if (IsJSGlobalProxy()) {
4300 Object* proto = GetPrototype();
4301 if (proto->IsNull()) return result->NotFound();
4302 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004303 return JSReceiver::cast(proto)->LocalLookup(name, result);
4304 }
4305
4306 if (IsJSProxy()) {
4307 result->HandlerResult(JSProxy::cast(this));
4308 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004309 }
4310
4311 // Do not use inline caching if the object is a non-global object
4312 // that requires access checks.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004313 if (IsAccessCheckNeeded()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004314 result->DisallowCaching();
4315 }
4316
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004317 JSObject* js_object = JSObject::cast(this);
4318
Steve Blocka7e24c12009-10-30 11:49:00 +00004319 // Check __proto__ before interceptor.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004320 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004321 result->ConstantResult(js_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00004322 return;
4323 }
4324
4325 // Check for lookup interceptor except when bootstrapping.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004326 if (js_object->HasNamedInterceptor() &&
4327 !heap->isolate()->bootstrapper()->IsActive()) {
4328 result->InterceptorResult(js_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00004329 return;
4330 }
4331
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004332 js_object->LocalLookupRealNamedProperty(name, result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004333}
4334
4335
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004336void JSReceiver::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004337 // Ecma-262 3rd 8.6.2.4
Steve Block44f0eee2011-05-26 01:26:41 +01004338 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004339 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004340 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004341 current = JSObject::cast(current)->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004342 JSReceiver::cast(current)->LocalLookup(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00004343 if (result->IsProperty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004344 }
4345 result->NotFound();
4346}
4347
4348
4349// Search object and it's prototype chain for callback properties.
4350void JSObject::LookupCallback(String* name, LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01004351 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004352 for (Object* current = this;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004353 current != heap->null_value() && current->IsJSObject();
Steve Blocka7e24c12009-10-30 11:49:00 +00004354 current = JSObject::cast(current)->GetPrototype()) {
4355 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004356 if (result->IsFound() && result->type() == CALLBACKS) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004357 }
4358 result->NotFound();
4359}
4360
4361
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004362// Search for a getter or setter in an elements dictionary and update its
Ben Murdochc7cc0282012-03-05 14:35:55 +00004363// attributes. Returns either undefined if the element is non-deletable, or the
4364// getter/setter pair if there is an existing one, or the hole value if the
4365// element does not exist or is a normal non-getter/setter data element.
4366static Object* UpdateGetterSetterInDictionary(
4367 SeededNumberDictionary* dictionary,
4368 uint32_t index,
4369 PropertyAttributes attributes,
4370 Heap* heap) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004371 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004372 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004373 Object* result = dictionary->ValueAt(entry);
4374 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004375 // TODO(mstarzinger): We should check for details.IsDontDelete() here once
4376 // we only call into the runtime once to set both getter and setter.
4377 if (details.type() == CALLBACKS && result->IsAccessorPair()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004378 if (details.attributes() != attributes) {
4379 dictionary->DetailsAtPut(entry,
4380 PropertyDetails(attributes, CALLBACKS, index));
4381 }
4382 return result;
4383 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004384 }
4385 return heap->the_hole_value();
4386}
4387
4388
John Reck59135872010-11-02 12:39:01 -07004389MaybeObject* JSObject::DefineGetterSetter(String* name,
4390 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01004391 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004392 // Make sure that the top context does not change when doing callbacks or
4393 // interceptor calls.
4394 AssertNoContextChange ncc;
4395
Steve Blocka7e24c12009-10-30 11:49:00 +00004396 // Try to flatten before operating on the string.
Steve Block6ded16b2010-05-10 14:33:55 +01004397 name->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00004398
Leon Clarkef7060e22010-06-03 12:02:55 +01004399 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004400 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004401 }
4402
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004403 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00004404 bool is_element = name->AsArrayIndex(&index);
Steve Blocka7e24c12009-10-30 11:49:00 +00004405
4406 if (is_element) {
4407 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004408 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00004409 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004410 case FAST_DOUBLE_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00004411 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004412 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00004413 case EXTERNAL_BYTE_ELEMENTS:
4414 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4415 case EXTERNAL_SHORT_ELEMENTS:
4416 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4417 case EXTERNAL_INT_ELEMENTS:
4418 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4419 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00004420 case EXTERNAL_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00004421 // Ignore getters and setters on pixel and external array
4422 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01004423 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004424 case DICTIONARY_ELEMENTS: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004425 Object* probe = UpdateGetterSetterInDictionary(element_dictionary(),
4426 index,
4427 attributes,
4428 heap);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004429 if (!probe->IsTheHole()) return probe;
4430 // Otherwise allow to override it.
4431 break;
4432 }
4433 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4434 // Ascertain whether we have read-only properties or an existing
4435 // getter/setter pair in an arguments elements dictionary backing
4436 // store.
4437 FixedArray* parameter_map = FixedArray::cast(elements());
4438 uint32_t length = parameter_map->length();
4439 Object* probe =
4440 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
4441 if (probe == NULL || probe->IsTheHole()) {
4442 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4443 if (arguments->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004444 SeededNumberDictionary* dictionary =
4445 SeededNumberDictionary::cast(arguments);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004446 probe = UpdateGetterSetterInDictionary(dictionary,
4447 index,
4448 attributes,
4449 heap);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004450 if (!probe->IsTheHole()) return probe;
Steve Blocka7e24c12009-10-30 11:49:00 +00004451 }
4452 }
4453 break;
4454 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004455 }
4456 } else {
4457 // Lookup the name.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004458 LookupResult result(heap->isolate());
Ben Murdochc7cc0282012-03-05 14:35:55 +00004459 LocalLookupRealNamedProperty(name, &result);
4460 if (result.IsFound()) {
4461 // TODO(mstarzinger): We should check for result.IsDontDelete() here once
4462 // we only call into the runtime once to set both getter and setter.
Steve Blocka7e24c12009-10-30 11:49:00 +00004463 if (result.type() == CALLBACKS) {
4464 Object* obj = result.GetCallbackObject();
Leon Clarkef7060e22010-06-03 12:02:55 +01004465 // Need to preserve old getters/setters.
Ben Murdochc7cc0282012-03-05 14:35:55 +00004466 if (obj->IsAccessorPair()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004467 // Use set to update attributes.
4468 return SetPropertyCallback(name, obj, attributes);
Leon Clarked91b9f72010-01-27 17:25:45 +00004469 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004470 }
4471 }
4472 }
4473
Ben Murdochc7cc0282012-03-05 14:35:55 +00004474 AccessorPair* accessors;
4475 { MaybeObject* maybe_accessors = heap->AllocateAccessorPair();
4476 if (!maybe_accessors->To<AccessorPair>(&accessors)) return maybe_accessors;
John Reck59135872010-11-02 12:39:01 -07004477 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004478
4479 if (is_element) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004480 return SetElementCallback(index, accessors, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00004481 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004482 return SetPropertyCallback(name, accessors, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00004483 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004484}
4485
4486
4487bool JSObject::CanSetCallback(String* name) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004488 ASSERT(!IsAccessCheckNeeded() ||
4489 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
Leon Clarkef7060e22010-06-03 12:02:55 +01004490
4491 // Check if there is an API defined callback object which prohibits
4492 // callback overwriting in this object or it's prototype chain.
4493 // This mechanism is needed for instance in a browser setting, where
4494 // certain accessors such as window.location should not be allowed
4495 // to be overwritten because allowing overwriting could potentially
4496 // cause security problems.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004497 LookupResult callback_result(GetIsolate());
Leon Clarkef7060e22010-06-03 12:02:55 +01004498 LookupCallback(name, &callback_result);
4499 if (callback_result.IsProperty()) {
4500 Object* obj = callback_result.GetCallbackObject();
4501 if (obj->IsAccessorInfo() &&
4502 AccessorInfo::cast(obj)->prohibits_overwriting()) {
4503 return false;
4504 }
4505 }
4506
4507 return true;
4508}
4509
4510
John Reck59135872010-11-02 12:39:01 -07004511MaybeObject* JSObject::SetElementCallback(uint32_t index,
4512 Object* structure,
4513 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004514 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4515
4516 // Normalize elements to make this operation simple.
Ben Murdochc7cc0282012-03-05 14:35:55 +00004517 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004518 { Object* result;
4519 MaybeObject* maybe = NormalizeElements();
4520 if (!maybe->ToObject(&result)) return maybe;
Ben Murdochc7cc0282012-03-05 14:35:55 +00004521 dictionary = SeededNumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07004522 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004523 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Leon Clarkef7060e22010-06-03 12:02:55 +01004524
4525 // Update the dictionary with the new CALLBACKS property.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004526 { Object* result;
4527 MaybeObject* maybe = dictionary->Set(index, structure, details);
4528 if (!maybe->ToObject(&result)) return maybe;
Ben Murdochc7cc0282012-03-05 14:35:55 +00004529 dictionary = SeededNumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07004530 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004531
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004532 dictionary->set_requires_slow_elements();
4533 // Update the dictionary backing store on the object.
4534 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
4535 // Also delete any parameter alias.
4536 //
4537 // TODO(kmillikin): when deleting the last parameter alias we could
4538 // switch to a direct backing store without the parameter map. This
4539 // would allow GC of the context.
4540 FixedArray* parameter_map = FixedArray::cast(elements());
4541 uint32_t length = parameter_map->length();
4542 if (index < length - 2) {
4543 parameter_map->set(index + 2, GetHeap()->the_hole_value());
4544 }
4545 parameter_map->set(1, dictionary);
4546 } else {
4547 set_elements(dictionary);
4548 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004549
4550 return structure;
4551}
4552
4553
John Reck59135872010-11-02 12:39:01 -07004554MaybeObject* JSObject::SetPropertyCallback(String* name,
4555 Object* structure,
4556 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004557 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4558
4559 bool convert_back_to_fast = HasFastProperties() &&
4560 (map()->instance_descriptors()->number_of_descriptors()
4561 < DescriptorArray::kMaxNumberOfDescriptors);
4562
4563 // Normalize object to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07004564 Object* ok;
4565 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
4566 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4567 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004568
4569 // For the global object allocate a new map to invalidate the global inline
4570 // caches which have a global property cell reference directly in the code.
4571 if (IsGlobalObject()) {
John Reck59135872010-11-02 12:39:01 -07004572 Object* new_map;
4573 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
4574 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4575 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004576 set_map(Map::cast(new_map));
Ben Murdochb0fe1622011-05-05 13:52:32 +01004577 // When running crankshaft, changing the map is not enough. We
4578 // need to deoptimize all functions that rely on this global
4579 // object.
4580 Deoptimizer::DeoptimizeGlobalObject(this);
Leon Clarkef7060e22010-06-03 12:02:55 +01004581 }
4582
4583 // Update the dictionary with the new CALLBACKS property.
John Reck59135872010-11-02 12:39:01 -07004584 Object* result;
4585 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
4586 if (!maybe_result->ToObject(&result)) return maybe_result;
4587 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004588
4589 if (convert_back_to_fast) {
John Reck59135872010-11-02 12:39:01 -07004590 { MaybeObject* maybe_ok = TransformToFastProperties(0);
4591 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4592 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004593 }
4594 return result;
4595}
4596
John Reck59135872010-11-02 12:39:01 -07004597MaybeObject* JSObject::DefineAccessor(String* name,
4598 bool is_getter,
Ben Murdochb0fe1622011-05-05 13:52:32 +01004599 Object* fun,
John Reck59135872010-11-02 12:39:01 -07004600 PropertyAttributes attributes) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004601 ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01004602 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00004603 // Check access rights if needed.
4604 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004605 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4606 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4607 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004608 }
4609
4610 if (IsJSGlobalProxy()) {
4611 Object* proto = GetPrototype();
4612 if (proto->IsNull()) return this;
4613 ASSERT(proto->IsJSGlobalObject());
4614 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
4615 fun, attributes);
4616 }
4617
Ben Murdochc7cc0282012-03-05 14:35:55 +00004618 Object* accessors;
4619 { MaybeObject* maybe_accessors = DefineGetterSetter(name, attributes);
4620 if (!maybe_accessors->To<Object>(&accessors)) return maybe_accessors;
John Reck59135872010-11-02 12:39:01 -07004621 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00004622 if (accessors->IsUndefined()) return accessors;
4623 if (is_getter) {
4624 AccessorPair::cast(accessors)->set_getter(fun);
4625 } else {
4626 AccessorPair::cast(accessors)->set_setter(fun);
4627 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004628 return this;
4629}
4630
4631
John Reck59135872010-11-02 12:39:01 -07004632MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Steve Block44f0eee2011-05-26 01:26:41 +01004633 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01004634 String* name = String::cast(info->name());
4635 // Check access rights if needed.
4636 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004637 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4638 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4639 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004640 }
4641
4642 if (IsJSGlobalProxy()) {
4643 Object* proto = GetPrototype();
4644 if (proto->IsNull()) return this;
4645 ASSERT(proto->IsJSGlobalObject());
4646 return JSObject::cast(proto)->DefineAccessor(info);
4647 }
4648
4649 // Make sure that the top context does not change when doing callbacks or
4650 // interceptor calls.
4651 AssertNoContextChange ncc;
4652
4653 // Try to flatten before operating on the string.
4654 name->TryFlatten();
4655
4656 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004657 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004658 }
4659
4660 uint32_t index = 0;
4661 bool is_element = name->AsArrayIndex(&index);
4662
4663 if (is_element) {
Steve Block44f0eee2011-05-26 01:26:41 +01004664 if (IsJSArray()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004665
4666 // Accessors overwrite previous callbacks (cf. with getters/setters).
4667 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004668 case FAST_SMI_ONLY_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004669 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004670 case FAST_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004671 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004672 case EXTERNAL_PIXEL_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004673 case EXTERNAL_BYTE_ELEMENTS:
4674 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4675 case EXTERNAL_SHORT_ELEMENTS:
4676 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4677 case EXTERNAL_INT_ELEMENTS:
4678 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4679 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00004680 case EXTERNAL_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004681 // Ignore getters and setters on pixel and external array
4682 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01004683 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004684 case DICTIONARY_ELEMENTS:
4685 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004686 case NON_STRICT_ARGUMENTS_ELEMENTS:
4687 UNIMPLEMENTED();
Leon Clarkef7060e22010-06-03 12:02:55 +01004688 break;
4689 }
4690
John Reck59135872010-11-02 12:39:01 -07004691 Object* ok;
4692 { MaybeObject* maybe_ok =
4693 SetElementCallback(index, info, info->property_attributes());
4694 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4695 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004696 } else {
4697 // Lookup the name.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004698 LookupResult result(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01004699 LocalLookup(name, &result);
4700 // ES5 forbids turning a property into an accessor if it's not
4701 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
4702 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
Steve Block44f0eee2011-05-26 01:26:41 +01004703 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004704 }
John Reck59135872010-11-02 12:39:01 -07004705 Object* ok;
4706 { MaybeObject* maybe_ok =
4707 SetPropertyCallback(name, info, info->property_attributes());
4708 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4709 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004710 }
4711
4712 return this;
4713}
4714
4715
Steve Blocka7e24c12009-10-30 11:49:00 +00004716Object* JSObject::LookupAccessor(String* name, bool is_getter) {
Steve Block44f0eee2011-05-26 01:26:41 +01004717 Heap* heap = GetHeap();
4718
Steve Blocka7e24c12009-10-30 11:49:00 +00004719 // Make sure that the top context does not change when doing callbacks or
4720 // interceptor calls.
4721 AssertNoContextChange ncc;
4722
4723 // Check access rights if needed.
4724 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004725 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
4726 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4727 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004728 }
4729
4730 // Make the lookup and include prototypes.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004731 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00004732 if (name->AsArrayIndex(&index)) {
4733 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004734 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004735 obj = JSObject::cast(obj)->GetPrototype()) {
4736 JSObject* js_object = JSObject::cast(obj);
4737 if (js_object->HasDictionaryElements()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004738 SeededNumberDictionary* dictionary = js_object->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +00004739 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004740 if (entry != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004741 Object* element = dictionary->ValueAt(entry);
4742 PropertyDetails details = dictionary->DetailsAt(entry);
4743 if (details.type() == CALLBACKS) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004744 if (element->IsAccessorPair()) {
4745 AccessorPair* accessors = AccessorPair::cast(element);
4746 return is_getter ? accessors->getter() : accessors->setter();
Leon Clarkef7060e22010-06-03 12:02:55 +01004747 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004748 }
4749 }
4750 }
4751 }
4752 } else {
4753 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004754 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004755 obj = JSObject::cast(obj)->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004756 LookupResult result(heap->isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004757 JSObject::cast(obj)->LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00004758 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004759 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004760 if (result.type() == CALLBACKS) {
4761 Object* obj = result.GetCallbackObject();
Ben Murdochc7cc0282012-03-05 14:35:55 +00004762 if (obj->IsAccessorPair()) {
4763 AccessorPair* accessors = AccessorPair::cast(obj);
4764 return is_getter ? accessors->getter() : accessors->setter();
Steve Blocka7e24c12009-10-30 11:49:00 +00004765 }
4766 }
4767 }
4768 }
4769 }
Steve Block44f0eee2011-05-26 01:26:41 +01004770 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004771}
4772
4773
4774Object* JSObject::SlowReverseLookup(Object* value) {
4775 if (HasFastProperties()) {
4776 DescriptorArray* descs = map()->instance_descriptors();
4777 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4778 if (descs->GetType(i) == FIELD) {
4779 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
4780 return descs->GetKey(i);
4781 }
4782 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
4783 if (descs->GetConstantFunction(i) == value) {
4784 return descs->GetKey(i);
4785 }
4786 }
4787 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01004788 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004789 } else {
4790 return property_dictionary()->SlowReverseLookup(value);
4791 }
4792}
4793
4794
John Reck59135872010-11-02 12:39:01 -07004795MaybeObject* Map::CopyDropDescriptors() {
Steve Block44f0eee2011-05-26 01:26:41 +01004796 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07004797 Object* result;
4798 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004799 heap->AllocateMap(instance_type(), instance_size());
John Reck59135872010-11-02 12:39:01 -07004800 if (!maybe_result->ToObject(&result)) return maybe_result;
4801 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004802 Map::cast(result)->set_prototype(prototype());
4803 Map::cast(result)->set_constructor(constructor());
4804 // Don't copy descriptors, so map transitions always remain a forest.
4805 // If we retained the same descriptors we would have two maps
4806 // pointing to the same transition which is bad because the garbage
4807 // collector relies on being able to reverse pointers from transitions
4808 // to maps. If properties need to be retained use CopyDropTransitions.
Ben Murdoch257744e2011-11-30 15:57:28 +00004809 Map::cast(result)->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00004810 // Please note instance_type and instance_size are set when allocated.
4811 Map::cast(result)->set_inobject_properties(inobject_properties());
4812 Map::cast(result)->set_unused_property_fields(unused_property_fields());
4813
4814 // If the map has pre-allocated properties always start out with a descriptor
4815 // array describing these properties.
4816 if (pre_allocated_property_fields() > 0) {
4817 ASSERT(constructor()->IsJSFunction());
4818 JSFunction* ctor = JSFunction::cast(constructor());
John Reck59135872010-11-02 12:39:01 -07004819 Object* descriptors;
4820 { MaybeObject* maybe_descriptors =
4821 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4822 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4823 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004824 Map::cast(result)->set_instance_descriptors(
4825 DescriptorArray::cast(descriptors));
4826 Map::cast(result)->set_pre_allocated_property_fields(
4827 pre_allocated_property_fields());
4828 }
4829 Map::cast(result)->set_bit_field(bit_field());
4830 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004831 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004832 Map::cast(result)->set_is_shared(false);
Steve Block44f0eee2011-05-26 01:26:41 +01004833 Map::cast(result)->ClearCodeCache(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00004834 return result;
4835}
4836
4837
John Reck59135872010-11-02 12:39:01 -07004838MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4839 NormalizedMapSharingMode sharing) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004840 int new_instance_size = instance_size();
4841 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4842 new_instance_size -= inobject_properties() * kPointerSize;
4843 }
4844
John Reck59135872010-11-02 12:39:01 -07004845 Object* result;
4846 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004847 GetHeap()->AllocateMap(instance_type(), new_instance_size);
John Reck59135872010-11-02 12:39:01 -07004848 if (!maybe_result->ToObject(&result)) return maybe_result;
4849 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004850
4851 if (mode != CLEAR_INOBJECT_PROPERTIES) {
4852 Map::cast(result)->set_inobject_properties(inobject_properties());
4853 }
4854
4855 Map::cast(result)->set_prototype(prototype());
4856 Map::cast(result)->set_constructor(constructor());
4857
4858 Map::cast(result)->set_bit_field(bit_field());
4859 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004860 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004861
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004862 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4863
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004864#ifdef DEBUG
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004865 if (FLAG_verify_heap && Map::cast(result)->is_shared()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004866 Map::cast(result)->SharedMapVerify();
4867 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004868#endif
4869
4870 return result;
4871}
4872
4873
John Reck59135872010-11-02 12:39:01 -07004874MaybeObject* Map::CopyDropTransitions() {
4875 Object* new_map;
4876 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4877 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4878 }
4879 Object* descriptors;
4880 { MaybeObject* maybe_descriptors =
4881 instance_descriptors()->RemoveTransitions();
4882 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4883 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004884 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
Steve Block8defd9f2010-07-08 12:39:36 +01004885 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00004886}
4887
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004888void Map::UpdateCodeCache(Handle<Map> map,
4889 Handle<String> name,
4890 Handle<Code> code) {
4891 Isolate* isolate = map->GetIsolate();
4892 CALL_HEAP_FUNCTION_VOID(isolate,
4893 map->UpdateCodeCache(*name, *code));
4894}
Steve Blocka7e24c12009-10-30 11:49:00 +00004895
John Reck59135872010-11-02 12:39:01 -07004896MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004897 // Allocate the code cache if not present.
4898 if (code_cache()->IsFixedArray()) {
John Reck59135872010-11-02 12:39:01 -07004899 Object* result;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00004900 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
John Reck59135872010-11-02 12:39:01 -07004901 if (!maybe_result->ToObject(&result)) return maybe_result;
4902 }
Steve Block6ded16b2010-05-10 14:33:55 +01004903 set_code_cache(result);
4904 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004905
Steve Block6ded16b2010-05-10 14:33:55 +01004906 // Update the code cache.
4907 return CodeCache::cast(code_cache())->Update(name, code);
4908}
4909
4910
4911Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4912 // Do a lookup if a code cache exists.
4913 if (!code_cache()->IsFixedArray()) {
4914 return CodeCache::cast(code_cache())->Lookup(name, flags);
4915 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004916 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004917 }
4918}
4919
4920
4921int Map::IndexInCodeCache(Object* name, Code* code) {
4922 // Get the internal index if a code cache exists.
4923 if (!code_cache()->IsFixedArray()) {
4924 return CodeCache::cast(code_cache())->GetIndex(name, code);
4925 }
4926 return -1;
4927}
4928
4929
4930void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4931 // No GC is supposed to happen between a call to IndexInCodeCache and
4932 // RemoveFromCodeCache so the code cache must be there.
4933 ASSERT(!code_cache()->IsFixedArray());
4934 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4935}
4936
4937
Ben Murdochc7cc0282012-03-05 14:35:55 +00004938// An iterator over all map transitions in an descriptor array, reusing the map
4939// field of the contens array while it is running.
4940class IntrusiveMapTransitionIterator {
4941 public:
4942 explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array)
4943 : descriptor_array_(descriptor_array) { }
4944
4945 void Start() {
4946 ASSERT(!IsIterating());
4947 if (HasContentArray()) *ContentHeader() = Smi::FromInt(0);
4948 }
4949
4950 bool IsIterating() {
4951 return HasContentArray() && (*ContentHeader())->IsSmi();
4952 }
4953
4954 Map* Next() {
4955 ASSERT(IsIterating());
4956 FixedArray* contents = ContentArray();
4957 // Attention, tricky index manipulation ahead: Every entry in the contents
4958 // array consists of a value/details pair, so the index is typically even.
4959 // An exception is made for CALLBACKS entries: An even index means we look
4960 // at its getter, and an odd index means we look at its setter.
4961 int index = Smi::cast(*ContentHeader())->value();
4962 while (index < contents->length()) {
4963 PropertyDetails details(Smi::cast(contents->get(index | 1)));
4964 switch (details.type()) {
4965 case MAP_TRANSITION:
4966 case CONSTANT_TRANSITION:
4967 case ELEMENTS_TRANSITION:
4968 // We definitely have a map transition.
4969 *ContentHeader() = Smi::FromInt(index + 2);
4970 return static_cast<Map*>(contents->get(index));
4971 case CALLBACKS: {
4972 // We might have a map transition in a getter or in a setter.
4973 AccessorPair* accessors =
4974 static_cast<AccessorPair*>(contents->get(index & ~1));
4975 Object* accessor =
4976 ((index & 1) == 0) ? accessors->getter() : accessors->setter();
4977 index++;
4978 if (accessor->IsMap()) {
4979 *ContentHeader() = Smi::FromInt(index);
4980 return static_cast<Map*>(accessor);
4981 }
Steve Block053d10c2011-06-13 19:13:29 +01004982 break;
4983 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00004984 case NORMAL:
4985 case FIELD:
4986 case CONSTANT_FUNCTION:
4987 case HANDLER:
4988 case INTERCEPTOR:
4989 case NULL_DESCRIPTOR:
4990 // We definitely have no map transition.
4991 index += 2;
4992 break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004993 }
4994 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00004995 *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map();
4996 return NULL;
4997 }
Steve Block053d10c2011-06-13 19:13:29 +01004998
Ben Murdochc7cc0282012-03-05 14:35:55 +00004999 private:
5000 bool HasContentArray() {
5001 return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex;
5002 }
5003
5004 FixedArray* ContentArray() {
5005 Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex);
5006 return static_cast<FixedArray*>(array);
5007 }
5008
5009 Object** ContentHeader() {
5010 return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset);
5011 }
5012
5013 DescriptorArray* descriptor_array_;
5014};
5015
5016
5017// An iterator over all prototype transitions, reusing the map field of the
5018// underlying array while it is running.
5019class IntrusivePrototypeTransitionIterator {
5020 public:
5021 explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
5022 : proto_trans_(proto_trans) { }
5023
5024 void Start() {
5025 ASSERT(!IsIterating());
5026 if (HasTransitions()) *Header() = Smi::FromInt(0);
5027 }
5028
5029 bool IsIterating() {
5030 return HasTransitions() && (*Header())->IsSmi();
5031 }
5032
5033 Map* Next() {
5034 ASSERT(IsIterating());
5035 int transitionNumber = Smi::cast(*Header())->value();
5036 if (transitionNumber < NumberOfTransitions()) {
5037 *Header() = Smi::FromInt(transitionNumber + 1);
5038 return GetTransition(transitionNumber);
5039 }
5040 *Header() = proto_trans_->GetHeap()->fixed_array_map();
5041 return NULL;
5042 }
5043
5044 private:
5045 bool HasTransitions() {
5046 return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
5047 }
5048
5049 Object** Header() {
5050 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
5051 }
5052
5053 int NumberOfTransitions() {
5054 Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
5055 return Smi::cast(num)->value();
5056 }
5057
5058 Map* GetTransition(int transitionNumber) {
5059 return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
5060 }
5061
5062 int IndexFor(int transitionNumber) {
5063 return Map::kProtoTransitionHeaderSize +
5064 Map::kProtoTransitionMapOffset +
5065 transitionNumber * Map::kProtoTransitionElementsPerEntry;
5066 }
5067
5068 FixedArray* proto_trans_;
5069};
5070
5071
5072// To traverse the transition tree iteratively, we have to store two kinds of
5073// information in a map: The parent map in the traversal and which children of a
5074// node have already been visited. To do this without additional memory, we
5075// temporarily reuse two maps with known values:
5076//
5077// (1) The map of the map temporarily holds the parent, and is restored to the
5078// meta map afterwards.
5079//
5080// (2) The info which children have already been visited depends on which part
5081// of the map we currently iterate:
5082//
5083// (a) If we currently follow normal map transitions, we temporarily store
5084// the current index in the map of the FixedArray of the desciptor
5085// array's contents, and restore it to the fixed array map afterwards.
5086// Note that a single descriptor can have 0, 1, or 2 transitions.
5087//
5088// (b) If we currently follow prototype transitions, we temporarily store
5089// the current index in the map of the FixedArray holding the prototype
5090// transitions, and restore it to the fixed array map afterwards.
5091//
5092// Note that the child iterator is just a concatenation of two iterators: One
5093// iterating over map transitions and one iterating over prototype transisitons.
5094class TraversableMap : public Map {
5095 public:
5096 // Record the parent in the traversal within this map. Note that this destroys
5097 // this map's map!
5098 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
5099
5100 // Reset the current map's map, returning the parent previously stored in it.
5101 TraversableMap* GetAndResetParent() {
5102 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
5103 set_map_no_write_barrier(GetHeap()->meta_map());
5104 return old_parent;
5105 }
5106
5107 // Start iterating over this map's children, possibly destroying a FixedArray
5108 // map (see explanation above).
5109 void ChildIteratorStart() {
5110 IntrusiveMapTransitionIterator(instance_descriptors()).Start();
5111 IntrusivePrototypeTransitionIterator(
5112 unchecked_prototype_transitions()).Start();
5113 }
5114
5115 // If we have an unvisited child map, return that one and advance. If we have
5116 // none, return NULL and reset any destroyed FixedArray maps.
5117 TraversableMap* ChildIteratorNext() {
5118 IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors());
5119 if (descriptor_iterator.IsIterating()) {
5120 Map* next = descriptor_iterator.Next();
5121 if (next != NULL) return static_cast<TraversableMap*>(next);
5122 }
5123 IntrusivePrototypeTransitionIterator
5124 proto_iterator(unchecked_prototype_transitions());
5125 if (proto_iterator.IsIterating()) {
5126 Map* next = proto_iterator.Next();
5127 if (next != NULL) return static_cast<TraversableMap*>(next);
5128 }
5129 return NULL;
5130 }
5131};
5132
5133
5134// Traverse the transition tree in postorder without using the C++ stack by
5135// doing pointer reversal.
5136void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
5137 TraversableMap* current = static_cast<TraversableMap*>(this);
5138 current->ChildIteratorStart();
5139 while (true) {
5140 TraversableMap* child = current->ChildIteratorNext();
5141 if (child != NULL) {
5142 child->ChildIteratorStart();
5143 child->SetParent(current);
5144 current = child;
5145 } else {
5146 TraversableMap* parent = current->GetAndResetParent();
5147 callback(current, data);
5148 if (current == this) break;
5149 current = parent;
5150 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005151 }
5152}
5153
5154
John Reck59135872010-11-02 12:39:01 -07005155MaybeObject* CodeCache::Update(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01005156 // The number of monomorphic stubs for normal load/store/call IC's can grow to
5157 // a large number and therefore they need to go into a hash table. They are
5158 // used to load global properties from cells.
5159 if (code->type() == NORMAL) {
5160 // Make sure that a hash table is allocated for the normal load code cache.
5161 if (normal_type_cache()->IsUndefined()) {
John Reck59135872010-11-02 12:39:01 -07005162 Object* result;
5163 { MaybeObject* maybe_result =
5164 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
5165 if (!maybe_result->ToObject(&result)) return maybe_result;
5166 }
Steve Block6ded16b2010-05-10 14:33:55 +01005167 set_normal_type_cache(result);
5168 }
5169 return UpdateNormalTypeCache(name, code);
5170 } else {
5171 ASSERT(default_cache()->IsFixedArray());
5172 return UpdateDefaultCache(name, code);
5173 }
5174}
5175
5176
John Reck59135872010-11-02 12:39:01 -07005177MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01005178 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00005179 // flags. This allows call constant stubs to overwrite call field
5180 // stubs, etc.
5181 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
5182
5183 // First check whether we can update existing code cache without
5184 // extending it.
Steve Block6ded16b2010-05-10 14:33:55 +01005185 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005186 int length = cache->length();
5187 int deleted_index = -1;
Steve Block6ded16b2010-05-10 14:33:55 +01005188 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005189 Object* key = cache->get(i);
5190 if (key->IsNull()) {
5191 if (deleted_index < 0) deleted_index = i;
5192 continue;
5193 }
5194 if (key->IsUndefined()) {
5195 if (deleted_index >= 0) i = deleted_index;
Steve Block6ded16b2010-05-10 14:33:55 +01005196 cache->set(i + kCodeCacheEntryNameOffset, name);
5197 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00005198 return this;
5199 }
5200 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01005201 Code::Flags found =
5202 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
Steve Blocka7e24c12009-10-30 11:49:00 +00005203 if (Code::RemoveTypeFromFlags(found) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01005204 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00005205 return this;
5206 }
5207 }
5208 }
5209
5210 // Reached the end of the code cache. If there were deleted
5211 // elements, reuse the space for the first of them.
5212 if (deleted_index >= 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01005213 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
5214 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00005215 return this;
5216 }
5217
Steve Block6ded16b2010-05-10 14:33:55 +01005218 // Extend the code cache with some new entries (at least one). Must be a
5219 // multiple of the entry size.
5220 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
5221 new_length = new_length - new_length % kCodeCacheEntrySize;
5222 ASSERT((new_length % kCodeCacheEntrySize) == 0);
John Reck59135872010-11-02 12:39:01 -07005223 Object* result;
5224 { MaybeObject* maybe_result = cache->CopySize(new_length);
5225 if (!maybe_result->ToObject(&result)) return maybe_result;
5226 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005227
5228 // Add the (name, code) pair to the new cache.
5229 cache = FixedArray::cast(result);
Steve Block6ded16b2010-05-10 14:33:55 +01005230 cache->set(length + kCodeCacheEntryNameOffset, name);
5231 cache->set(length + kCodeCacheEntryCodeOffset, code);
5232 set_default_cache(cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00005233 return this;
5234}
5235
5236
John Reck59135872010-11-02 12:39:01 -07005237MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01005238 // Adding a new entry can cause a new cache to be allocated.
5239 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
John Reck59135872010-11-02 12:39:01 -07005240 Object* new_cache;
5241 { MaybeObject* maybe_new_cache = cache->Put(name, code);
5242 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5243 }
Steve Block6ded16b2010-05-10 14:33:55 +01005244 set_normal_type_cache(new_cache);
5245 return this;
5246}
5247
5248
5249Object* CodeCache::Lookup(String* name, Code::Flags flags) {
5250 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
5251 return LookupNormalTypeCache(name, flags);
5252 } else {
5253 return LookupDefaultCache(name, flags);
5254 }
5255}
5256
5257
5258Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
5259 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005260 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01005261 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
5262 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00005263 // Skip deleted elements.
5264 if (key->IsNull()) continue;
5265 if (key->IsUndefined()) return key;
5266 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01005267 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
5268 if (code->flags() == flags) {
5269 return code;
5270 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005271 }
5272 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01005273 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00005274}
5275
5276
Steve Block6ded16b2010-05-10 14:33:55 +01005277Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
5278 if (!normal_type_cache()->IsUndefined()) {
5279 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5280 return cache->Lookup(name, flags);
5281 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005282 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005283 }
5284}
5285
5286
5287int CodeCache::GetIndex(Object* name, Code* code) {
5288 if (code->type() == NORMAL) {
5289 if (normal_type_cache()->IsUndefined()) return -1;
5290 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5291 return cache->GetIndex(String::cast(name), code->flags());
5292 }
5293
5294 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005295 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01005296 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
5297 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00005298 }
5299 return -1;
5300}
5301
5302
Steve Block6ded16b2010-05-10 14:33:55 +01005303void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
5304 if (code->type() == NORMAL) {
5305 ASSERT(!normal_type_cache()->IsUndefined());
5306 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5307 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
5308 cache->RemoveByIndex(index);
5309 } else {
5310 FixedArray* array = default_cache();
5311 ASSERT(array->length() >= index && array->get(index)->IsCode());
5312 // Use null instead of undefined for deleted elements to distinguish
5313 // deleted elements from unused elements. This distinction is used
5314 // when looking up in the cache and when updating the cache.
5315 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
5316 array->set_null(index - 1); // Name.
5317 array->set_null(index); // Code.
5318 }
5319}
5320
5321
5322// The key in the code cache hash table consists of the property name and the
5323// code object. The actual match is on the name and the code flags. If a key
5324// is created using the flags and not a code object it can only be used for
5325// lookup not to create a new entry.
5326class CodeCacheHashTableKey : public HashTableKey {
5327 public:
5328 CodeCacheHashTableKey(String* name, Code::Flags flags)
5329 : name_(name), flags_(flags), code_(NULL) { }
5330
5331 CodeCacheHashTableKey(String* name, Code* code)
5332 : name_(name),
5333 flags_(code->flags()),
5334 code_(code) { }
5335
5336
5337 bool IsMatch(Object* other) {
5338 if (!other->IsFixedArray()) return false;
5339 FixedArray* pair = FixedArray::cast(other);
5340 String* name = String::cast(pair->get(0));
5341 Code::Flags flags = Code::cast(pair->get(1))->flags();
5342 if (flags != flags_) {
5343 return false;
5344 }
5345 return name_->Equals(name);
5346 }
5347
5348 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
5349 return name->Hash() ^ flags;
5350 }
5351
5352 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
5353
5354 uint32_t HashForObject(Object* obj) {
5355 FixedArray* pair = FixedArray::cast(obj);
5356 String* name = String::cast(pair->get(0));
5357 Code* code = Code::cast(pair->get(1));
5358 return NameFlagsHashHelper(name, code->flags());
5359 }
5360
John Reck59135872010-11-02 12:39:01 -07005361 MUST_USE_RESULT MaybeObject* AsObject() {
Steve Block6ded16b2010-05-10 14:33:55 +01005362 ASSERT(code_ != NULL);
John Reck59135872010-11-02 12:39:01 -07005363 Object* obj;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005364 { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07005365 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5366 }
Steve Block6ded16b2010-05-10 14:33:55 +01005367 FixedArray* pair = FixedArray::cast(obj);
5368 pair->set(0, name_);
5369 pair->set(1, code_);
5370 return pair;
5371 }
5372
5373 private:
5374 String* name_;
5375 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005376 // TODO(jkummerow): We should be able to get by without this.
Steve Block6ded16b2010-05-10 14:33:55 +01005377 Code* code_;
5378};
5379
5380
5381Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
5382 CodeCacheHashTableKey key(name, flags);
5383 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01005384 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005385 return get(EntryToIndex(entry) + 1);
5386}
5387
5388
John Reck59135872010-11-02 12:39:01 -07005389MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01005390 CodeCacheHashTableKey key(name, code);
John Reck59135872010-11-02 12:39:01 -07005391 Object* obj;
5392 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5393 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5394 }
Steve Block6ded16b2010-05-10 14:33:55 +01005395
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005396 // Don't use |this|, as the table might have grown.
Steve Block6ded16b2010-05-10 14:33:55 +01005397 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
5398
5399 int entry = cache->FindInsertionEntry(key.Hash());
John Reck59135872010-11-02 12:39:01 -07005400 Object* k;
5401 { MaybeObject* maybe_k = key.AsObject();
5402 if (!maybe_k->ToObject(&k)) return maybe_k;
5403 }
Steve Block6ded16b2010-05-10 14:33:55 +01005404
5405 cache->set(EntryToIndex(entry), k);
5406 cache->set(EntryToIndex(entry) + 1, code);
5407 cache->ElementAdded();
5408 return cache;
5409}
5410
5411
5412int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
5413 CodeCacheHashTableKey key(name, flags);
5414 int entry = FindEntry(&key);
5415 return (entry == kNotFound) ? -1 : entry;
5416}
5417
5418
5419void CodeCacheHashTable::RemoveByIndex(int index) {
5420 ASSERT(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01005421 Heap* heap = GetHeap();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005422 set(EntryToIndex(index), heap->the_hole_value());
5423 set(EntryToIndex(index) + 1, heap->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01005424 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00005425}
5426
5427
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005428void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
5429 MapHandleList* maps,
5430 Code::Flags flags,
5431 Handle<Code> code) {
5432 Isolate* isolate = cache->GetIsolate();
5433 CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
5434}
5435
5436
5437MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005438 Code::Flags flags,
5439 Code* code) {
5440 // Initialize cache if necessary.
5441 if (cache()->IsUndefined()) {
5442 Object* result;
5443 { MaybeObject* maybe_result =
5444 PolymorphicCodeCacheHashTable::Allocate(
5445 PolymorphicCodeCacheHashTable::kInitialSize);
5446 if (!maybe_result->ToObject(&result)) return maybe_result;
5447 }
5448 set_cache(result);
5449 } else {
5450 // This entry shouldn't be contained in the cache yet.
5451 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
5452 ->Lookup(maps, flags)->IsUndefined());
5453 }
5454 PolymorphicCodeCacheHashTable* hash_table =
5455 PolymorphicCodeCacheHashTable::cast(cache());
5456 Object* new_cache;
5457 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
5458 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5459 }
5460 set_cache(new_cache);
5461 return this;
5462}
5463
5464
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005465Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
5466 Code::Flags flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005467 if (!cache()->IsUndefined()) {
5468 PolymorphicCodeCacheHashTable* hash_table =
5469 PolymorphicCodeCacheHashTable::cast(cache());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005470 return Handle<Object>(hash_table->Lookup(maps, flags));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005471 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005472 return GetIsolate()->factory()->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005473 }
5474}
5475
5476
5477// Despite their name, object of this class are not stored in the actual
5478// hash table; instead they're temporarily used for lookups. It is therefore
5479// safe to have a weak (non-owning) pointer to a MapList as a member field.
5480class PolymorphicCodeCacheHashTableKey : public HashTableKey {
5481 public:
5482 // Callers must ensure that |maps| outlives the newly constructed object.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005483 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005484 : maps_(maps),
5485 code_flags_(code_flags) {}
5486
5487 bool IsMatch(Object* other) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005488 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005489 int other_flags;
5490 FromObject(other, &other_flags, &other_maps);
5491 if (code_flags_ != other_flags) return false;
5492 if (maps_->length() != other_maps.length()) return false;
5493 // Compare just the hashes first because it's faster.
5494 int this_hash = MapsHashHelper(maps_, code_flags_);
5495 int other_hash = MapsHashHelper(&other_maps, other_flags);
5496 if (this_hash != other_hash) return false;
5497
5498 // Full comparison: for each map in maps_, look for an equivalent map in
5499 // other_maps. This implementation is slow, but probably good enough for
5500 // now because the lists are short (<= 4 elements currently).
5501 for (int i = 0; i < maps_->length(); ++i) {
5502 bool match_found = false;
5503 for (int j = 0; j < other_maps.length(); ++j) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005504 if (maps_->at(i)->EquivalentTo(*other_maps.at(j))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005505 match_found = true;
5506 break;
5507 }
5508 }
5509 if (!match_found) return false;
5510 }
5511 return true;
5512 }
5513
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005514 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005515 uint32_t hash = code_flags;
5516 for (int i = 0; i < maps->length(); ++i) {
5517 hash ^= maps->at(i)->Hash();
5518 }
5519 return hash;
5520 }
5521
5522 uint32_t Hash() {
5523 return MapsHashHelper(maps_, code_flags_);
5524 }
5525
5526 uint32_t HashForObject(Object* obj) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005527 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005528 int other_flags;
5529 FromObject(obj, &other_flags, &other_maps);
5530 return MapsHashHelper(&other_maps, other_flags);
5531 }
5532
5533 MUST_USE_RESULT MaybeObject* AsObject() {
5534 Object* obj;
5535 // The maps in |maps_| must be copied to a newly allocated FixedArray,
5536 // both because the referenced MapList is short-lived, and because C++
5537 // objects can't be stored in the heap anyway.
5538 { MaybeObject* maybe_obj =
5539 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
5540 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5541 }
5542 FixedArray* list = FixedArray::cast(obj);
5543 list->set(0, Smi::FromInt(code_flags_));
5544 for (int i = 0; i < maps_->length(); ++i) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005545 list->set(i + 1, *maps_->at(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005546 }
5547 return list;
5548 }
5549
5550 private:
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005551 static MapHandleList* FromObject(Object* obj,
5552 int* code_flags,
5553 MapHandleList* maps) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005554 FixedArray* list = FixedArray::cast(obj);
5555 maps->Rewind(0);
5556 *code_flags = Smi::cast(list->get(0))->value();
5557 for (int i = 1; i < list->length(); ++i) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005558 maps->Add(Handle<Map>(Map::cast(list->get(i))));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005559 }
5560 return maps;
5561 }
5562
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005563 MapHandleList* maps_; // weak.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005564 int code_flags_;
5565 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
5566};
5567
5568
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005569Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
5570 int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005571 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5572 int entry = FindEntry(&key);
5573 if (entry == kNotFound) return GetHeap()->undefined_value();
5574 return get(EntryToIndex(entry) + 1);
5575}
5576
5577
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005578MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005579 int code_flags,
5580 Code* code) {
5581 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5582 Object* obj;
5583 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5584 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5585 }
5586 PolymorphicCodeCacheHashTable* cache =
5587 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
5588 int entry = cache->FindInsertionEntry(key.Hash());
5589 { MaybeObject* maybe_obj = key.AsObject();
5590 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5591 }
5592 cache->set(EntryToIndex(entry), obj);
5593 cache->set(EntryToIndex(entry) + 1, code);
5594 cache->ElementAdded();
5595 return cache;
5596}
5597
5598
John Reck59135872010-11-02 12:39:01 -07005599MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005600 ElementsAccessor* accessor = array->GetElementsAccessor();
5601 MaybeObject* maybe_result =
5602 accessor->AddElementsToFixedArray(array->elements(), this, array, array);
5603 FixedArray* result;
5604 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
5605#ifdef DEBUG
5606 if (FLAG_enable_slow_asserts) {
5607 for (int i = 0; i < result->length(); i++) {
5608 Object* current = result->get(i);
5609 ASSERT(current->IsNumber() || current->IsString());
Steve Blocka7e24c12009-10-30 11:49:00 +00005610 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005611 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005612#endif
5613 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00005614}
5615
5616
John Reck59135872010-11-02 12:39:01 -07005617MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005618 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
5619 MaybeObject* maybe_result =
5620 accessor->AddElementsToFixedArray(other, this, NULL, NULL);
5621 FixedArray* result;
5622 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
Ben Murdochf87a2032010-10-22 12:50:53 +01005623#ifdef DEBUG
5624 if (FLAG_enable_slow_asserts) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005625 for (int i = 0; i < result->length(); i++) {
5626 Object* current = result->get(i);
5627 ASSERT(current->IsNumber() || current->IsString());
Ben Murdochf87a2032010-10-22 12:50:53 +01005628 }
5629 }
5630#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00005631 return result;
5632}
5633
5634
John Reck59135872010-11-02 12:39:01 -07005635MaybeObject* FixedArray::CopySize(int new_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01005636 Heap* heap = GetHeap();
5637 if (new_length == 0) return heap->empty_fixed_array();
John Reck59135872010-11-02 12:39:01 -07005638 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01005639 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
John Reck59135872010-11-02 12:39:01 -07005640 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5641 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005642 FixedArray* result = FixedArray::cast(obj);
5643 // Copy the content
Leon Clarke4515c472010-02-03 11:58:03 +00005644 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00005645 int len = length();
5646 if (new_length < len) len = new_length;
Ben Murdochc7cc0282012-03-05 14:35:55 +00005647 // We are taking the map from the old fixed array so the map is sure to
5648 // be an immortal immutable object.
5649 result->set_map_no_write_barrier(map());
Leon Clarke4515c472010-02-03 11:58:03 +00005650 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00005651 for (int i = 0; i < len; i++) {
5652 result->set(i, get(i), mode);
5653 }
5654 return result;
5655}
5656
5657
5658void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Leon Clarke4515c472010-02-03 11:58:03 +00005659 AssertNoAllocation no_gc;
5660 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00005661 for (int index = 0; index < len; index++) {
5662 dest->set(dest_pos+index, get(pos+index), mode);
5663 }
5664}
5665
5666
5667#ifdef DEBUG
5668bool FixedArray::IsEqualTo(FixedArray* other) {
5669 if (length() != other->length()) return false;
5670 for (int i = 0 ; i < length(); ++i) {
5671 if (get(i) != other->get(i)) return false;
5672 }
5673 return true;
5674}
5675#endif
5676
5677
John Reck59135872010-11-02 12:39:01 -07005678MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01005679 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005680 if (number_of_descriptors == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01005681 return heap->empty_descriptor_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00005682 }
5683 // Allocate the array of keys.
John Reck59135872010-11-02 12:39:01 -07005684 Object* array;
5685 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01005686 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
John Reck59135872010-11-02 12:39:01 -07005687 if (!maybe_array->ToObject(&array)) return maybe_array;
5688 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005689 // Do not use DescriptorArray::cast on incomplete object.
5690 FixedArray* result = FixedArray::cast(array);
5691
5692 // Allocate the content array and set it in the descriptor array.
John Reck59135872010-11-02 12:39:01 -07005693 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01005694 heap->AllocateFixedArray(number_of_descriptors << 1);
John Reck59135872010-11-02 12:39:01 -07005695 if (!maybe_array->ToObject(&array)) return maybe_array;
5696 }
Ben Murdoch257744e2011-11-30 15:57:28 +00005697 result->set(kBitField3StorageIndex, Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00005698 result->set(kContentArrayIndex, array);
5699 result->set(kEnumerationIndexIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00005700 Smi::FromInt(PropertyDetails::kInitialIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00005701 return result;
5702}
5703
5704
5705void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
5706 FixedArray* new_cache) {
5707 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
5708 if (HasEnumCache()) {
5709 FixedArray::cast(get(kEnumerationIndexIndex))->
5710 set(kEnumCacheBridgeCacheIndex, new_cache);
5711 } else {
5712 if (IsEmpty()) return; // Do nothing for empty descriptor array.
5713 FixedArray::cast(bridge_storage)->
5714 set(kEnumCacheBridgeCacheIndex, new_cache);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005715 NoWriteBarrierSet(FixedArray::cast(bridge_storage),
5716 kEnumCacheBridgeEnumIndex,
5717 get(kEnumerationIndexIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00005718 set(kEnumerationIndexIndex, bridge_storage);
5719 }
5720}
5721
5722
John Reck59135872010-11-02 12:39:01 -07005723MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
5724 TransitionFlag transition_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005725 // Transitions are only kept when inserting another transition.
5726 // This precondition is not required by this function's implementation, but
5727 // is currently required by the semantics of maps, so we check it.
5728 // Conversely, we filter after replacing, so replacing a transition and
5729 // removing all other transitions is not supported.
5730 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
5731 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
5732 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
5733
5734 // Ensure the key is a symbol.
John Reck59135872010-11-02 12:39:01 -07005735 Object* result;
5736 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
5737 if (!maybe_result->ToObject(&result)) return maybe_result;
5738 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005739
5740 int transitions = 0;
5741 int null_descriptors = 0;
5742 if (remove_transitions) {
5743 for (int i = 0; i < number_of_descriptors(); i++) {
5744 if (IsTransition(i)) transitions++;
5745 if (IsNullDescriptor(i)) null_descriptors++;
5746 }
5747 } else {
5748 for (int i = 0; i < number_of_descriptors(); i++) {
5749 if (IsNullDescriptor(i)) null_descriptors++;
5750 }
5751 }
5752 int new_size = number_of_descriptors() - transitions - null_descriptors;
5753
5754 // If key is in descriptor, we replace it in-place when filtering.
5755 // Count a null descriptor for key as inserted, not replaced.
5756 int index = Search(descriptor->GetKey());
5757 const bool inserting = (index == kNotFound);
5758 const bool replacing = !inserting;
5759 bool keep_enumeration_index = false;
5760 if (inserting) {
5761 ++new_size;
5762 }
5763 if (replacing) {
5764 // We are replacing an existing descriptor. We keep the enumeration
5765 // index of a visible property.
5766 PropertyType t = PropertyDetails(GetDetails(index)).type();
5767 if (t == CONSTANT_FUNCTION ||
5768 t == FIELD ||
5769 t == CALLBACKS ||
5770 t == INTERCEPTOR) {
5771 keep_enumeration_index = true;
5772 } else if (remove_transitions) {
5773 // Replaced descriptor has been counted as removed if it is
5774 // a transition that will be replaced. Adjust count in this case.
5775 ++new_size;
5776 }
5777 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005778
5779 DescriptorArray* new_descriptors;
John Reck59135872010-11-02 12:39:01 -07005780 { MaybeObject* maybe_result = Allocate(new_size);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005781 if (!maybe_result->To<DescriptorArray>(&new_descriptors)) {
5782 return maybe_result;
5783 }
John Reck59135872010-11-02 12:39:01 -07005784 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005785
5786 DescriptorArray::WhitenessWitness witness(new_descriptors);
5787
Steve Blocka7e24c12009-10-30 11:49:00 +00005788 // Set the enumeration index in the descriptors and set the enumeration index
5789 // in the result.
5790 int enumeration_index = NextEnumerationIndex();
5791 if (!descriptor->GetDetails().IsTransition()) {
5792 if (keep_enumeration_index) {
5793 descriptor->SetEnumerationIndex(
5794 PropertyDetails(GetDetails(index)).index());
5795 } else {
5796 descriptor->SetEnumerationIndex(enumeration_index);
5797 ++enumeration_index;
5798 }
5799 }
5800 new_descriptors->SetNextEnumerationIndex(enumeration_index);
5801
5802 // Copy the descriptors, filtering out transitions and null descriptors,
5803 // and inserting or replacing a descriptor.
5804 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
5805 int from_index = 0;
5806 int to_index = 0;
5807
5808 for (; from_index < number_of_descriptors(); from_index++) {
5809 String* key = GetKey(from_index);
5810 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
5811 break;
5812 }
5813 if (IsNullDescriptor(from_index)) continue;
5814 if (remove_transitions && IsTransition(from_index)) continue;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005815 new_descriptors->CopyFrom(to_index++, this, from_index, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +00005816 }
5817
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005818 new_descriptors->Set(to_index++, descriptor, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +00005819 if (replacing) from_index++;
5820
5821 for (; from_index < number_of_descriptors(); from_index++) {
5822 if (IsNullDescriptor(from_index)) continue;
5823 if (remove_transitions && IsTransition(from_index)) continue;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005824 new_descriptors->CopyFrom(to_index++, this, from_index, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +00005825 }
5826
5827 ASSERT(to_index == new_descriptors->number_of_descriptors());
5828 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
5829
5830 return new_descriptors;
5831}
5832
5833
John Reck59135872010-11-02 12:39:01 -07005834MaybeObject* DescriptorArray::RemoveTransitions() {
Steve Blocka7e24c12009-10-30 11:49:00 +00005835 // Remove all transitions and null descriptors. Return a copy of the array
5836 // with all transitions removed, or a Failure object if the new array could
5837 // not be allocated.
5838
5839 // Compute the size of the map transition entries to be removed.
5840 int num_removed = 0;
5841 for (int i = 0; i < number_of_descriptors(); i++) {
5842 if (!IsProperty(i)) num_removed++;
5843 }
5844
5845 // Allocate the new descriptor array.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005846 DescriptorArray* new_descriptors;
John Reck59135872010-11-02 12:39:01 -07005847 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005848 if (!maybe_result->To<DescriptorArray>(&new_descriptors)) {
5849 return maybe_result;
5850 }
John Reck59135872010-11-02 12:39:01 -07005851 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005852
5853 DescriptorArray::WhitenessWitness witness(new_descriptors);
Steve Blocka7e24c12009-10-30 11:49:00 +00005854
5855 // Copy the content.
5856 int next_descriptor = 0;
5857 for (int i = 0; i < number_of_descriptors(); i++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005858 if (IsProperty(i)) {
5859 new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
5860 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005861 }
5862 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
5863
5864 return new_descriptors;
5865}
5866
5867
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005868void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005869 // In-place heap sort.
5870 int len = number_of_descriptors();
5871
5872 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01005873 // Index of the last node with children
5874 const int max_parent_index = (len / 2) - 1;
5875 for (int i = max_parent_index; i >= 0; --i) {
5876 int parent_index = i;
5877 const uint32_t parent_hash = GetKey(i)->Hash();
5878 while (parent_index <= max_parent_index) {
5879 int child_index = 2 * parent_index + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00005880 uint32_t child_hash = GetKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01005881 if (child_index + 1 < len) {
5882 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5883 if (right_child_hash > child_hash) {
5884 child_index++;
5885 child_hash = right_child_hash;
5886 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005887 }
Steve Block6ded16b2010-05-10 14:33:55 +01005888 if (child_hash <= parent_hash) break;
Ben Murdochc7cc0282012-03-05 14:35:55 +00005889 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01005890 // Now element at child_index could be < its children.
5891 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00005892 }
5893 }
5894
5895 // Extract elements and create sorted array.
5896 for (int i = len - 1; i > 0; --i) {
5897 // Put max element at the back of the array.
Ben Murdochc7cc0282012-03-05 14:35:55 +00005898 NoIncrementalWriteBarrierSwapDescriptors(0, i);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005899 // Shift down the new top element.
Steve Blocka7e24c12009-10-30 11:49:00 +00005900 int parent_index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01005901 const uint32_t parent_hash = GetKey(parent_index)->Hash();
5902 const int max_parent_index = (i / 2) - 1;
5903 while (parent_index <= max_parent_index) {
5904 int child_index = parent_index * 2 + 1;
5905 uint32_t child_hash = GetKey(child_index)->Hash();
5906 if (child_index + 1 < i) {
5907 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5908 if (right_child_hash > child_hash) {
5909 child_index++;
5910 child_hash = right_child_hash;
5911 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005912 }
Steve Block6ded16b2010-05-10 14:33:55 +01005913 if (child_hash <= parent_hash) break;
Ben Murdochc7cc0282012-03-05 14:35:55 +00005914 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01005915 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00005916 }
5917 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005918}
Steve Blocka7e24c12009-10-30 11:49:00 +00005919
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005920
Ben Murdoch592a9fc2012-03-05 11:04:45 +00005921void DescriptorArray::Sort(const WhitenessWitness& witness) {
5922 SortUnchecked(witness);
Steve Blocka7e24c12009-10-30 11:49:00 +00005923 SLOW_ASSERT(IsSortedNoDuplicates());
5924}
5925
5926
5927int DescriptorArray::BinarySearch(String* name, int low, int high) {
5928 uint32_t hash = name->Hash();
5929
5930 while (low <= high) {
5931 int mid = (low + high) / 2;
5932 String* mid_name = GetKey(mid);
5933 uint32_t mid_hash = mid_name->Hash();
5934
5935 if (mid_hash > hash) {
5936 high = mid - 1;
5937 continue;
5938 }
5939 if (mid_hash < hash) {
5940 low = mid + 1;
5941 continue;
5942 }
5943 // Found an element with the same hash-code.
5944 ASSERT(hash == mid_hash);
5945 // There might be more, so we find the first one and
5946 // check them all to see if we have a match.
5947 if (name == mid_name && !is_null_descriptor(mid)) return mid;
5948 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
5949 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
5950 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
5951 }
5952 break;
5953 }
5954 return kNotFound;
5955}
5956
5957
5958int DescriptorArray::LinearSearch(String* name, int len) {
5959 uint32_t hash = name->Hash();
5960 for (int number = 0; number < len; number++) {
5961 String* entry = GetKey(number);
5962 if ((entry->Hash() == hash) &&
5963 name->Equals(entry) &&
5964 !is_null_descriptor(number)) {
5965 return number;
5966 }
5967 }
5968 return kNotFound;
5969}
5970
5971
Ben Murdochb0fe1622011-05-05 13:52:32 +01005972MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5973 PretenureFlag pretenure) {
5974 ASSERT(deopt_entry_count > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01005975 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005976 pretenure);
5977}
5978
5979
5980MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5981 PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01005982 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5983 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005984 pretenure);
5985}
5986
5987
Steve Blocka7e24c12009-10-30 11:49:00 +00005988#ifdef DEBUG
5989bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5990 if (IsEmpty()) return other->IsEmpty();
5991 if (other->IsEmpty()) return false;
5992 if (length() != other->length()) return false;
5993 for (int i = 0; i < length(); ++i) {
5994 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5995 }
5996 return GetContentArray()->IsEqualTo(other->GetContentArray());
5997}
5998#endif
5999
6000
Steve Blocka7e24c12009-10-30 11:49:00 +00006001bool String::LooksValid() {
Steve Block44f0eee2011-05-26 01:26:41 +01006002 if (!Isolate::Current()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00006003 return true;
6004}
6005
6006
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006007String::FlatContent String::GetFlatContent() {
Steve Blocka7e24c12009-10-30 11:49:00 +00006008 int length = this->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006009 StringShape shape(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00006010 String* string = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00006011 int offset = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006012 if (shape.representation_tag() == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006013 ConsString* cons = ConsString::cast(string);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006014 if (cons->second()->length() != 0) {
6015 return FlatContent();
6016 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006017 string = cons->first();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006018 shape = StringShape(string);
Steve Blocka7e24c12009-10-30 11:49:00 +00006019 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006020 if (shape.representation_tag() == kSlicedStringTag) {
6021 SlicedString* slice = SlicedString::cast(string);
6022 offset = slice->offset();
6023 string = slice->parent();
6024 shape = StringShape(string);
6025 ASSERT(shape.representation_tag() != kConsStringTag &&
6026 shape.representation_tag() != kSlicedStringTag);
Steve Blocka7e24c12009-10-30 11:49:00 +00006027 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006028 if (shape.encoding_tag() == kAsciiStringTag) {
6029 const char* start;
6030 if (shape.representation_tag() == kSeqStringTag) {
6031 start = SeqAsciiString::cast(string)->GetChars();
6032 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006033 start = ExternalAsciiString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006034 }
6035 return FlatContent(Vector<const char>(start + offset, length));
6036 } else {
6037 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
6038 const uc16* start;
6039 if (shape.representation_tag() == kSeqStringTag) {
6040 start = SeqTwoByteString::cast(string)->GetChars();
6041 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006042 start = ExternalTwoByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006043 }
6044 return FlatContent(Vector<const uc16>(start + offset, length));
6045 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006046}
6047
6048
Ben Murdoch589d6972011-11-30 16:04:58 +00006049SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6050 RobustnessFlag robust_flag,
6051 int offset,
6052 int length,
6053 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006054 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00006055 return SmartArrayPointer<char>(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00006056 }
Steve Block44f0eee2011-05-26 01:26:41 +01006057 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006058
6059 // Negative length means the to the end of the string.
6060 if (length < 0) length = kMaxInt - offset;
6061
6062 // Compute the size of the UTF-8 string. Start at the specified offset.
Steve Block44f0eee2011-05-26 01:26:41 +01006063 Access<StringInputBuffer> buffer(
6064 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00006065 buffer->Reset(offset, this);
6066 int character_position = offset;
6067 int utf8_bytes = 0;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006068 while (buffer->has_more() && character_position++ < offset + length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006069 uint16_t character = buffer->GetNext();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006070 utf8_bytes += unibrow::Utf8::Length(character);
Steve Blocka7e24c12009-10-30 11:49:00 +00006071 }
6072
6073 if (length_return) {
6074 *length_return = utf8_bytes;
6075 }
6076
6077 char* result = NewArray<char>(utf8_bytes + 1);
6078
6079 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
6080 buffer->Rewind();
6081 buffer->Seek(offset);
6082 character_position = offset;
6083 int utf8_byte_position = 0;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006084 while (buffer->has_more() && character_position++ < offset + length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006085 uint16_t character = buffer->GetNext();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006086 if (allow_nulls == DISALLOW_NULLS && character == 0) {
6087 character = ' ';
Steve Blocka7e24c12009-10-30 11:49:00 +00006088 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006089 utf8_byte_position +=
6090 unibrow::Utf8::Encode(result + utf8_byte_position, character);
Steve Blocka7e24c12009-10-30 11:49:00 +00006091 }
6092 result[utf8_byte_position] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00006093 return SmartArrayPointer<char>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00006094}
6095
6096
Ben Murdoch589d6972011-11-30 16:04:58 +00006097SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6098 RobustnessFlag robust_flag,
6099 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006100 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
6101}
6102
6103
6104const uc16* String::GetTwoByteData() {
6105 return GetTwoByteData(0);
6106}
6107
6108
6109const uc16* String::GetTwoByteData(unsigned start) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006110 ASSERT(!IsAsciiRepresentationUnderneath());
Steve Blocka7e24c12009-10-30 11:49:00 +00006111 switch (StringShape(this).representation_tag()) {
6112 case kSeqStringTag:
6113 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
6114 case kExternalStringTag:
6115 return ExternalTwoByteString::cast(this)->
6116 ExternalTwoByteStringGetData(start);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006117 case kSlicedStringTag: {
6118 SlicedString* slice = SlicedString::cast(this);
6119 return slice->parent()->GetTwoByteData(start + slice->offset());
6120 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006121 case kConsStringTag:
6122 UNREACHABLE();
6123 return NULL;
6124 }
6125 UNREACHABLE();
6126 return NULL;
6127}
6128
6129
Ben Murdoch589d6972011-11-30 16:04:58 +00006130SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006131 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00006132 return SmartArrayPointer<uc16>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006133 }
Steve Block44f0eee2011-05-26 01:26:41 +01006134 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006135
Steve Block44f0eee2011-05-26 01:26:41 +01006136 Access<StringInputBuffer> buffer(
6137 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00006138 buffer->Reset(this);
6139
6140 uc16* result = NewArray<uc16>(length() + 1);
6141
6142 int i = 0;
6143 while (buffer->has_more()) {
6144 uint16_t character = buffer->GetNext();
6145 result[i++] = character;
6146 }
6147 result[i] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00006148 return SmartArrayPointer<uc16>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00006149}
6150
6151
6152const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
6153 return reinterpret_cast<uc16*>(
6154 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
6155}
6156
6157
6158void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6159 unsigned* offset_ptr,
6160 unsigned max_chars) {
6161 unsigned chars_read = 0;
6162 unsigned offset = *offset_ptr;
6163 while (chars_read < max_chars) {
6164 uint16_t c = *reinterpret_cast<uint16_t*>(
6165 reinterpret_cast<char*>(this) -
6166 kHeapObjectTag + kHeaderSize + offset * kShortSize);
6167 if (c <= kMaxAsciiCharCode) {
6168 // Fast case for ASCII characters. Cursor is an input output argument.
6169 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6170 rbb->util_buffer,
6171 rbb->capacity,
6172 rbb->cursor)) {
6173 break;
6174 }
6175 } else {
6176 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6177 rbb->util_buffer,
6178 rbb->capacity,
6179 rbb->cursor)) {
6180 break;
6181 }
6182 }
6183 offset++;
6184 chars_read++;
6185 }
6186 *offset_ptr = offset;
6187 rbb->remaining += chars_read;
6188}
6189
6190
6191const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
6192 unsigned* remaining,
6193 unsigned* offset_ptr,
6194 unsigned max_chars) {
6195 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
6196 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
6197 *remaining = max_chars;
6198 *offset_ptr += max_chars;
6199 return b;
6200}
6201
6202
6203// This will iterate unless the block of string data spans two 'halves' of
6204// a ConsString, in which case it will recurse. Since the block of string
6205// data to be read has a maximum size this limits the maximum recursion
6206// depth to something sane. Since C++ does not have tail call recursion
6207// elimination, the iteration must be explicit. Since this is not an
6208// -IntoBuffer method it can delegate to one of the efficient
6209// *AsciiStringReadBlock routines.
6210const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
6211 unsigned* offset_ptr,
6212 unsigned max_chars) {
6213 ConsString* current = this;
6214 unsigned offset = *offset_ptr;
6215 int offset_correction = 0;
6216
6217 while (true) {
6218 String* left = current->first();
6219 unsigned left_length = (unsigned)left->length();
6220 if (left_length > offset &&
6221 (max_chars <= left_length - offset ||
6222 (rbb->capacity <= left_length - offset &&
6223 (max_chars = left_length - offset, true)))) { // comma operator!
6224 // Left hand side only - iterate unless we have reached the bottom of
6225 // the cons tree. The assignment on the left of the comma operator is
6226 // in order to make use of the fact that the -IntoBuffer routines can
6227 // produce at most 'capacity' characters. This enables us to postpone
6228 // the point where we switch to the -IntoBuffer routines (below) in order
6229 // to maximize the chances of delegating a big chunk of work to the
6230 // efficient *AsciiStringReadBlock routines.
6231 if (StringShape(left).IsCons()) {
6232 current = ConsString::cast(left);
6233 continue;
6234 } else {
6235 const unibrow::byte* answer =
6236 String::ReadBlock(left, rbb, &offset, max_chars);
6237 *offset_ptr = offset + offset_correction;
6238 return answer;
6239 }
6240 } else if (left_length <= offset) {
6241 // Right hand side only - iterate unless we have reached the bottom of
6242 // the cons tree.
6243 String* right = current->second();
6244 offset -= left_length;
6245 offset_correction += left_length;
6246 if (StringShape(right).IsCons()) {
6247 current = ConsString::cast(right);
6248 continue;
6249 } else {
6250 const unibrow::byte* answer =
6251 String::ReadBlock(right, rbb, &offset, max_chars);
6252 *offset_ptr = offset + offset_correction;
6253 return answer;
6254 }
6255 } else {
6256 // The block to be read spans two sides of the ConsString, so we call the
6257 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
6258 // are able to assemble data from several part strings because they use
6259 // the util_buffer to store their data and never return direct pointers
6260 // to their storage. We don't try to read more than the buffer capacity
6261 // here or we can get too much recursion.
6262 ASSERT(rbb->remaining == 0);
6263 ASSERT(rbb->cursor == 0);
6264 current->ConsStringReadBlockIntoBuffer(
6265 rbb,
6266 &offset,
6267 max_chars > rbb->capacity ? rbb->capacity : max_chars);
6268 *offset_ptr = offset + offset_correction;
6269 return rbb->util_buffer;
6270 }
6271 }
6272}
6273
6274
Steve Blocka7e24c12009-10-30 11:49:00 +00006275const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
6276 unsigned* remaining,
6277 unsigned* offset_ptr,
6278 unsigned max_chars) {
6279 // Cast const char* to unibrow::byte* (signedness difference).
6280 const unibrow::byte* b =
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006281 reinterpret_cast<const unibrow::byte*>(GetChars()) + *offset_ptr;
Steve Blocka7e24c12009-10-30 11:49:00 +00006282 *remaining = max_chars;
6283 *offset_ptr += max_chars;
6284 return b;
6285}
6286
6287
Steve Blocka7e24c12009-10-30 11:49:00 +00006288void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
6289 ReadBlockBuffer* rbb,
6290 unsigned* offset_ptr,
6291 unsigned max_chars) {
6292 unsigned chars_read = 0;
6293 unsigned offset = *offset_ptr;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006294 const uint16_t* data = GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006295 while (chars_read < max_chars) {
6296 uint16_t c = data[offset];
6297 if (c <= kMaxAsciiCharCode) {
6298 // Fast case for ASCII characters. Cursor is an input output argument.
6299 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6300 rbb->util_buffer,
6301 rbb->capacity,
6302 rbb->cursor))
6303 break;
6304 } else {
6305 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6306 rbb->util_buffer,
6307 rbb->capacity,
6308 rbb->cursor))
6309 break;
6310 }
6311 offset++;
6312 chars_read++;
6313 }
6314 *offset_ptr = offset;
6315 rbb->remaining += chars_read;
6316}
6317
6318
6319void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6320 unsigned* offset_ptr,
6321 unsigned max_chars) {
6322 unsigned capacity = rbb->capacity - rbb->cursor;
6323 if (max_chars > capacity) max_chars = capacity;
6324 memcpy(rbb->util_buffer + rbb->cursor,
6325 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
6326 *offset_ptr * kCharSize,
6327 max_chars);
6328 rbb->remaining += max_chars;
6329 *offset_ptr += max_chars;
6330 rbb->cursor += max_chars;
6331}
6332
6333
6334void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
6335 ReadBlockBuffer* rbb,
6336 unsigned* offset_ptr,
6337 unsigned max_chars) {
6338 unsigned capacity = rbb->capacity - rbb->cursor;
6339 if (max_chars > capacity) max_chars = capacity;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006340 memcpy(rbb->util_buffer + rbb->cursor, GetChars() + *offset_ptr, max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006341 rbb->remaining += max_chars;
6342 *offset_ptr += max_chars;
6343 rbb->cursor += max_chars;
6344}
6345
6346
6347// This method determines the type of string involved and then copies
6348// a whole chunk of characters into a buffer, or returns a pointer to a buffer
6349// where they can be found. The pointer is not necessarily valid across a GC
6350// (see AsciiStringReadBlock).
6351const unibrow::byte* String::ReadBlock(String* input,
6352 ReadBlockBuffer* rbb,
6353 unsigned* offset_ptr,
6354 unsigned max_chars) {
6355 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
6356 if (max_chars == 0) {
6357 rbb->remaining = 0;
6358 return NULL;
6359 }
6360 switch (StringShape(input).representation_tag()) {
6361 case kSeqStringTag:
6362 if (input->IsAsciiRepresentation()) {
6363 SeqAsciiString* str = SeqAsciiString::cast(input);
6364 return str->SeqAsciiStringReadBlock(&rbb->remaining,
6365 offset_ptr,
6366 max_chars);
6367 } else {
6368 SeqTwoByteString* str = SeqTwoByteString::cast(input);
6369 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6370 offset_ptr,
6371 max_chars);
6372 return rbb->util_buffer;
6373 }
6374 case kConsStringTag:
6375 return ConsString::cast(input)->ConsStringReadBlock(rbb,
6376 offset_ptr,
6377 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006378 case kExternalStringTag:
6379 if (input->IsAsciiRepresentation()) {
6380 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
6381 &rbb->remaining,
6382 offset_ptr,
6383 max_chars);
6384 } else {
6385 ExternalTwoByteString::cast(input)->
6386 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6387 offset_ptr,
6388 max_chars);
6389 return rbb->util_buffer;
6390 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006391 case kSlicedStringTag:
6392 return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
6393 offset_ptr,
6394 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006395 default:
6396 break;
6397 }
6398
6399 UNREACHABLE();
6400 return 0;
6401}
6402
6403
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006404// This method determines the type of string involved and then gets the UTF8
6405// length of the string. It doesn't flatten the string and has log(n) recursion
6406// for a string of length n.
6407int String::Utf8Length(String* input, int from, int to) {
6408 if (from == to) return 0;
6409 int total = 0;
6410 while (true) {
6411 if (input->IsAsciiRepresentation()) return total + to - from;
6412 switch (StringShape(input).representation_tag()) {
6413 case kConsStringTag: {
6414 ConsString* str = ConsString::cast(input);
6415 String* first = str->first();
6416 String* second = str->second();
6417 int first_length = first->length();
6418 if (first_length - from < to - first_length) {
6419 if (first_length > from) {
6420 // Left hand side is shorter.
6421 total += Utf8Length(first, from, first_length);
6422 input = second;
6423 from = 0;
6424 to -= first_length;
6425 } else {
6426 // We only need the right hand side.
6427 input = second;
6428 from -= first_length;
6429 to -= first_length;
6430 }
6431 } else {
6432 if (first_length <= to) {
6433 // Right hand side is shorter.
6434 total += Utf8Length(second, 0, to - first_length);
6435 input = first;
6436 to = first_length;
6437 } else {
6438 // We only need the left hand side.
6439 input = first;
6440 }
6441 }
6442 continue;
6443 }
6444 case kExternalStringTag:
6445 case kSeqStringTag: {
6446 Vector<const uc16> vector = input->GetFlatContent().ToUC16Vector();
6447 const uc16* p = vector.start();
6448 for (int i = from; i < to; i++) {
6449 total += unibrow::Utf8::Length(p[i]);
6450 }
6451 return total;
6452 }
6453 case kSlicedStringTag: {
6454 SlicedString* str = SlicedString::cast(input);
6455 int offset = str->offset();
6456 input = str->parent();
6457 from += offset;
6458 to += offset;
6459 continue;
6460 }
6461 default:
6462 break;
6463 }
6464 UNREACHABLE();
6465 return 0;
6466 }
6467 return 0;
6468}
6469
6470
Steve Blocka7e24c12009-10-30 11:49:00 +00006471void Relocatable::PostGarbageCollectionProcessing() {
Steve Block44f0eee2011-05-26 01:26:41 +01006472 Isolate* isolate = Isolate::Current();
6473 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00006474 while (current != NULL) {
6475 current->PostGarbageCollection();
6476 current = current->prev_;
6477 }
6478}
6479
6480
6481// Reserve space for statics needing saving and restoring.
6482int Relocatable::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +01006483 return sizeof(Isolate::Current()->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00006484}
6485
6486
6487// Archive statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00006488char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01006489 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
6490 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00006491 return to + ArchiveSpacePerThread();
6492}
6493
6494
6495// Restore statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00006496char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01006497 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00006498 return from + ArchiveSpacePerThread();
6499}
6500
6501
6502char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
6503 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
6504 Iterate(v, top);
6505 return thread_storage + ArchiveSpacePerThread();
6506}
6507
6508
6509void Relocatable::Iterate(ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01006510 Isolate* isolate = Isolate::Current();
6511 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00006512}
6513
6514
6515void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
6516 Relocatable* current = top;
6517 while (current != NULL) {
6518 current->IterateInstance(v);
6519 current = current->prev_;
6520 }
6521}
6522
6523
Steve Block44f0eee2011-05-26 01:26:41 +01006524FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
6525 : Relocatable(isolate),
6526 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00006527 length_(str->length()) {
6528 PostGarbageCollection();
6529}
6530
6531
Steve Block44f0eee2011-05-26 01:26:41 +01006532FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
6533 : Relocatable(isolate),
6534 str_(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00006535 is_ascii_(true),
6536 length_(input.length()),
6537 start_(input.start()) { }
6538
6539
6540void FlatStringReader::PostGarbageCollection() {
6541 if (str_ == NULL) return;
6542 Handle<String> str(str_);
6543 ASSERT(str->IsFlat());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006544 String::FlatContent content = str->GetFlatContent();
6545 ASSERT(content.IsFlat());
6546 is_ascii_ = content.IsAscii();
Steve Blocka7e24c12009-10-30 11:49:00 +00006547 if (is_ascii_) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006548 start_ = content.ToAsciiVector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00006549 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006550 start_ = content.ToUC16Vector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00006551 }
6552}
6553
6554
6555void StringInputBuffer::Seek(unsigned pos) {
6556 Reset(pos, input_);
6557}
6558
6559
6560void SafeStringInputBuffer::Seek(unsigned pos) {
6561 Reset(pos, input_);
6562}
6563
6564
6565// This method determines the type of string involved and then copies
6566// a whole chunk of characters into a buffer. It can be used with strings
6567// that have been glued together to form a ConsString and which must cooperate
6568// to fill up a buffer.
6569void String::ReadBlockIntoBuffer(String* input,
6570 ReadBlockBuffer* rbb,
6571 unsigned* offset_ptr,
6572 unsigned max_chars) {
6573 ASSERT(*offset_ptr <= (unsigned)input->length());
6574 if (max_chars == 0) return;
6575
6576 switch (StringShape(input).representation_tag()) {
6577 case kSeqStringTag:
6578 if (input->IsAsciiRepresentation()) {
6579 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
6580 offset_ptr,
6581 max_chars);
6582 return;
6583 } else {
6584 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6585 offset_ptr,
6586 max_chars);
6587 return;
6588 }
6589 case kConsStringTag:
6590 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
6591 offset_ptr,
6592 max_chars);
6593 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00006594 case kExternalStringTag:
6595 if (input->IsAsciiRepresentation()) {
Steve Blockd0582a62009-12-15 09:54:21 +00006596 ExternalAsciiString::cast(input)->
6597 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
6598 } else {
6599 ExternalTwoByteString::cast(input)->
6600 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6601 offset_ptr,
6602 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006603 }
6604 return;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006605 case kSlicedStringTag:
6606 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
6607 offset_ptr,
6608 max_chars);
6609 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00006610 default:
6611 break;
6612 }
6613
6614 UNREACHABLE();
6615 return;
6616}
6617
6618
6619const unibrow::byte* String::ReadBlock(String* input,
6620 unibrow::byte* util_buffer,
6621 unsigned capacity,
6622 unsigned* remaining,
6623 unsigned* offset_ptr) {
6624 ASSERT(*offset_ptr <= (unsigned)input->length());
6625 unsigned chars = input->length() - *offset_ptr;
6626 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6627 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
6628 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6629 *remaining = rbb.remaining;
6630 return answer;
6631}
6632
6633
6634const unibrow::byte* String::ReadBlock(String** raw_input,
6635 unibrow::byte* util_buffer,
6636 unsigned capacity,
6637 unsigned* remaining,
6638 unsigned* offset_ptr) {
6639 Handle<String> input(raw_input);
6640 ASSERT(*offset_ptr <= (unsigned)input->length());
6641 unsigned chars = input->length() - *offset_ptr;
6642 if (chars > capacity) chars = capacity;
6643 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6644 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
6645 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6646 *remaining = rbb.remaining;
6647 return rbb.util_buffer;
6648}
6649
6650
6651// This will iterate unless the block of string data spans two 'halves' of
6652// a ConsString, in which case it will recurse. Since the block of string
6653// data to be read has a maximum size this limits the maximum recursion
6654// depth to something sane. Since C++ does not have tail call recursion
6655// elimination, the iteration must be explicit.
6656void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6657 unsigned* offset_ptr,
6658 unsigned max_chars) {
6659 ConsString* current = this;
6660 unsigned offset = *offset_ptr;
6661 int offset_correction = 0;
6662
6663 while (true) {
6664 String* left = current->first();
6665 unsigned left_length = (unsigned)left->length();
6666 if (left_length > offset &&
6667 max_chars <= left_length - offset) {
6668 // Left hand side only - iterate unless we have reached the bottom of
6669 // the cons tree.
6670 if (StringShape(left).IsCons()) {
6671 current = ConsString::cast(left);
6672 continue;
6673 } else {
6674 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
6675 *offset_ptr = offset + offset_correction;
6676 return;
6677 }
6678 } else if (left_length <= offset) {
6679 // Right hand side only - iterate unless we have reached the bottom of
6680 // the cons tree.
6681 offset -= left_length;
6682 offset_correction += left_length;
6683 String* right = current->second();
6684 if (StringShape(right).IsCons()) {
6685 current = ConsString::cast(right);
6686 continue;
6687 } else {
6688 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6689 *offset_ptr = offset + offset_correction;
6690 return;
6691 }
6692 } else {
6693 // The block to be read spans two sides of the ConsString, so we recurse.
6694 // First recurse on the left.
6695 max_chars -= left_length - offset;
6696 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
6697 // We may have reached the max or there may not have been enough space
6698 // in the buffer for the characters in the left hand side.
6699 if (offset == left_length) {
6700 // Recurse on the right.
6701 String* right = String::cast(current->second());
6702 offset -= left_length;
6703 offset_correction += left_length;
6704 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6705 }
6706 *offset_ptr = offset + offset_correction;
6707 return;
6708 }
6709 }
6710}
6711
6712
Steve Blocka7e24c12009-10-30 11:49:00 +00006713uint16_t ConsString::ConsStringGet(int index) {
6714 ASSERT(index >= 0 && index < this->length());
6715
6716 // Check for a flattened cons string
6717 if (second()->length() == 0) {
6718 String* left = first();
6719 return left->Get(index);
6720 }
6721
6722 String* string = String::cast(this);
6723
6724 while (true) {
6725 if (StringShape(string).IsCons()) {
6726 ConsString* cons_string = ConsString::cast(string);
6727 String* left = cons_string->first();
6728 if (left->length() > index) {
6729 string = left;
6730 } else {
6731 index -= left->length();
6732 string = cons_string->second();
6733 }
6734 } else {
6735 return string->Get(index);
6736 }
6737 }
6738
6739 UNREACHABLE();
6740 return 0;
6741}
6742
6743
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006744uint16_t SlicedString::SlicedStringGet(int index) {
6745 return parent()->Get(offset() + index);
6746}
6747
6748
6749const unibrow::byte* SlicedString::SlicedStringReadBlock(
6750 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6751 unsigned offset = this->offset();
6752 *offset_ptr += offset;
6753 const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
6754 buffer, offset_ptr, chars);
6755 *offset_ptr -= offset;
6756 return answer;
6757}
6758
6759
6760void SlicedString::SlicedStringReadBlockIntoBuffer(
6761 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6762 unsigned offset = this->offset();
6763 *offset_ptr += offset;
6764 String::ReadBlockIntoBuffer(String::cast(parent()),
6765 buffer, offset_ptr, chars);
6766 *offset_ptr -= offset;
6767}
6768
Steve Blocka7e24c12009-10-30 11:49:00 +00006769template <typename sinkchar>
6770void String::WriteToFlat(String* src,
6771 sinkchar* sink,
6772 int f,
6773 int t) {
6774 String* source = src;
6775 int from = f;
6776 int to = t;
6777 while (true) {
6778 ASSERT(0 <= from && from <= to && to <= source->length());
6779 switch (StringShape(source).full_representation_tag()) {
6780 case kAsciiStringTag | kExternalStringTag: {
6781 CopyChars(sink,
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006782 ExternalAsciiString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +00006783 to - from);
6784 return;
6785 }
6786 case kTwoByteStringTag | kExternalStringTag: {
6787 const uc16* data =
Ben Murdoch592a9fc2012-03-05 11:04:45 +00006788 ExternalTwoByteString::cast(source)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006789 CopyChars(sink,
6790 data + from,
6791 to - from);
6792 return;
6793 }
6794 case kAsciiStringTag | kSeqStringTag: {
6795 CopyChars(sink,
6796 SeqAsciiString::cast(source)->GetChars() + from,
6797 to - from);
6798 return;
6799 }
6800 case kTwoByteStringTag | kSeqStringTag: {
6801 CopyChars(sink,
6802 SeqTwoByteString::cast(source)->GetChars() + from,
6803 to - from);
6804 return;
6805 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006806 case kAsciiStringTag | kConsStringTag:
6807 case kTwoByteStringTag | kConsStringTag: {
6808 ConsString* cons_string = ConsString::cast(source);
6809 String* first = cons_string->first();
6810 int boundary = first->length();
6811 if (to - boundary >= boundary - from) {
6812 // Right hand side is longer. Recurse over left.
6813 if (from < boundary) {
6814 WriteToFlat(first, sink, from, boundary);
6815 sink += boundary - from;
6816 from = 0;
6817 } else {
6818 from -= boundary;
6819 }
6820 to -= boundary;
6821 source = cons_string->second();
6822 } else {
6823 // Left hand side is longer. Recurse over right.
6824 if (to > boundary) {
6825 String* second = cons_string->second();
6826 WriteToFlat(second,
6827 sink + boundary - from,
6828 0,
6829 to - boundary);
6830 to = boundary;
6831 }
6832 source = first;
6833 }
6834 break;
6835 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006836 case kAsciiStringTag | kSlicedStringTag:
6837 case kTwoByteStringTag | kSlicedStringTag: {
6838 SlicedString* slice = SlicedString::cast(source);
6839 unsigned offset = slice->offset();
6840 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
6841 return;
6842 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006843 }
6844 }
6845}
6846
6847
Steve Blocka7e24c12009-10-30 11:49:00 +00006848template <typename IteratorA, typename IteratorB>
6849static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
6850 // General slow case check. We know that the ia and ib iterators
6851 // have the same length.
6852 while (ia->has_more()) {
6853 uc32 ca = ia->GetNext();
6854 uc32 cb = ib->GetNext();
6855 if (ca != cb)
6856 return false;
6857 }
6858 return true;
6859}
6860
6861
6862// Compares the contents of two strings by reading and comparing
6863// int-sized blocks of characters.
6864template <typename Char>
6865static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
6866 int length = a.length();
6867 ASSERT_EQ(length, b.length());
6868 const Char* pa = a.start();
6869 const Char* pb = b.start();
6870 int i = 0;
6871#ifndef V8_HOST_CAN_READ_UNALIGNED
6872 // If this architecture isn't comfortable reading unaligned ints
6873 // then we have to check that the strings are aligned before
6874 // comparing them blockwise.
6875 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
6876 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
6877 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
6878 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
6879#endif
6880 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
6881 int endpoint = length - kStepSize;
6882 // Compare blocks until we reach near the end of the string.
6883 for (; i <= endpoint; i += kStepSize) {
6884 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
6885 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
6886 if (wa != wb) {
6887 return false;
6888 }
6889 }
6890#ifndef V8_HOST_CAN_READ_UNALIGNED
6891 }
6892#endif
6893 // Compare the remaining characters that didn't fit into a block.
6894 for (; i < length; i++) {
6895 if (a[i] != b[i]) {
6896 return false;
6897 }
6898 }
6899 return true;
6900}
6901
6902
Steve Blocka7e24c12009-10-30 11:49:00 +00006903template <typename IteratorA>
Steve Block44f0eee2011-05-26 01:26:41 +01006904static inline bool CompareStringContentsPartial(Isolate* isolate,
6905 IteratorA* ia,
6906 String* b) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006907 String::FlatContent content = b->GetFlatContent();
6908 if (content.IsFlat()) {
6909 if (content.IsAscii()) {
6910 VectorIterator<char> ib(content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006911 return CompareStringContents(ia, &ib);
6912 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006913 VectorIterator<uc16> ib(content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006914 return CompareStringContents(ia, &ib);
6915 }
6916 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006917 isolate->objects_string_compare_buffer_b()->Reset(0, b);
6918 return CompareStringContents(ia,
6919 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006920 }
6921}
6922
6923
Steve Blocka7e24c12009-10-30 11:49:00 +00006924bool String::SlowEquals(String* other) {
6925 // Fast check: negative check with lengths.
6926 int len = length();
6927 if (len != other->length()) return false;
6928 if (len == 0) return true;
6929
6930 // Fast check: if hash code is computed for both strings
6931 // a fast negative check can be performed.
6932 if (HasHashCode() && other->HasHashCode()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00006933#ifdef DEBUG
6934 if (FLAG_enable_slow_asserts) {
6935 if (Hash() != other->Hash()) {
6936 bool found_difference = false;
6937 for (int i = 0; i < len; i++) {
6938 if (Get(i) != other->Get(i)) {
6939 found_difference = true;
6940 break;
6941 }
6942 }
6943 ASSERT(found_difference);
6944 }
6945 }
6946#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00006947 if (Hash() != other->Hash()) return false;
6948 }
6949
Leon Clarkef7060e22010-06-03 12:02:55 +01006950 // We know the strings are both non-empty. Compare the first chars
6951 // before we try to flatten the strings.
6952 if (this->Get(0) != other->Get(0)) return false;
6953
6954 String* lhs = this->TryFlattenGetString();
6955 String* rhs = other->TryFlattenGetString();
6956
6957 if (StringShape(lhs).IsSequentialAscii() &&
6958 StringShape(rhs).IsSequentialAscii()) {
6959 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
6960 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006961 return CompareRawStringContents(Vector<const char>(str1, len),
6962 Vector<const char>(str2, len));
6963 }
6964
Steve Block44f0eee2011-05-26 01:26:41 +01006965 Isolate* isolate = GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006966 String::FlatContent lhs_content = lhs->GetFlatContent();
6967 String::FlatContent rhs_content = rhs->GetFlatContent();
6968 if (lhs_content.IsFlat()) {
6969 if (lhs_content.IsAscii()) {
6970 Vector<const char> vec1 = lhs_content.ToAsciiVector();
6971 if (rhs_content.IsFlat()) {
6972 if (rhs_content.IsAscii()) {
6973 Vector<const char> vec2 = rhs_content.ToAsciiVector();
Steve Blocka7e24c12009-10-30 11:49:00 +00006974 return CompareRawStringContents(vec1, vec2);
6975 } else {
6976 VectorIterator<char> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006977 VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006978 return CompareStringContents(&buf1, &ib);
6979 }
6980 } else {
6981 VectorIterator<char> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01006982 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6983 return CompareStringContents(&buf1,
6984 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006985 }
6986 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006987 Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
6988 if (rhs_content.IsFlat()) {
6989 if (rhs_content.IsAscii()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006990 VectorIterator<uc16> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006991 VectorIterator<char> ib(rhs_content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006992 return CompareStringContents(&buf1, &ib);
6993 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006994 Vector<const uc16> vec2(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006995 return CompareRawStringContents(vec1, vec2);
6996 }
6997 } else {
6998 VectorIterator<uc16> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01006999 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
7000 return CompareStringContents(&buf1,
7001 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00007002 }
7003 }
7004 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01007005 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
7006 return CompareStringContentsPartial(isolate,
7007 isolate->objects_string_compare_buffer_a(), rhs);
Steve Blocka7e24c12009-10-30 11:49:00 +00007008 }
7009}
7010
7011
7012bool String::MarkAsUndetectable() {
7013 if (StringShape(this).IsSymbol()) return false;
7014
7015 Map* map = this->map();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007016 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01007017 if (map == heap->string_map()) {
7018 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00007019 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01007020 } else if (map == heap->ascii_string_map()) {
7021 this->set_map(heap->undetectable_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00007022 return true;
7023 }
7024 // Rest cannot be marked as undetectable
7025 return false;
7026}
7027
7028
7029bool String::IsEqualTo(Vector<const char> str) {
Steve Block44f0eee2011-05-26 01:26:41 +01007030 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007031 int slen = length();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007032 Access<UnicodeCache::Utf8Decoder>
7033 decoder(isolate->unicode_cache()->utf8_decoder());
Steve Blocka7e24c12009-10-30 11:49:00 +00007034 decoder->Reset(str.start(), str.length());
7035 int i;
7036 for (i = 0; i < slen && decoder->has_more(); i++) {
7037 uc32 r = decoder->GetNext();
7038 if (Get(i) != r) return false;
7039 }
7040 return i == slen && !decoder->has_more();
7041}
7042
7043
Steve Block9fac8402011-05-12 15:51:54 +01007044bool String::IsAsciiEqualTo(Vector<const char> str) {
7045 int slen = length();
7046 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007047 FlatContent content = GetFlatContent();
7048 if (content.IsAscii()) {
7049 return CompareChars(content.ToAsciiVector().start(),
7050 str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007051 }
7052 for (int i = 0; i < slen; i++) {
7053 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +01007054 }
7055 return true;
7056}
7057
7058
7059bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
7060 int slen = length();
7061 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007062 FlatContent content = GetFlatContent();
7063 if (content.IsTwoByte()) {
7064 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007065 }
Steve Block9fac8402011-05-12 15:51:54 +01007066 for (int i = 0; i < slen; i++) {
7067 if (Get(i) != str[i]) return false;
7068 }
7069 return true;
7070}
7071
7072
Steve Blocka7e24c12009-10-30 11:49:00 +00007073uint32_t String::ComputeAndSetHash() {
7074 // Should only be called if hash code has not yet been computed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007075 ASSERT(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00007076
Steve Block6ded16b2010-05-10 14:33:55 +01007077 const int len = length();
7078
Steve Blocka7e24c12009-10-30 11:49:00 +00007079 // Compute the hash code.
Steve Block6ded16b2010-05-10 14:33:55 +01007080 uint32_t field = 0;
7081 if (StringShape(this).IsSequentialAscii()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00007082 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(),
7083 len,
7084 GetHeap()->HashSeed());
Steve Block6ded16b2010-05-10 14:33:55 +01007085 } else if (StringShape(this).IsSequentialTwoByte()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00007086 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(),
7087 len,
7088 GetHeap()->HashSeed());
Steve Block6ded16b2010-05-10 14:33:55 +01007089 } else {
7090 StringInputBuffer buffer(this);
Ben Murdochc7cc0282012-03-05 14:35:55 +00007091 field = ComputeHashField(&buffer, len, GetHeap()->HashSeed());
Steve Block6ded16b2010-05-10 14:33:55 +01007092 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007093
7094 // Store the hash code in the object.
Steve Blockd0582a62009-12-15 09:54:21 +00007095 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00007096
7097 // Check the hash code is there.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007098 ASSERT(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00007099 uint32_t result = field >> kHashShift;
7100 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
7101 return result;
7102}
7103
7104
7105bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
7106 uint32_t* index,
7107 int length) {
7108 if (length == 0 || length > kMaxArrayIndexSize) return false;
7109 uc32 ch = buffer->GetNext();
7110
7111 // If the string begins with a '0' character, it must only consist
7112 // of it to be a legal array index.
7113 if (ch == '0') {
7114 *index = 0;
7115 return length == 1;
7116 }
7117
7118 // Convert string to uint32 array index; character by character.
7119 int d = ch - '0';
7120 if (d < 0 || d > 9) return false;
7121 uint32_t result = d;
7122 while (buffer->has_more()) {
7123 d = buffer->GetNext() - '0';
7124 if (d < 0 || d > 9) return false;
7125 // Check that the new result is below the 32 bit limit.
7126 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
7127 result = (result * 10) + d;
7128 }
7129
7130 *index = result;
7131 return true;
7132}
7133
7134
7135bool String::SlowAsArrayIndex(uint32_t* index) {
7136 if (length() <= kMaxCachedArrayIndexLength) {
7137 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00007138 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007139 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00007140 // Isolate the array index form the full hash field.
7141 *index = (kArrayIndexHashMask & field) >> kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00007142 return true;
7143 } else {
7144 StringInputBuffer buffer(this);
7145 return ComputeArrayIndex(&buffer, index, length());
7146 }
7147}
7148
7149
Iain Merrick9ac36c92010-09-13 15:29:50 +01007150uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01007151 // For array indexes mix the length into the hash as an array index could
7152 // be zero.
7153 ASSERT(length > 0);
7154 ASSERT(length <= String::kMaxArrayIndexSize);
7155 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
7156 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01007157
7158 value <<= String::kHashShift;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01007159 value |= length << String::kArrayIndexHashLengthShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01007160
7161 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
7162 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
7163 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01007164 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00007165}
7166
7167
7168uint32_t StringHasher::GetHashField() {
7169 ASSERT(is_valid());
Steve Blockd0582a62009-12-15 09:54:21 +00007170 if (length_ <= String::kMaxHashCalcLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007171 if (is_array_index()) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01007172 return MakeArrayIndexHash(array_index(), length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00007173 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01007174 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00007175 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01007176 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00007177 }
7178}
7179
7180
Steve Blockd0582a62009-12-15 09:54:21 +00007181uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
Ben Murdochc7cc0282012-03-05 14:35:55 +00007182 int length,
7183 uint32_t seed) {
7184 StringHasher hasher(length, seed);
Steve Blocka7e24c12009-10-30 11:49:00 +00007185
7186 // Very long strings have a trivial hash that doesn't inspect the
7187 // string contents.
7188 if (hasher.has_trivial_hash()) {
7189 return hasher.GetHashField();
7190 }
7191
7192 // Do the iterative array index computation as long as there is a
7193 // chance this is an array index.
7194 while (buffer->has_more() && hasher.is_array_index()) {
7195 hasher.AddCharacter(buffer->GetNext());
7196 }
7197
7198 // Process the remaining characters without updating the array
7199 // index.
7200 while (buffer->has_more()) {
7201 hasher.AddCharacterNoIndex(buffer->GetNext());
7202 }
7203
7204 return hasher.GetHashField();
7205}
7206
7207
John Reck59135872010-11-02 12:39:01 -07007208MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01007209 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007210 if (start == 0 && end == length()) return this;
Steve Block44f0eee2011-05-26 01:26:41 +01007211 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
Steve Blockd0582a62009-12-15 09:54:21 +00007212 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007213}
7214
7215
7216void String::PrintOn(FILE* file) {
7217 int length = this->length();
7218 for (int i = 0; i < length; i++) {
7219 fprintf(file, "%c", Get(i));
7220 }
7221}
7222
7223
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007224void Map::CreateOneBackPointer(Map* target) {
7225#ifdef DEBUG
7226 // Verify target.
7227 Object* source_prototype = prototype();
7228 Object* target_prototype = target->prototype();
7229 ASSERT(source_prototype->IsJSReceiver() ||
7230 source_prototype->IsMap() ||
7231 source_prototype->IsNull());
7232 ASSERT(target_prototype->IsJSReceiver() ||
7233 target_prototype->IsNull());
7234 ASSERT(source_prototype->IsMap() ||
7235 source_prototype == target_prototype);
7236#endif
7237 // Point target back to source. set_prototype() will not let us set
7238 // the prototype to a map, as we do here.
7239 *RawField(target, kPrototypeOffset) = this;
7240}
7241
7242
Steve Blocka7e24c12009-10-30 11:49:00 +00007243void Map::CreateBackPointers() {
7244 DescriptorArray* descriptors = instance_descriptors();
7245 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007246 if (descriptors->IsTransition(i)) {
7247 Object* object = reinterpret_cast<Object*>(descriptors->GetValue(i));
7248 if (object->IsMap()) {
7249 CreateOneBackPointer(reinterpret_cast<Map*>(object));
7250 } else {
7251 ASSERT(object->IsFixedArray());
7252 ASSERT(descriptors->GetType(i) == ELEMENTS_TRANSITION);
7253 FixedArray* array = reinterpret_cast<FixedArray*>(object);
7254 for (int i = 0; i < array->length(); ++i) {
7255 Map* target = reinterpret_cast<Map*>(array->get(i));
7256 if (!target->IsUndefined()) {
7257 CreateOneBackPointer(target);
7258 }
7259 }
7260 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007261 }
7262 }
7263}
7264
7265
Steve Block44f0eee2011-05-26 01:26:41 +01007266void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007267 // Live DescriptorArray objects will be marked, so we must use
7268 // low-level accessors to get and modify their data.
7269 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00007270 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
7271 if (d->IsEmpty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00007272 Smi* NullDescriptorDetails =
7273 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
7274 FixedArray* contents = reinterpret_cast<FixedArray*>(
7275 d->get(DescriptorArray::kContentArrayIndex));
7276 ASSERT(contents->length() >= 2);
7277 for (int i = 0; i < contents->length(); i += 2) {
7278 // If the pair (value, details) is a map transition,
7279 // check if the target is live. If not, null the descriptor.
7280 // Also drop the back pointer for that map transition, so that this
7281 // map is not reached again by following a back pointer from a
7282 // non-live object.
7283 PropertyDetails details(Smi::cast(contents->get(i + 1)));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007284 if (IsTransitionType(details.type())) {
7285 Object* object = reinterpret_cast<Object*>(contents->get(i));
7286 if (object->IsMap()) {
7287 Map* target = reinterpret_cast<Map*>(object);
7288 ASSERT(target->IsHeapObject());
7289 MarkBit map_mark = Marking::MarkBitFrom(target);
7290 if (!map_mark.Get()) {
7291 ASSERT(target->IsMap());
7292 contents->set_unchecked(i + 1, NullDescriptorDetails);
7293 contents->set_null_unchecked(heap, i);
7294 ASSERT(target->prototype() == this ||
7295 target->prototype() == real_prototype);
7296 // Getter prototype() is read-only, set_prototype() has side effects.
7297 *RawField(target, Map::kPrototypeOffset) = real_prototype;
7298 }
7299 } else {
7300 ASSERT(object->IsFixedArray());
7301 ASSERT(details.type() == ELEMENTS_TRANSITION);
7302 FixedArray* array = reinterpret_cast<FixedArray*>(object);
7303 bool reachable_map_found = false;
7304 for (int j = 0; j < array->length(); ++j) {
7305 Map* target = reinterpret_cast<Map*>(array->get(j));
7306 ASSERT(target->IsHeapObject());
7307 MarkBit map_mark = Marking::MarkBitFrom(target);
7308 if (!map_mark.Get()) {
7309 ASSERT(target->IsMap());
7310 array->set_undefined(j);
7311 ASSERT(target->prototype() == this ||
7312 target->prototype() == real_prototype);
7313 // Getter prototype() is read-only, set_prototype() has side
7314 // effects.
7315 *RawField(target, Map::kPrototypeOffset) = real_prototype;
7316 } else if (target->IsMap()) {
7317 reachable_map_found = true;
7318 }
7319 }
7320 // If no map was found, make sure the FixedArray also gets collected.
7321 if (!reachable_map_found) {
7322 contents->set_unchecked(i + 1, NullDescriptorDetails);
7323 contents->set_null_unchecked(heap, i);
7324 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007325 }
7326 }
7327 }
7328}
7329
7330
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007331int Map::Hash() {
7332 // For performance reasons we only hash the 3 most variable fields of a map:
7333 // constructor, prototype and bit_field2.
7334
7335 // Shift away the tag.
7336 int hash = (static_cast<uint32_t>(
7337 reinterpret_cast<uintptr_t>(constructor())) >> 2);
7338
7339 // XOR-ing the prototype and constructor directly yields too many zero bits
7340 // when the two pointers are close (which is fairly common).
7341 // To avoid this we shift the prototype 4 bits relatively to the constructor.
7342 hash ^= (static_cast<uint32_t>(
7343 reinterpret_cast<uintptr_t>(prototype())) << 2);
7344
7345 return hash ^ (hash >> 16) ^ bit_field2();
7346}
7347
7348
7349bool Map::EquivalentToForNormalization(Map* other,
7350 PropertyNormalizationMode mode) {
7351 return
7352 constructor() == other->constructor() &&
7353 prototype() == other->prototype() &&
7354 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
7355 0 :
7356 other->inobject_properties()) &&
7357 instance_type() == other->instance_type() &&
7358 bit_field() == other->bit_field() &&
7359 bit_field2() == other->bit_field2() &&
7360 (bit_field3() & ~(1<<Map::kIsShared)) ==
7361 (other->bit_field3() & ~(1<<Map::kIsShared));
7362}
7363
7364
Steve Block791712a2010-08-27 10:21:07 +01007365void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
7366 // Iterate over all fields in the body but take care in dealing with
7367 // the code entry.
7368 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
7369 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
7370 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
7371}
7372
7373
Ben Murdochb0fe1622011-05-05 13:52:32 +01007374void JSFunction::MarkForLazyRecompilation() {
7375 ASSERT(is_compiled() && !IsOptimized());
Ben Murdochb8e0da22011-05-16 14:20:40 +01007376 ASSERT(shared()->allows_lazy_compilation() ||
7377 code()->optimizable());
Steve Block44f0eee2011-05-26 01:26:41 +01007378 Builtins* builtins = GetIsolate()->builtins();
7379 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007380}
7381
7382
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007383bool SharedFunctionInfo::EnsureCompiled(Handle<SharedFunctionInfo> shared,
7384 ClearExceptionFlag flag) {
7385 return shared->is_compiled() || CompileLazy(shared, flag);
7386}
7387
7388
7389static bool CompileLazyHelper(CompilationInfo* info,
7390 ClearExceptionFlag flag) {
7391 // Compile the source information to a code object.
7392 ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
7393 ASSERT(!info->isolate()->has_pending_exception());
7394 bool result = Compiler::CompileLazy(info);
7395 ASSERT(result != Isolate::Current()->has_pending_exception());
7396 if (!result && flag == CLEAR_EXCEPTION) {
7397 info->isolate()->clear_pending_exception();
7398 }
7399 return result;
7400}
7401
7402
7403bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
7404 ClearExceptionFlag flag) {
7405 CompilationInfo info(shared);
7406 return CompileLazyHelper(&info, flag);
7407}
7408
7409
7410bool JSFunction::CompileLazy(Handle<JSFunction> function,
7411 ClearExceptionFlag flag) {
7412 bool result = true;
7413 if (function->shared()->is_compiled()) {
7414 function->ReplaceCode(function->shared()->code());
7415 function->shared()->set_code_age(0);
7416 } else {
7417 CompilationInfo info(function);
7418 result = CompileLazyHelper(&info, flag);
7419 ASSERT(!result || function->is_compiled());
7420 }
7421 return result;
7422}
7423
7424
7425bool JSFunction::CompileOptimized(Handle<JSFunction> function,
7426 int osr_ast_id,
7427 ClearExceptionFlag flag) {
7428 CompilationInfo info(function);
7429 info.SetOptimizing(osr_ast_id);
7430 return CompileLazyHelper(&info, flag);
7431}
7432
7433
Ben Murdochb0fe1622011-05-05 13:52:32 +01007434bool JSFunction::IsInlineable() {
7435 if (IsBuiltin()) return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007436 SharedFunctionInfo* shared_info = shared();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007437 // Check that the function has a script associated with it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007438 if (!shared_info->script()->IsScript()) return false;
7439 if (shared_info->optimization_disabled()) return false;
7440 Code* code = shared_info->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007441 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
7442 // If we never ran this (unlikely) then lets try to optimize it.
7443 if (code->kind() != Code::FUNCTION) return true;
7444 return code->optimizable();
7445}
7446
7447
Steve Blocka7e24c12009-10-30 11:49:00 +00007448Object* JSFunction::SetInstancePrototype(Object* value) {
7449 ASSERT(value->IsJSObject());
Steve Block44f0eee2011-05-26 01:26:41 +01007450 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007451 if (has_initial_map()) {
7452 initial_map()->set_prototype(value);
7453 } else {
7454 // Put the value in the initial map field until an initial map is
7455 // needed. At that point, a new initial map is created and the
7456 // prototype is put into the initial map where it belongs.
7457 set_prototype_or_initial_map(value);
7458 }
Steve Block44f0eee2011-05-26 01:26:41 +01007459 heap->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00007460 return value;
7461}
7462
7463
John Reck59135872010-11-02 12:39:01 -07007464MaybeObject* JSFunction::SetPrototype(Object* value) {
Steve Block6ded16b2010-05-10 14:33:55 +01007465 ASSERT(should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +00007466 Object* construct_prototype = value;
7467
7468 // If the value is not a JSObject, store the value in the map's
7469 // constructor field so it can be accessed. Also, set the prototype
7470 // used for constructing objects to the original object prototype.
7471 // See ECMA-262 13.2.2.
7472 if (!value->IsJSObject()) {
7473 // Copy the map so this does not affect unrelated functions.
7474 // Remove map transitions because they point to maps with a
7475 // different prototype.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007476 Object* new_object;
John Reck59135872010-11-02 12:39:01 -07007477 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007478 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07007479 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01007480 Map* new_map = Map::cast(new_object);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007481 Heap* heap = new_map->GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007482 set_map(new_map);
7483 new_map->set_constructor(value);
7484 new_map->set_non_instance_prototype(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00007485 construct_prototype =
Steve Block44f0eee2011-05-26 01:26:41 +01007486 heap->isolate()->context()->global_context()->
7487 initial_object_prototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00007488 } else {
7489 map()->set_non_instance_prototype(false);
7490 }
7491
7492 return SetInstancePrototype(construct_prototype);
7493}
7494
7495
Steve Block6ded16b2010-05-10 14:33:55 +01007496Object* JSFunction::RemovePrototype() {
Steve Block44f0eee2011-05-26 01:26:41 +01007497 Context* global_context = context()->global_context();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007498 Map* no_prototype_map = shared()->is_classic_mode()
7499 ? global_context->function_without_prototype_map()
7500 : global_context->strict_mode_function_without_prototype_map();
Steve Block44f0eee2011-05-26 01:26:41 +01007501
7502 if (map() == no_prototype_map) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007503 // Be idempotent.
7504 return this;
7505 }
Steve Block44f0eee2011-05-26 01:26:41 +01007506
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007507 ASSERT(map() == (shared()->is_classic_mode()
7508 ? global_context->function_map()
7509 : global_context->strict_mode_function_map()));
Steve Block44f0eee2011-05-26 01:26:41 +01007510
7511 set_map(no_prototype_map);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007512 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01007513 return this;
7514}
7515
7516
Steve Blocka7e24c12009-10-30 11:49:00 +00007517Object* JSFunction::SetInstanceClassName(String* name) {
7518 shared()->set_instance_class_name(name);
7519 return this;
7520}
7521
7522
Ben Murdochb0fe1622011-05-05 13:52:32 +01007523void JSFunction::PrintName(FILE* out) {
Ben Murdoch589d6972011-11-30 16:04:58 +00007524 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007525 PrintF(out, "%s", *name);
7526}
7527
7528
Steve Blocka7e24c12009-10-30 11:49:00 +00007529Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
7530 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
7531}
7532
7533
Steve Block44f0eee2011-05-26 01:26:41 +01007534MaybeObject* Oddball::Initialize(const char* to_string,
7535 Object* to_number,
7536 byte kind) {
John Reck59135872010-11-02 12:39:01 -07007537 Object* symbol;
Steve Block44f0eee2011-05-26 01:26:41 +01007538 { MaybeObject* maybe_symbol =
7539 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
John Reck59135872010-11-02 12:39:01 -07007540 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
7541 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007542 set_to_string(String::cast(symbol));
7543 set_to_number(to_number);
Steve Block44f0eee2011-05-26 01:26:41 +01007544 set_kind(kind);
Steve Blocka7e24c12009-10-30 11:49:00 +00007545 return this;
7546}
7547
7548
Ben Murdochf87a2032010-10-22 12:50:53 +01007549String* SharedFunctionInfo::DebugName() {
7550 Object* n = name();
7551 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
7552 return String::cast(n);
7553}
7554
7555
Steve Blocka7e24c12009-10-30 11:49:00 +00007556bool SharedFunctionInfo::HasSourceCode() {
7557 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01007558 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00007559}
7560
7561
7562Object* SharedFunctionInfo::GetSourceCode() {
Steve Block44f0eee2011-05-26 01:26:41 +01007563 Isolate* isolate = GetIsolate();
7564 if (!HasSourceCode()) return isolate->heap()->undefined_value();
7565 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007566 Object* source = Script::cast(script())->source();
Steve Block44f0eee2011-05-26 01:26:41 +01007567 return *SubString(Handle<String>(String::cast(source), isolate),
Steve Blocka7e24c12009-10-30 11:49:00 +00007568 start_position(), end_position());
7569}
7570
7571
Ben Murdochb0fe1622011-05-05 13:52:32 +01007572int SharedFunctionInfo::SourceSize() {
7573 return end_position() - start_position();
7574}
7575
7576
Steve Blocka7e24c12009-10-30 11:49:00 +00007577int SharedFunctionInfo::CalculateInstanceSize() {
7578 int instance_size =
7579 JSObject::kHeaderSize +
7580 expected_nof_properties() * kPointerSize;
7581 if (instance_size > JSObject::kMaxInstanceSize) {
7582 instance_size = JSObject::kMaxInstanceSize;
7583 }
7584 return instance_size;
7585}
7586
7587
7588int SharedFunctionInfo::CalculateInObjectProperties() {
7589 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
7590}
7591
7592
Andrei Popescu402d9372010-02-26 13:31:12 +00007593bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
7594 // Check the basic conditions for generating inline constructor code.
7595 if (!FLAG_inline_new
7596 || !has_only_simple_this_property_assignments()
7597 || this_property_assignments_count() == 0) {
7598 return false;
7599 }
7600
7601 // If the prototype is null inline constructors cause no problems.
7602 if (!prototype->IsJSObject()) {
7603 ASSERT(prototype->IsNull());
7604 return true;
7605 }
7606
Ben Murdoch8b112d22011-06-08 16:22:53 +01007607 Heap* heap = GetHeap();
7608
Andrei Popescu402d9372010-02-26 13:31:12 +00007609 // Traverse the proposed prototype chain looking for setters for properties of
7610 // the same names as are set by the inline constructor.
7611 for (Object* obj = prototype;
Steve Block44f0eee2011-05-26 01:26:41 +01007612 obj != heap->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00007613 obj = obj->GetPrototype()) {
7614 JSObject* js_object = JSObject::cast(obj);
7615 for (int i = 0; i < this_property_assignments_count(); i++) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007616 LookupResult result(heap->isolate());
Andrei Popescu402d9372010-02-26 13:31:12 +00007617 String* name = GetThisPropertyAssignmentName(i);
7618 js_object->LocalLookupRealNamedProperty(name, &result);
Ben Murdochc7cc0282012-03-05 14:35:55 +00007619 if (result.IsFound() && result.type() == CALLBACKS) {
Andrei Popescu402d9372010-02-26 13:31:12 +00007620 return false;
7621 }
7622 }
7623 }
7624
7625 return true;
7626}
7627
7628
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007629void SharedFunctionInfo::ForbidInlineConstructor() {
7630 set_compiler_hints(BooleanBit::set(compiler_hints(),
7631 kHasOnlySimpleThisPropertyAssignments,
7632 false));
7633}
7634
7635
Steve Blocka7e24c12009-10-30 11:49:00 +00007636void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +00007637 bool only_simple_this_property_assignments,
7638 FixedArray* assignments) {
7639 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00007640 kHasOnlySimpleThisPropertyAssignments,
7641 only_simple_this_property_assignments));
7642 set_this_property_assignments(assignments);
7643 set_this_property_assignments_count(assignments->length() / 3);
7644}
7645
7646
7647void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
Steve Block44f0eee2011-05-26 01:26:41 +01007648 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007649 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00007650 kHasOnlySimpleThisPropertyAssignments,
7651 false));
Steve Block44f0eee2011-05-26 01:26:41 +01007652 set_this_property_assignments(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007653 set_this_property_assignments_count(0);
7654}
7655
7656
7657String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
7658 Object* obj = this_property_assignments();
7659 ASSERT(obj->IsFixedArray());
7660 ASSERT(index < this_property_assignments_count());
7661 obj = FixedArray::cast(obj)->get(index * 3);
7662 ASSERT(obj->IsString());
7663 return String::cast(obj);
7664}
7665
7666
7667bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
7668 Object* obj = this_property_assignments();
7669 ASSERT(obj->IsFixedArray());
7670 ASSERT(index < this_property_assignments_count());
7671 obj = FixedArray::cast(obj)->get(index * 3 + 1);
7672 return Smi::cast(obj)->value() != -1;
7673}
7674
7675
7676int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
7677 ASSERT(IsThisPropertyAssignmentArgument(index));
7678 Object* obj =
7679 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
7680 return Smi::cast(obj)->value();
7681}
7682
7683
7684Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
7685 ASSERT(!IsThisPropertyAssignmentArgument(index));
7686 Object* obj =
7687 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
7688 return obj;
7689}
7690
7691
Steve Blocka7e24c12009-10-30 11:49:00 +00007692// Support function for printing the source code to a StringStream
7693// without any allocation in the heap.
7694void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
7695 int max_length) {
7696 // For some native functions there is no source.
Ben Murdochb0fe1622011-05-05 13:52:32 +01007697 if (!HasSourceCode()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007698 accumulator->Add("<No Source>");
7699 return;
7700 }
7701
Steve Blockd0582a62009-12-15 09:54:21 +00007702 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00007703 // Don't use String::cast because we don't want more assertion errors while
7704 // we are already creating a stack dump.
7705 String* script_source =
7706 reinterpret_cast<String*>(Script::cast(script())->source());
7707
7708 if (!script_source->LooksValid()) {
7709 accumulator->Add("<Invalid Source>");
7710 return;
7711 }
7712
7713 if (!is_toplevel()) {
7714 accumulator->Add("function ");
7715 Object* name = this->name();
7716 if (name->IsString() && String::cast(name)->length() > 0) {
7717 accumulator->PrintName(name);
7718 }
7719 }
7720
7721 int len = end_position() - start_position();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007722 if (len <= max_length || max_length < 0) {
7723 accumulator->Put(script_source, start_position(), end_position());
7724 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00007725 accumulator->Put(script_source,
7726 start_position(),
7727 start_position() + max_length);
7728 accumulator->Add("...\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00007729 }
7730}
7731
7732
Ben Murdochb0fe1622011-05-05 13:52:32 +01007733static bool IsCodeEquivalent(Code* code, Code* recompiled) {
7734 if (code->instruction_size() != recompiled->instruction_size()) return false;
7735 ByteArray* code_relocation = code->relocation_info();
7736 ByteArray* recompiled_relocation = recompiled->relocation_info();
7737 int length = code_relocation->length();
7738 if (length != recompiled_relocation->length()) return false;
7739 int compare = memcmp(code_relocation->GetDataStartAddress(),
7740 recompiled_relocation->GetDataStartAddress(),
7741 length);
7742 return compare == 0;
7743}
7744
7745
7746void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
7747 ASSERT(!has_deoptimization_support());
7748 AssertNoAllocation no_allocation;
7749 Code* code = this->code();
7750 if (IsCodeEquivalent(code, recompiled)) {
7751 // Copy the deoptimization data from the recompiled code.
7752 code->set_deoptimization_data(recompiled->deoptimization_data());
7753 code->set_has_deoptimization_support(true);
7754 } else {
7755 // TODO(3025757): In case the recompiled isn't equivalent to the
7756 // old code, we have to replace it. We should try to avoid this
7757 // altogether because it flushes valuable type feedback by
7758 // effectively resetting all IC state.
7759 set_code(recompiled);
7760 }
7761 ASSERT(has_deoptimization_support());
7762}
7763
7764
Ben Murdoch257744e2011-11-30 15:57:28 +00007765void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
7766 // Disable optimization for the shared function info and mark the
7767 // code as non-optimizable. The marker on the shared function info
7768 // is there because we flush non-optimized code thereby loosing the
7769 // non-optimizable information for the code. When the code is
7770 // regenerated and set on the shared function info it is marked as
7771 // non-optimizable if optimization is disabled for the shared
7772 // function info.
7773 set_optimization_disabled(true);
7774 // Code should be the lazy compilation stub or else unoptimized. If the
7775 // latter, disable optimization for the code too.
7776 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
7777 if (code()->kind() == Code::FUNCTION) {
7778 code()->set_optimizable(false);
7779 }
7780 if (FLAG_trace_opt) {
7781 PrintF("[disabled optimization for: ");
7782 function->PrintName();
7783 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
7784 }
7785}
7786
7787
Ben Murdochb0fe1622011-05-05 13:52:32 +01007788bool SharedFunctionInfo::VerifyBailoutId(int id) {
7789 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
7790 // we are always bailing out on ARM.
7791
7792 ASSERT(id != AstNode::kNoNumber);
7793 Code* unoptimized = code();
7794 DeoptimizationOutputData* data =
7795 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
7796 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
7797 USE(ignore);
7798 return true; // Return true if there was no ASSERT.
7799}
7800
7801
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007802void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
7803 ASSERT(!IsInobjectSlackTrackingInProgress());
7804
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007805 if (!FLAG_clever_optimizations) return;
7806
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007807 // Only initiate the tracking the first time.
7808 if (live_objects_may_exist()) return;
7809 set_live_objects_may_exist(true);
7810
7811 // No tracking during the snapshot construction phase.
7812 if (Serializer::enabled()) return;
7813
7814 if (map->unused_property_fields() == 0) return;
7815
7816 // Nonzero counter is a leftover from the previous attempt interrupted
7817 // by GC, keep it.
7818 if (construction_count() == 0) {
7819 set_construction_count(kGenerousAllocationCount);
7820 }
7821 set_initial_map(map);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007822 Builtins* builtins = map->GetHeap()->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01007823 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007824 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01007825 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007826}
7827
7828
7829// Called from GC, hence reinterpret_cast and unchecked accessors.
7830void SharedFunctionInfo::DetachInitialMap() {
7831 Map* map = reinterpret_cast<Map*>(initial_map());
7832
7833 // Make the map remember to restore the link if it survives the GC.
7834 map->set_bit_field2(
7835 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
7836
7837 // Undo state changes made by StartInobjectTracking (except the
7838 // construction_count). This way if the initial map does not survive the GC
7839 // then StartInobjectTracking will be called again the next time the
7840 // constructor is called. The countdown will continue and (possibly after
7841 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007842 Heap* heap = map->GetHeap();
7843 set_initial_map(heap->raw_unchecked_undefined_value());
7844 Builtins* builtins = heap->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01007845 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007846 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01007847 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007848 // It is safe to clear the flag: it will be set again if the map is live.
7849 set_live_objects_may_exist(false);
7850}
7851
7852
7853// Called from GC, hence reinterpret_cast and unchecked accessors.
7854void SharedFunctionInfo::AttachInitialMap(Map* map) {
7855 map->set_bit_field2(
7856 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
7857
7858 // Resume inobject slack tracking.
7859 set_initial_map(map);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007860 Builtins* builtins = map->GetHeap()->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01007861 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007862 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01007863 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007864 // The map survived the gc, so there may be objects referencing it.
7865 set_live_objects_may_exist(true);
7866}
7867
7868
7869static void GetMinInobjectSlack(Map* map, void* data) {
7870 int slack = map->unused_property_fields();
7871 if (*reinterpret_cast<int*>(data) > slack) {
7872 *reinterpret_cast<int*>(data) = slack;
7873 }
7874}
7875
7876
7877static void ShrinkInstanceSize(Map* map, void* data) {
7878 int slack = *reinterpret_cast<int*>(data);
7879 map->set_inobject_properties(map->inobject_properties() - slack);
7880 map->set_unused_property_fields(map->unused_property_fields() - slack);
7881 map->set_instance_size(map->instance_size() - slack * kPointerSize);
7882
7883 // Visitor id might depend on the instance size, recalculate it.
7884 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
7885}
7886
7887
7888void SharedFunctionInfo::CompleteInobjectSlackTracking() {
7889 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
7890 Map* map = Map::cast(initial_map());
7891
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007892 Heap* heap = map->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01007893 set_initial_map(heap->undefined_value());
7894 Builtins* builtins = heap->isolate()->builtins();
7895 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007896 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01007897 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007898
7899 int slack = map->unused_property_fields();
7900 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
7901 if (slack != 0) {
7902 // Resize the initial map and all maps in its transition tree.
7903 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007904
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007905 // Give the correct expected_nof_properties to initial maps created later.
7906 ASSERT(expected_nof_properties() >= slack);
7907 set_expected_nof_properties(expected_nof_properties() - slack);
7908 }
7909}
7910
7911
Ben Murdochc7cc0282012-03-05 14:35:55 +00007912#define DECLARE_TAG(ignore1, name, ignore2) name,
7913const char* const VisitorSynchronization::kTags[
7914 VisitorSynchronization::kNumberOfSyncTags] = {
7915 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7916};
7917#undef DECLARE_TAG
7918
7919
7920#define DECLARE_TAG(ignore1, ignore2, name) name,
7921const char* const VisitorSynchronization::kTagNames[
7922 VisitorSynchronization::kNumberOfSyncTags] = {
7923 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7924};
7925#undef DECLARE_TAG
7926
7927
Steve Blocka7e24c12009-10-30 11:49:00 +00007928void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
7929 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
7930 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
7931 Object* old_target = target;
7932 VisitPointer(&target);
7933 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
7934}
7935
7936
Steve Block791712a2010-08-27 10:21:07 +01007937void ObjectVisitor::VisitCodeEntry(Address entry_address) {
7938 Object* code = Code::GetObjectFromEntryAddress(entry_address);
7939 Object* old_code = code;
7940 VisitPointer(&code);
7941 if (code != old_code) {
7942 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
7943 }
7944}
7945
7946
Ben Murdochb0fe1622011-05-05 13:52:32 +01007947void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
7948 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
7949 Object* cell = rinfo->target_cell();
7950 Object* old_cell = cell;
7951 VisitPointer(&cell);
7952 if (cell != old_cell) {
7953 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
7954 }
7955}
7956
7957
Steve Blocka7e24c12009-10-30 11:49:00 +00007958void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007959 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
7960 rinfo->IsPatchedReturnSequence()) ||
7961 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
7962 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007963 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
7964 Object* old_target = target;
7965 VisitPointer(&target);
7966 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
7967}
7968
7969
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007970void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
7971 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
7972 VisitPointer(rinfo->target_object_address());
7973}
7974
7975void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
7976 Address* p = rinfo->target_reference_address();
7977 VisitExternalReferences(p, p + 1);
7978}
7979
Ben Murdochb0fe1622011-05-05 13:52:32 +01007980void Code::InvalidateRelocation() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007981 set_relocation_info(GetHeap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007982}
7983
7984
Steve Blockd0582a62009-12-15 09:54:21 +00007985void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007986 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
7987 it.rinfo()->apply(delta);
7988 }
7989 CPU::FlushICache(instruction_start(), instruction_size());
7990}
7991
7992
7993void Code::CopyFrom(const CodeDesc& desc) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00007994 ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
7995
Steve Blocka7e24c12009-10-30 11:49:00 +00007996 // copy code
7997 memmove(instruction_start(), desc.buffer, desc.instr_size);
7998
Steve Blocka7e24c12009-10-30 11:49:00 +00007999 // copy reloc info
8000 memmove(relocation_start(),
8001 desc.buffer + desc.buffer_size - desc.reloc_size,
8002 desc.reloc_size);
8003
8004 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +00008005 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +00008006 int mode_mask = RelocInfo::kCodeTargetMask |
8007 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb0fe1622011-05-05 13:52:32 +01008008 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
Steve Blocka7e24c12009-10-30 11:49:00 +00008009 RelocInfo::kApplyMask;
Steve Block3ce2e202009-11-05 08:53:23 +00008010 Assembler* origin = desc.origin; // Needed to find target_object on X64.
Steve Blocka7e24c12009-10-30 11:49:00 +00008011 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
8012 RelocInfo::Mode mode = it.rinfo()->rmode();
8013 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +00008014 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008015 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008016 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008017 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
8018 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
Steve Blocka7e24c12009-10-30 11:49:00 +00008019 } else if (RelocInfo::IsCodeTarget(mode)) {
8020 // rewrite code handles in inline cache targets to direct
8021 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +00008022 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00008023 Code* code = Code::cast(*p);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008024 it.rinfo()->set_target_address(code->instruction_start(),
8025 SKIP_WRITE_BARRIER);
Steve Blocka7e24c12009-10-30 11:49:00 +00008026 } else {
8027 it.rinfo()->apply(delta);
8028 }
8029 }
8030 CPU::FlushICache(instruction_start(), instruction_size());
8031}
8032
8033
8034// Locate the source position which is closest to the address in the code. This
8035// is using the source position information embedded in the relocation info.
8036// The position returned is relative to the beginning of the script where the
8037// source for this function is found.
8038int Code::SourcePosition(Address pc) {
8039 int distance = kMaxInt;
8040 int position = RelocInfo::kNoPosition; // Initially no position found.
8041 // Run through all the relocation info to find the best matching source
8042 // position. All the code needs to be considered as the sequence of the
8043 // instructions in the code does not necessarily follow the same order as the
8044 // source.
8045 RelocIterator it(this, RelocInfo::kPositionMask);
8046 while (!it.done()) {
8047 // Only look at positions after the current pc.
8048 if (it.rinfo()->pc() < pc) {
8049 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +00008050
8051 int dist = static_cast<int>(pc - it.rinfo()->pc());
8052 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00008053 // If this position is closer than the current candidate or if it has the
8054 // same distance as the current candidate and the position is higher then
8055 // this position is the new candidate.
8056 if ((dist < distance) ||
8057 (dist == distance && pos > position)) {
8058 position = pos;
8059 distance = dist;
8060 }
8061 }
8062 it.next();
8063 }
8064 return position;
8065}
8066
8067
8068// Same as Code::SourcePosition above except it only looks for statement
8069// positions.
8070int Code::SourceStatementPosition(Address pc) {
8071 // First find the position as close as possible using all position
8072 // information.
8073 int position = SourcePosition(pc);
8074 // Now find the closest statement position before the position.
8075 int statement_position = 0;
8076 RelocIterator it(this, RelocInfo::kPositionMask);
8077 while (!it.done()) {
8078 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +00008079 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00008080 if (statement_position < p && p <= position) {
8081 statement_position = p;
8082 }
8083 }
8084 it.next();
8085 }
8086 return statement_position;
8087}
8088
8089
Ben Murdochb8e0da22011-05-16 14:20:40 +01008090SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008091 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01008092 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008093}
8094
8095
8096void Code::SetNoStackCheckTable() {
8097 // Indicate the absence of a stack-check table by a table start after the
8098 // end of the instructions. Table start must be aligned, so round up.
Steve Block1e0659c2011-05-24 12:43:12 +01008099 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008100}
8101
8102
8103Map* Code::FindFirstMap() {
8104 ASSERT(is_inline_cache_stub());
8105 AssertNoAllocation no_allocation;
8106 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
8107 for (RelocIterator it(this, mask); !it.done(); it.next()) {
8108 RelocInfo* info = it.rinfo();
8109 Object* object = info->target_object();
8110 if (object->IsMap()) return Map::cast(object);
8111 }
8112 return NULL;
8113}
8114
8115
Steve Blocka7e24c12009-10-30 11:49:00 +00008116#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +01008117
Ben Murdochb0fe1622011-05-05 13:52:32 +01008118void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
8119 disasm::NameConverter converter;
8120 int deopt_count = DeoptCount();
8121 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
8122 if (0 == deopt_count) return;
8123
Ben Murdoch2b4ba112012-01-20 14:57:15 +00008124 PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc",
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008125 FLAG_print_code_verbose ? "commands" : "");
Ben Murdochb0fe1622011-05-05 13:52:32 +01008126 for (int i = 0; i < deopt_count; i++) {
Ben Murdoch2b4ba112012-01-20 14:57:15 +00008127 PrintF(out, "%6d %6d %6d %6d",
8128 i,
8129 AstId(i)->value(),
8130 ArgumentsStackHeight(i)->value(),
8131 Pc(i)->value());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008132
8133 if (!FLAG_print_code_verbose) {
8134 PrintF(out, "\n");
8135 continue;
8136 }
8137 // Print details of the frame translation.
Ben Murdochb0fe1622011-05-05 13:52:32 +01008138 int translation_index = TranslationIndex(i)->value();
8139 TranslationIterator iterator(TranslationByteArray(), translation_index);
8140 Translation::Opcode opcode =
8141 static_cast<Translation::Opcode>(iterator.Next());
8142 ASSERT(Translation::BEGIN == opcode);
8143 int frame_count = iterator.Next();
Ben Murdochc7cc0282012-03-05 14:35:55 +00008144 int jsframe_count = iterator.Next();
8145 PrintF(out, " %s {frame count=%d, js frame count=%d}\n",
8146 Translation::StringFor(opcode),
8147 frame_count,
8148 jsframe_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008149
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008150 while (iterator.HasNext() &&
8151 Translation::BEGIN !=
8152 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
8153 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
8154
8155 switch (opcode) {
8156 case Translation::BEGIN:
8157 UNREACHABLE();
8158 break;
8159
Ben Murdochc7cc0282012-03-05 14:35:55 +00008160 case Translation::JS_FRAME: {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008161 int ast_id = iterator.Next();
8162 int function_id = iterator.Next();
8163 JSFunction* function =
8164 JSFunction::cast(LiteralArray()->get(function_id));
8165 unsigned height = iterator.Next();
Ben Murdoch589d6972011-11-30 16:04:58 +00008166 PrintF(out, "{ast_id=%d, function=", ast_id);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008167 function->PrintName(out);
8168 PrintF(out, ", height=%u}", height);
8169 break;
8170 }
8171
Ben Murdochc7cc0282012-03-05 14:35:55 +00008172 case Translation::ARGUMENTS_ADAPTOR_FRAME: {
8173 unsigned height = iterator.Next();
8174 PrintF(out, "{arguments adaptor, height=%d}", height);
8175 break;
8176 }
8177
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008178 case Translation::DUPLICATE:
8179 break;
8180
8181 case Translation::REGISTER: {
8182 int reg_code = iterator.Next();
8183 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8184 break;
8185 }
8186
8187 case Translation::INT32_REGISTER: {
8188 int reg_code = iterator.Next();
8189 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8190 break;
8191 }
8192
8193 case Translation::DOUBLE_REGISTER: {
8194 int reg_code = iterator.Next();
8195 PrintF(out, "{input=%s}",
8196 DoubleRegister::AllocationIndexToString(reg_code));
8197 break;
8198 }
8199
8200 case Translation::STACK_SLOT: {
8201 int input_slot_index = iterator.Next();
8202 PrintF(out, "{input=%d}", input_slot_index);
8203 break;
8204 }
8205
8206 case Translation::INT32_STACK_SLOT: {
8207 int input_slot_index = iterator.Next();
8208 PrintF(out, "{input=%d}", input_slot_index);
8209 break;
8210 }
8211
8212 case Translation::DOUBLE_STACK_SLOT: {
8213 int input_slot_index = iterator.Next();
8214 PrintF(out, "{input=%d}", input_slot_index);
8215 break;
8216 }
8217
8218 case Translation::LITERAL: {
8219 unsigned literal_index = iterator.Next();
8220 PrintF(out, "{literal_id=%u}", literal_index);
8221 break;
8222 }
8223
8224 case Translation::ARGUMENTS_OBJECT:
8225 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008226 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008227 PrintF(out, "\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01008228 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008229 }
8230}
8231
8232
8233void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
8234 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
8235 this->DeoptPoints());
8236 if (this->DeoptPoints() == 0) return;
8237
8238 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
8239 for (int i = 0; i < this->DeoptPoints(); i++) {
8240 int pc_and_state = this->PcAndState(i)->value();
8241 PrintF("%6d %8d %s\n",
8242 this->AstId(i)->value(),
8243 FullCodeGenerator::PcField::decode(pc_and_state),
8244 FullCodeGenerator::State2String(
8245 FullCodeGenerator::StateField::decode(pc_and_state)));
8246 }
8247}
8248
Ben Murdochb0fe1622011-05-05 13:52:32 +01008249
Steve Blocka7e24c12009-10-30 11:49:00 +00008250// Identify kind of code.
8251const char* Code::Kind2String(Kind kind) {
8252 switch (kind) {
8253 case FUNCTION: return "FUNCTION";
Ben Murdochb0fe1622011-05-05 13:52:32 +01008254 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
Steve Blocka7e24c12009-10-30 11:49:00 +00008255 case STUB: return "STUB";
8256 case BUILTIN: return "BUILTIN";
8257 case LOAD_IC: return "LOAD_IC";
8258 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
8259 case STORE_IC: return "STORE_IC";
8260 case KEYED_STORE_IC: return "KEYED_STORE_IC";
8261 case CALL_IC: return "CALL_IC";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008262 case KEYED_CALL_IC: return "KEYED_CALL_IC";
Ben Murdoch257744e2011-11-30 15:57:28 +00008263 case UNARY_OP_IC: return "UNARY_OP_IC";
8264 case BINARY_OP_IC: return "BINARY_OP_IC";
Ben Murdochb0fe1622011-05-05 13:52:32 +01008265 case COMPARE_IC: return "COMPARE_IC";
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008266 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00008267 }
8268 UNREACHABLE();
8269 return NULL;
8270}
8271
8272
8273const char* Code::ICState2String(InlineCacheState state) {
8274 switch (state) {
8275 case UNINITIALIZED: return "UNINITIALIZED";
8276 case PREMONOMORPHIC: return "PREMONOMORPHIC";
8277 case MONOMORPHIC: return "MONOMORPHIC";
8278 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
8279 case MEGAMORPHIC: return "MEGAMORPHIC";
8280 case DEBUG_BREAK: return "DEBUG_BREAK";
8281 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
8282 }
8283 UNREACHABLE();
8284 return NULL;
8285}
8286
8287
8288const char* Code::PropertyType2String(PropertyType type) {
8289 switch (type) {
8290 case NORMAL: return "NORMAL";
8291 case FIELD: return "FIELD";
8292 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
8293 case CALLBACKS: return "CALLBACKS";
Ben Murdoch257744e2011-11-30 15:57:28 +00008294 case HANDLER: return "HANDLER";
Steve Blocka7e24c12009-10-30 11:49:00 +00008295 case INTERCEPTOR: return "INTERCEPTOR";
8296 case MAP_TRANSITION: return "MAP_TRANSITION";
Ben Murdoch589d6972011-11-30 16:04:58 +00008297 case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
Steve Blocka7e24c12009-10-30 11:49:00 +00008298 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
8299 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
8300 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008301 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +00008302 return NULL;
8303}
8304
Ben Murdochb0fe1622011-05-05 13:52:32 +01008305
Steve Block1e0659c2011-05-24 12:43:12 +01008306void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
8307 const char* name = NULL;
8308 switch (kind) {
8309 case CALL_IC:
8310 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
8311 name = "STRING_INDEX_OUT_OF_BOUNDS";
8312 }
8313 break;
8314 case STORE_IC:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008315 case KEYED_STORE_IC:
8316 if (extra == kStrictMode) {
Steve Block1e0659c2011-05-24 12:43:12 +01008317 name = "STRICT";
8318 }
8319 break;
8320 default:
8321 break;
8322 }
8323 if (name != NULL) {
8324 PrintF(out, "extra_ic_state = %s\n", name);
8325 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008326 PrintF(out, "extra_ic_state = %d\n", extra);
Steve Block1e0659c2011-05-24 12:43:12 +01008327 }
8328}
8329
8330
Ben Murdochb0fe1622011-05-05 13:52:32 +01008331void Code::Disassemble(const char* name, FILE* out) {
8332 PrintF(out, "kind = %s\n", Kind2String(kind()));
Steve Blocka7e24c12009-10-30 11:49:00 +00008333 if (is_inline_cache_stub()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008334 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
Steve Block1e0659c2011-05-24 12:43:12 +01008335 PrintExtraICState(out, kind(), extra_ic_state());
Steve Blocka7e24c12009-10-30 11:49:00 +00008336 if (ic_state() == MONOMORPHIC) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008337 PrintF(out, "type = %s\n", PropertyType2String(type()));
Steve Blocka7e24c12009-10-30 11:49:00 +00008338 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008339 if (is_call_stub() || is_keyed_call_stub()) {
8340 PrintF(out, "argc = %d\n", arguments_count());
8341 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008342 }
8343 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008344 PrintF(out, "name = %s\n", name);
8345 }
8346 if (kind() == OPTIMIZED_FUNCTION) {
8347 PrintF(out, "stack_slots = %d\n", stack_slots());
Steve Blocka7e24c12009-10-30 11:49:00 +00008348 }
8349
Ben Murdochb0fe1622011-05-05 13:52:32 +01008350 PrintF(out, "Instructions (size = %d)\n", instruction_size());
8351 Disassembler::Decode(out, this);
8352 PrintF(out, "\n");
8353
Ben Murdochb0fe1622011-05-05 13:52:32 +01008354 if (kind() == FUNCTION) {
8355 DeoptimizationOutputData* data =
8356 DeoptimizationOutputData::cast(this->deoptimization_data());
8357 data->DeoptimizationOutputDataPrint(out);
8358 } else if (kind() == OPTIMIZED_FUNCTION) {
8359 DeoptimizationInputData* data =
8360 DeoptimizationInputData::cast(this->deoptimization_data());
8361 data->DeoptimizationInputDataPrint(out);
8362 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008363 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01008364
8365 if (kind() == OPTIMIZED_FUNCTION) {
8366 SafepointTable table(this);
8367 PrintF(out, "Safepoints (size = %u)\n", table.size());
8368 for (unsigned i = 0; i < table.length(); i++) {
8369 unsigned pc_offset = table.GetPcOffset(i);
8370 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
8371 table.PrintEntry(i);
8372 PrintF(out, " (sp -> fp)");
Ben Murdochb8e0da22011-05-16 14:20:40 +01008373 SafepointEntry entry = table.GetEntry(i);
8374 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
8375 PrintF(out, " %6d", entry.deoptimization_index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008376 } else {
8377 PrintF(out, " <none>");
8378 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01008379 if (entry.argument_count() > 0) {
8380 PrintF(out, " argc: %d", entry.argument_count());
8381 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008382 PrintF(out, "\n");
8383 }
8384 PrintF(out, "\n");
8385 } else if (kind() == FUNCTION) {
Steve Block1e0659c2011-05-24 12:43:12 +01008386 unsigned offset = stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008387 // If there is no stack check table, the "table start" will at or after
8388 // (due to alignment) the end of the instruction stream.
8389 if (static_cast<int>(offset) < instruction_size()) {
8390 unsigned* address =
8391 reinterpret_cast<unsigned*>(instruction_start() + offset);
8392 unsigned length = address[0];
8393 PrintF(out, "Stack checks (size = %u)\n", length);
8394 PrintF(out, "ast_id pc_offset\n");
8395 for (unsigned i = 0; i < length; ++i) {
8396 unsigned index = (2 * i) + 1;
8397 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
8398 }
8399 PrintF(out, "\n");
8400 }
8401 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008402
8403 PrintF("RelocInfo (size = %d)\n", relocation_size());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008404 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
8405 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00008406}
8407#endif // ENABLE_DISASSEMBLER
8408
8409
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008410static void CopyFastElementsToFast(FixedArray* source,
8411 FixedArray* destination,
8412 WriteBarrierMode mode) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008413 int count = source->length();
8414 int copy_size = Min(count, destination->length());
8415 if (mode == SKIP_WRITE_BARRIER ||
8416 !Page::FromAddress(destination->address())->IsFlagSet(
8417 MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING)) {
8418 Address to = destination->address() + FixedArray::kHeaderSize;
8419 Address from = source->address() + FixedArray::kHeaderSize;
8420 memcpy(reinterpret_cast<void*>(to),
8421 reinterpret_cast<void*>(from),
8422 kPointerSize * copy_size);
8423 } else {
8424 for (int i = 0; i < copy_size; ++i) {
8425 destination->set(i, source->get(i), mode);
8426 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008427 }
8428}
8429
8430
Ben Murdochc7cc0282012-03-05 14:35:55 +00008431static void CopySlowElementsToFast(SeededNumberDictionary* source,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008432 FixedArray* destination,
8433 WriteBarrierMode mode) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008434 int destination_length = destination->length();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008435 for (int i = 0; i < source->Capacity(); ++i) {
8436 Object* key = source->KeyAt(i);
8437 if (key->IsNumber()) {
8438 uint32_t entry = static_cast<uint32_t>(key->Number());
Ben Murdochc7cc0282012-03-05 14:35:55 +00008439 if (entry < static_cast<uint32_t>(destination_length)) {
8440 destination->set(entry, source->ValueAt(i), mode);
8441 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008442 }
8443 }
8444}
8445
8446
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008447MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8448 int capacity,
8449 int length,
8450 SetFastElementsCapacityMode set_capacity_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01008451 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00008452 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01008453 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01008454
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008455 // Allocate a new fast elements backing store.
8456 FixedArray* new_elements = NULL;
8457 { Object* object;
8458 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
8459 if (!maybe->ToObject(&object)) return maybe;
8460 new_elements = FixedArray::cast(object);
8461 }
8462
8463 // Find the new map to use for this object if there is a map change.
8464 Map* new_map = NULL;
8465 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
8466 Object* object;
Ben Murdochc7cc0282012-03-05 14:35:55 +00008467 // The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces
8468 // it, or if it's allowed and the old elements array contained only SMIs.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008469 bool has_fast_smi_only_elements =
Ben Murdochc7cc0282012-03-05 14:35:55 +00008470 (set_capacity_mode == kForceSmiOnlyElements) ||
8471 ((set_capacity_mode == kAllowSmiOnlyElements) &&
8472 (elements()->map()->has_fast_smi_only_elements() ||
8473 elements() == heap->empty_fixed_array()));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008474 ElementsKind elements_kind = has_fast_smi_only_elements
8475 ? FAST_SMI_ONLY_ELEMENTS
8476 : FAST_ELEMENTS;
8477 MaybeObject* maybe = GetElementsTransitionMap(elements_kind);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008478 if (!maybe->ToObject(&object)) return maybe;
8479 new_map = Map::cast(object);
8480 }
8481
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008482 FixedArrayBase* old_elements_raw = elements();
8483 ElementsKind elements_kind = GetElementsKind();
8484 switch (elements_kind) {
8485 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008486 case FAST_ELEMENTS: {
8487 AssertNoAllocation no_gc;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008488 WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc));
8489 CopyFastElementsToFast(FixedArray::cast(old_elements_raw),
8490 new_elements, mode);
Ben Murdochc7cc0282012-03-05 14:35:55 +00008491 set_map_and_elements(new_map, new_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008492 break;
8493 }
8494 case DICTIONARY_ELEMENTS: {
8495 AssertNoAllocation no_gc;
8496 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
Ben Murdochc7cc0282012-03-05 14:35:55 +00008497 CopySlowElementsToFast(SeededNumberDictionary::cast(old_elements_raw),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008498 new_elements,
8499 mode);
Ben Murdochc7cc0282012-03-05 14:35:55 +00008500 set_map_and_elements(new_map, new_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008501 break;
8502 }
8503 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8504 AssertNoAllocation no_gc;
8505 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
8506 // The object's map and the parameter map are unchanged, the unaliased
8507 // arguments are copied to the new backing store.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008508 FixedArray* parameter_map = FixedArray::cast(old_elements_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008509 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8510 if (arguments->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008511 CopySlowElementsToFast(SeededNumberDictionary::cast(arguments),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008512 new_elements,
8513 mode);
8514 } else {
8515 CopyFastElementsToFast(arguments, new_elements, mode);
8516 }
8517 parameter_map->set(1, new_elements);
8518 break;
8519 }
8520 case FAST_DOUBLE_ELEMENTS: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008521 FixedDoubleArray* old_elements = FixedDoubleArray::cast(old_elements_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008522 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
8523 // Fill out the new array with this content and array holes.
8524 for (uint32_t i = 0; i < old_length; i++) {
8525 if (!old_elements->is_the_hole(i)) {
8526 Object* obj;
8527 // Objects must be allocated in the old object space, since the
8528 // overall number of HeapNumbers needed for the conversion might
8529 // exceed the capacity of new space, and we would fail repeatedly
8530 // trying to convert the FixedDoubleArray.
8531 MaybeObject* maybe_value_object =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008532 GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
8533 TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008534 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
8535 // Force write barrier. It's not worth trying to exploit
8536 // elems->GetWriteBarrierMode(), since it requires an
8537 // AssertNoAllocation stack object that would have to be positioned
8538 // after the HeapNumber allocation anyway.
8539 new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
8540 }
8541 }
8542 set_map(new_map);
8543 set_elements(new_elements);
8544 break;
8545 }
8546 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:
8552 case EXTERNAL_FLOAT_ELEMENTS:
8553 case EXTERNAL_DOUBLE_ELEMENTS:
8554 case EXTERNAL_PIXEL_ELEMENTS:
8555 UNREACHABLE();
8556 break;
8557 }
8558
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008559 if (FLAG_trace_elements_transitions) {
8560 PrintElementsTransition(stdout, elements_kind, old_elements_raw,
8561 FAST_ELEMENTS, new_elements);
8562 }
8563
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008564 // Update the length if necessary.
8565 if (IsJSArray()) {
8566 JSArray::cast(this)->set_length(Smi::FromInt(length));
8567 }
8568
8569 return new_elements;
8570}
8571
8572
8573MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
8574 int capacity,
8575 int length) {
8576 Heap* heap = GetHeap();
8577 // We should never end in here with a pixel or external array.
8578 ASSERT(!HasExternalArrayElements());
8579
John Reck59135872010-11-02 12:39:01 -07008580 Object* obj;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008581 { MaybeObject* maybe_obj =
8582 heap->AllocateUninitializedFixedDoubleArray(capacity);
John Reck59135872010-11-02 12:39:01 -07008583 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8584 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008585 FixedDoubleArray* elems = FixedDoubleArray::cast(obj);
Steve Block8defd9f2010-07-08 12:39:36 +01008586
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008587 { MaybeObject* maybe_obj =
8588 GetElementsTransitionMap(FAST_DOUBLE_ELEMENTS);
John Reck59135872010-11-02 12:39:01 -07008589 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8590 }
Steve Block8defd9f2010-07-08 12:39:36 +01008591 Map* new_map = Map::cast(obj);
8592
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008593 FixedArrayBase* old_elements = elements();
8594 ElementsKind elements_kind(GetElementsKind());
Leon Clarke4515c472010-02-03 11:58:03 +00008595 AssertNoAllocation no_gc;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008596 switch (elements_kind) {
8597 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00008598 case FAST_ELEMENTS: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008599 elems->Initialize(FixedArray::cast(old_elements));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008600 break;
8601 }
8602 case FAST_DOUBLE_ELEMENTS: {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008603 elems->Initialize(FixedDoubleArray::cast(old_elements));
Steve Blocka7e24c12009-10-30 11:49:00 +00008604 break;
8605 }
8606 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008607 elems->Initialize(SeededNumberDictionary::cast(old_elements));
Steve Blocka7e24c12009-10-30 11:49:00 +00008608 break;
8609 }
8610 default:
8611 UNREACHABLE();
8612 break;
8613 }
Steve Block8defd9f2010-07-08 12:39:36 +01008614
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008615 if (FLAG_trace_elements_transitions) {
8616 PrintElementsTransition(stdout, elements_kind, old_elements,
8617 FAST_DOUBLE_ELEMENTS, elems);
8618 }
8619
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008620 ASSERT(new_map->has_fast_double_elements());
Steve Block8defd9f2010-07-08 12:39:36 +01008621 set_map(new_map);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008622 ASSERT(elems->IsFixedDoubleArray());
Steve Blocka7e24c12009-10-30 11:49:00 +00008623 set_elements(elems);
Steve Block8defd9f2010-07-08 12:39:36 +01008624
8625 if (IsJSArray()) {
8626 JSArray::cast(this)->set_length(Smi::FromInt(length));
8627 }
8628
8629 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00008630}
8631
8632
John Reck59135872010-11-02 12:39:01 -07008633MaybeObject* JSArray::Initialize(int capacity) {
Steve Block44f0eee2011-05-26 01:26:41 +01008634 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008635 ASSERT(capacity >= 0);
Leon Clarke4515c472010-02-03 11:58:03 +00008636 set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00008637 FixedArray* new_elements;
8638 if (capacity == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01008639 new_elements = heap->empty_fixed_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00008640 } else {
John Reck59135872010-11-02 12:39:01 -07008641 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01008642 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07008643 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8644 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008645 new_elements = FixedArray::cast(obj);
8646 }
8647 set_elements(new_elements);
8648 return this;
8649}
8650
8651
8652void JSArray::Expand(int required_size) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008653 GetIsolate()->factory()->SetElementsCapacityAndLength(
8654 Handle<JSArray>(this), required_size, required_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00008655}
8656
8657
Ben Murdochc7cc0282012-03-05 14:35:55 +00008658MaybeObject* JSArray::SetElementsLength(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00008659 // We should never end in here with a pixel or external array.
Steve Block6ded16b2010-05-10 14:33:55 +01008660 ASSERT(AllowsSetElementsLength());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008661 return GetElementsAccessor()->SetLength(this, len);
Steve Blocka7e24c12009-10-30 11:49:00 +00008662}
8663
8664
Steve Block053d10c2011-06-13 19:13:29 +01008665Object* Map::GetPrototypeTransition(Object* prototype) {
8666 FixedArray* cache = prototype_transitions();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008667 int number_of_transitions = NumberOfProtoTransitions();
8668 const int proto_offset =
8669 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
8670 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
8671 const int step = kProtoTransitionElementsPerEntry;
8672 for (int i = 0; i < number_of_transitions; i++) {
8673 if (cache->get(proto_offset + i * step) == prototype) {
8674 Object* map = cache->get(map_offset + i * step);
8675 ASSERT(map->IsMap());
8676 return map;
8677 }
Steve Block053d10c2011-06-13 19:13:29 +01008678 }
8679 return NULL;
8680}
8681
8682
8683MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008684 ASSERT(map->IsMap());
8685 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
Steve Block053d10c2011-06-13 19:13:29 +01008686 // Don't cache prototype transition if this map is shared.
8687 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
8688
8689 FixedArray* cache = prototype_transitions();
8690
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008691 const int step = kProtoTransitionElementsPerEntry;
8692 const int header = kProtoTransitionHeaderSize;
Steve Block053d10c2011-06-13 19:13:29 +01008693
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008694 int capacity = (cache->length() - header) / step;
Steve Block053d10c2011-06-13 19:13:29 +01008695
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008696 int transitions = NumberOfProtoTransitions() + 1;
8697
8698 if (transitions > capacity) {
Steve Block053d10c2011-06-13 19:13:29 +01008699 if (capacity > kMaxCachedPrototypeTransitions) return this;
8700
8701 FixedArray* new_cache;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008702 // Grow array by factor 2 over and above what we need.
8703 { MaybeObject* maybe_cache =
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008704 GetHeap()->AllocateFixedArray(transitions * 2 * step + header);
Steve Block053d10c2011-06-13 19:13:29 +01008705 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
8706 }
8707
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008708 for (int i = 0; i < capacity * step; i++) {
8709 new_cache->set(i + header, cache->get(i + header));
8710 }
Steve Block053d10c2011-06-13 19:13:29 +01008711 cache = new_cache;
8712 set_prototype_transitions(cache);
8713 }
8714
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008715 int last = transitions - 1;
8716
8717 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
8718 cache->set(header + last * step + kProtoTransitionMapOffset, map);
8719 SetNumberOfProtoTransitions(transitions);
Steve Block053d10c2011-06-13 19:13:29 +01008720
8721 return cache;
8722}
8723
8724
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008725MaybeObject* JSReceiver::SetPrototype(Object* value,
8726 bool skip_hidden_prototypes) {
8727#ifdef DEBUG
8728 int size = Size();
8729#endif
8730
Steve Block44f0eee2011-05-26 01:26:41 +01008731 Heap* heap = GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +00008732 // Silently ignore the change if value is not a JSObject or null.
8733 // SpiderMonkey behaves this way.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008734 if (!value->IsJSReceiver() && !value->IsNull()) return value;
Andrei Popescu402d9372010-02-26 13:31:12 +00008735
Ben Murdoch8b112d22011-06-08 16:22:53 +01008736 // From 8.6.2 Object Internal Methods
8737 // ...
8738 // In addition, if [[Extensible]] is false the value of the [[Class]] and
8739 // [[Prototype]] internal properties of the object may not be modified.
8740 // ...
8741 // Implementation specific extensions that modify [[Class]], [[Prototype]]
8742 // or [[Extensible]] must not violate the invariants defined in the preceding
8743 // paragraph.
8744 if (!this->map()->is_extensible()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008745 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01008746 Handle<Object> handle(this, heap->isolate());
8747 return heap->isolate()->Throw(
8748 *FACTORY->NewTypeError("non_extensible_proto",
8749 HandleVector<Object>(&handle, 1)));
8750 }
8751
Andrei Popescu402d9372010-02-26 13:31:12 +00008752 // Before we can set the prototype we need to be sure
8753 // prototype cycles are prevented.
8754 // It is sufficient to validate that the receiver is not in the new prototype
8755 // chain.
Steve Block44f0eee2011-05-26 01:26:41 +01008756 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008757 if (JSReceiver::cast(pt) == this) {
Andrei Popescu402d9372010-02-26 13:31:12 +00008758 // Cycle detected.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008759 HandleScope scope(heap->isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01008760 return heap->isolate()->Throw(
8761 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
Andrei Popescu402d9372010-02-26 13:31:12 +00008762 }
8763 }
8764
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008765 JSReceiver* real_receiver = this;
Andrei Popescu402d9372010-02-26 13:31:12 +00008766
8767 if (skip_hidden_prototypes) {
8768 // Find the first object in the chain whose prototype object is not
8769 // hidden and set the new prototype on that object.
8770 Object* current_proto = real_receiver->GetPrototype();
8771 while (current_proto->IsJSObject() &&
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008772 JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) {
8773 real_receiver = JSReceiver::cast(current_proto);
Andrei Popescu402d9372010-02-26 13:31:12 +00008774 current_proto = current_proto->GetPrototype();
8775 }
8776 }
8777
8778 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +01008779 Map* map = real_receiver->map();
8780
8781 // Nothing to do if prototype is already set.
8782 if (map->prototype() == value) return value;
8783
8784 Object* new_map = map->GetPrototypeTransition(value);
8785 if (new_map == NULL) {
8786 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
8787 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
8788 }
8789
8790 { MaybeObject* maybe_new_cache =
8791 map->PutPrototypeTransition(value, Map::cast(new_map));
8792 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
8793 }
8794
8795 Map::cast(new_map)->set_prototype(value);
John Reck59135872010-11-02 12:39:01 -07008796 }
Steve Block053d10c2011-06-13 19:13:29 +01008797 ASSERT(Map::cast(new_map)->prototype() == value);
Andrei Popescu402d9372010-02-26 13:31:12 +00008798 real_receiver->set_map(Map::cast(new_map));
8799
Steve Block44f0eee2011-05-26 01:26:41 +01008800 heap->ClearInstanceofCache();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008801 ASSERT(size == Size());
Andrei Popescu402d9372010-02-26 13:31:12 +00008802 return value;
8803}
8804
8805
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008806MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
8807 uint32_t first_arg,
Ben Murdochc7cc0282012-03-05 14:35:55 +00008808 uint32_t arg_count,
8809 EnsureElementsMode mode) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008810 // Elements in |Arguments| are ordered backwards (because they're on the
8811 // stack), but the method that's called here iterates over them in forward
8812 // direction.
8813 return EnsureCanContainElements(
8814 args->arguments() - first_arg - (arg_count - 1),
Ben Murdochc7cc0282012-03-05 14:35:55 +00008815 arg_count, mode);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008816}
8817
8818
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008819bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008820 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008821 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00008822 case FAST_ELEMENTS: {
8823 uint32_t length = IsJSArray() ?
8824 static_cast<uint32_t>
8825 (Smi::cast(JSArray::cast(this)->length())->value()) :
8826 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8827 if ((index < length) &&
8828 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8829 return true;
8830 }
8831 break;
8832 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008833 case FAST_DOUBLE_ELEMENTS: {
8834 uint32_t length = IsJSArray() ?
8835 static_cast<uint32_t>
8836 (Smi::cast(JSArray::cast(this)->length())->value()) :
8837 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8838 if ((index < length) &&
8839 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
8840 return true;
8841 }
8842 break;
8843 }
Steve Block44f0eee2011-05-26 01:26:41 +01008844 case EXTERNAL_PIXEL_ELEMENTS: {
8845 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008846 if (index < static_cast<uint32_t>(pixels->length())) {
8847 return true;
8848 }
8849 break;
8850 }
Steve Block3ce2e202009-11-05 08:53:23 +00008851 case EXTERNAL_BYTE_ELEMENTS:
8852 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8853 case EXTERNAL_SHORT_ELEMENTS:
8854 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8855 case EXTERNAL_INT_ELEMENTS:
8856 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008857 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008858 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008859 ExternalArray* array = ExternalArray::cast(elements());
8860 if (index < static_cast<uint32_t>(array->length())) {
8861 return true;
8862 }
8863 break;
8864 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008865 case DICTIONARY_ELEMENTS: {
8866 if (element_dictionary()->FindEntry(index)
Ben Murdochc7cc0282012-03-05 14:35:55 +00008867 != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008868 return true;
8869 }
8870 break;
8871 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008872 case NON_STRICT_ARGUMENTS_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00008873 UNREACHABLE();
8874 break;
8875 }
8876
8877 // Handle [] on String objects.
8878 if (this->IsStringObjectWithCharacterAt(index)) return true;
8879
8880 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01008881 if (pt->IsNull()) return false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008882 if (pt->IsJSProxy()) {
8883 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8884 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8885 receiver, index) != ABSENT;
8886 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008887 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8888}
8889
8890
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008891bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01008892 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008893 // Make sure that the top context does not change when doing
8894 // callbacks or interceptor calls.
8895 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008896 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008897 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008898 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00008899 Handle<JSObject> holder_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01008900 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008901 v8::AccessorInfo info(args.end());
8902 if (!interceptor->query()->IsUndefined()) {
8903 v8::IndexedPropertyQuery query =
8904 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01008905 LOG(isolate,
8906 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
Iain Merrick75681382010-08-19 15:07:18 +01008907 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00008908 {
8909 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008910 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008911 result = query(index, info);
8912 }
Iain Merrick75681382010-08-19 15:07:18 +01008913 if (!result.IsEmpty()) {
8914 ASSERT(result->IsInt32());
8915 return true; // absence of property is signaled by empty handle.
8916 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008917 } else if (!interceptor->getter()->IsUndefined()) {
8918 v8::IndexedPropertyGetter getter =
8919 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008920 LOG(isolate,
8921 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
Steve Blocka7e24c12009-10-30 11:49:00 +00008922 v8::Handle<v8::Value> result;
8923 {
8924 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008925 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008926 result = getter(index, info);
8927 }
8928 if (!result.IsEmpty()) return true;
8929 }
8930 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
8931}
8932
8933
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008934JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008935 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008936 if (IsAccessCheckNeeded()) {
8937 Heap* heap = GetHeap();
8938 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8939 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8940 return UNDEFINED_ELEMENT;
8941 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008942 }
8943
Steve Block1e0659c2011-05-24 12:43:12 +01008944 if (IsJSGlobalProxy()) {
8945 Object* proto = GetPrototype();
8946 if (proto->IsNull()) return UNDEFINED_ELEMENT;
8947 ASSERT(proto->IsJSGlobalObject());
8948 return JSObject::cast(proto)->HasLocalElement(index);
8949 }
8950
Steve Blocka7e24c12009-10-30 11:49:00 +00008951 // Check for lookup interceptor
8952 if (HasIndexedInterceptor()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008953 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
8954 : UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00008955 }
8956
8957 // Handle [] on String objects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008958 if (this->IsStringObjectWithCharacterAt(index)) {
8959 return STRING_CHARACTER_ELEMENT;
8960 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008961
8962 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008963 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00008964 case FAST_ELEMENTS: {
8965 uint32_t length = IsJSArray() ?
8966 static_cast<uint32_t>
8967 (Smi::cast(JSArray::cast(this)->length())->value()) :
8968 static_cast<uint32_t>(FixedArray::cast(elements())->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008969 if ((index < length) &&
8970 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8971 return FAST_ELEMENT;
8972 }
8973 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008974 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008975 case FAST_DOUBLE_ELEMENTS: {
8976 uint32_t length = IsJSArray() ?
8977 static_cast<uint32_t>
8978 (Smi::cast(JSArray::cast(this)->length())->value()) :
8979 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8980 if ((index < length) &&
8981 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
8982 return FAST_ELEMENT;
8983 }
8984 break;
8985 }
Steve Block44f0eee2011-05-26 01:26:41 +01008986 case EXTERNAL_PIXEL_ELEMENTS: {
8987 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008988 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
8989 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008990 }
Steve Block3ce2e202009-11-05 08:53:23 +00008991 case EXTERNAL_BYTE_ELEMENTS:
8992 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8993 case EXTERNAL_SHORT_ELEMENTS:
8994 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8995 case EXTERNAL_INT_ELEMENTS:
8996 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008997 case EXTERNAL_FLOAT_ELEMENTS:
8998 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008999 ExternalArray* array = ExternalArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009000 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
9001 break;
Steve Block3ce2e202009-11-05 08:53:23 +00009002 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009003 case DICTIONARY_ELEMENTS: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009004 if (element_dictionary()->FindEntry(index) !=
Ben Murdochc7cc0282012-03-05 14:35:55 +00009005 SeededNumberDictionary::kNotFound) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009006 return DICTIONARY_ELEMENT;
9007 }
9008 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00009009 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009010 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9011 // Aliased parameters and non-aliased elements in a fast backing store
9012 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
9013 // backing store behave as DICTIONARY_ELEMENT.
9014 FixedArray* parameter_map = FixedArray::cast(elements());
9015 uint32_t length = parameter_map->length();
9016 Object* probe =
9017 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
9018 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
9019 // If not aliased, check the arguments.
9020 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9021 if (arguments->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009022 SeededNumberDictionary* dictionary =
9023 SeededNumberDictionary::cast(arguments);
9024 if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009025 return DICTIONARY_ELEMENT;
9026 }
9027 } else {
9028 length = arguments->length();
9029 probe = (index < length) ? arguments->get(index) : NULL;
9030 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
9031 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009032 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009033 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009034 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009035
9036 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00009037}
9038
9039
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009040bool JSObject::HasElementInElements(FixedArray* elements,
9041 ElementsKind kind,
9042 uint32_t index) {
9043 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
9044 if (kind == FAST_ELEMENTS) {
9045 int length = IsJSArray()
9046 ? Smi::cast(JSArray::cast(this)->length())->value()
9047 : elements->length();
9048 if (index < static_cast<uint32_t>(length) &&
9049 !elements->get(index)->IsTheHole()) {
9050 return true;
9051 }
9052 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009053 if (SeededNumberDictionary::cast(elements)->FindEntry(index) !=
9054 SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009055 return true;
9056 }
9057 }
9058 return false;
9059}
9060
9061
9062bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009063 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009064 if (IsAccessCheckNeeded()) {
9065 Heap* heap = GetHeap();
9066 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
9067 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9068 return false;
9069 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009070 }
9071
9072 // Check for lookup interceptor
9073 if (HasIndexedInterceptor()) {
9074 return HasElementWithInterceptor(receiver, index);
9075 }
9076
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009077 ElementsKind kind = GetElementsKind();
9078 switch (kind) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009079 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00009080 case FAST_ELEMENTS: {
9081 uint32_t length = IsJSArray() ?
9082 static_cast<uint32_t>
9083 (Smi::cast(JSArray::cast(this)->length())->value()) :
9084 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9085 if ((index < length) &&
9086 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
9087 break;
9088 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009089 case FAST_DOUBLE_ELEMENTS: {
9090 uint32_t length = IsJSArray() ?
9091 static_cast<uint32_t>
9092 (Smi::cast(JSArray::cast(this)->length())->value()) :
9093 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
9094 if ((index < length) &&
9095 !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
9096 break;
9097 }
Steve Block44f0eee2011-05-26 01:26:41 +01009098 case EXTERNAL_PIXEL_ELEMENTS: {
9099 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009100 if (index < static_cast<uint32_t>(pixels->length())) {
9101 return true;
9102 }
9103 break;
9104 }
Steve Block3ce2e202009-11-05 08:53:23 +00009105 case EXTERNAL_BYTE_ELEMENTS:
9106 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9107 case EXTERNAL_SHORT_ELEMENTS:
9108 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9109 case EXTERNAL_INT_ELEMENTS:
9110 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009111 case EXTERNAL_FLOAT_ELEMENTS:
9112 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00009113 ExternalArray* array = ExternalArray::cast(elements());
9114 if (index < static_cast<uint32_t>(array->length())) {
9115 return true;
9116 }
9117 break;
9118 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009119 case DICTIONARY_ELEMENTS: {
9120 if (element_dictionary()->FindEntry(index)
Ben Murdochc7cc0282012-03-05 14:35:55 +00009121 != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009122 return true;
9123 }
9124 break;
9125 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009126 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9127 FixedArray* parameter_map = FixedArray::cast(elements());
9128 uint32_t length = parameter_map->length();
9129 Object* probe =
9130 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
9131 if (probe != NULL && !probe->IsTheHole()) return true;
9132
9133 // Not a mapped parameter, check the arguments.
9134 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9135 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
9136 if (HasElementInElements(arguments, kind, index)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00009137 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009138 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009139 }
9140
9141 // Handle [] on String objects.
9142 if (this->IsStringObjectWithCharacterAt(index)) return true;
9143
9144 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01009145 if (pt->IsNull()) return false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009146 if (pt->IsJSProxy()) {
9147 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
9148 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
9149 receiver, index) != ABSENT;
9150 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009151 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
9152}
9153
9154
John Reck59135872010-11-02 12:39:01 -07009155MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01009156 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009157 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01009158 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01009159 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00009160 // Make sure that the top context does not change when doing
9161 // callbacks or interceptor calls.
9162 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01009163 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009164 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
9165 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01009166 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009167 if (!interceptor->setter()->IsUndefined()) {
9168 v8::IndexedPropertySetter setter =
9169 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +01009170 LOG(isolate,
9171 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
9172 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00009173 v8::AccessorInfo info(args.end());
9174 v8::Handle<v8::Value> result;
9175 {
9176 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01009177 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009178 result = setter(index, v8::Utils::ToLocal(value_handle), info);
9179 }
Steve Block44f0eee2011-05-26 01:26:41 +01009180 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009181 if (!result.IsEmpty()) return *value_handle;
9182 }
John Reck59135872010-11-02 12:39:01 -07009183 MaybeObject* raw_result =
Steve Block9fac8402011-05-12 15:51:54 +01009184 this_handle->SetElementWithoutInterceptor(index,
9185 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009186 strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01009187 check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01009188 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009189 return raw_result;
9190}
9191
9192
John Reck59135872010-11-02 12:39:01 -07009193MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
9194 Object* structure,
9195 uint32_t index,
9196 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01009197 Isolate* isolate = GetIsolate();
Ben Murdoch257744e2011-11-30 15:57:28 +00009198 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01009199
9200 // api style callbacks.
9201 if (structure->IsAccessorInfo()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00009202 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01009203 Object* fun_obj = data->getter();
9204 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Steve Block44f0eee2011-05-26 01:26:41 +01009205 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01009206 Handle<JSObject> self(JSObject::cast(receiver));
9207 Handle<JSObject> holder_handle(JSObject::cast(holder));
Steve Block44f0eee2011-05-26 01:26:41 +01009208 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009209 Handle<String> key = isolate->factory()->NumberToString(number);
Steve Block44f0eee2011-05-26 01:26:41 +01009210 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
9211 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01009212 v8::AccessorInfo info(args.end());
9213 v8::Handle<v8::Value> result;
9214 {
9215 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01009216 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01009217 result = call_fun(v8::Utils::ToLocal(key), info);
9218 }
Steve Block44f0eee2011-05-26 01:26:41 +01009219 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9220 if (result.IsEmpty()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01009221 return *v8::Utils::OpenHandle(*result);
9222 }
9223
9224 // __defineGetter__ callback
Ben Murdochc7cc0282012-03-05 14:35:55 +00009225 if (structure->IsAccessorPair()) {
9226 Object* getter = AccessorPair::cast(structure)->getter();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009227 if (getter->IsSpecFunction()) {
9228 // TODO(rossberg): nicer would be to cast to some JSCallable here...
9229 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
Leon Clarkef7060e22010-06-03 12:02:55 +01009230 }
9231 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +01009232 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01009233 }
9234
9235 UNREACHABLE();
9236 return NULL;
9237}
9238
9239
John Reck59135872010-11-02 12:39:01 -07009240MaybeObject* JSObject::SetElementWithCallback(Object* structure,
9241 uint32_t index,
9242 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009243 JSObject* holder,
9244 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01009245 Isolate* isolate = GetIsolate();
9246 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01009247
9248 // We should never get here to initialize a const with the hole
9249 // value since a const declaration would conflict with the setter.
9250 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01009251 Handle<Object> value_handle(value, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01009252
9253 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00009254 // data structure used to store the callbacks. Eventually foreign
Leon Clarkef7060e22010-06-03 12:02:55 +01009255 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00009256 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01009257
9258 if (structure->IsAccessorInfo()) {
9259 // api style callbacks
Ben Murdoch257744e2011-11-30 15:57:28 +00009260 Handle<JSObject> self(this);
9261 Handle<JSObject> holder_handle(JSObject::cast(holder));
9262 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01009263 Object* call_obj = data->setter();
9264 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
9265 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +01009266 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9267 Handle<String> key(isolate->factory()->NumberToString(number));
Ben Murdoch257744e2011-11-30 15:57:28 +00009268 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
9269 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01009270 v8::AccessorInfo info(args.end());
9271 {
9272 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01009273 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01009274 call_fun(v8::Utils::ToLocal(key),
9275 v8::Utils::ToLocal(value_handle),
9276 info);
9277 }
Steve Block44f0eee2011-05-26 01:26:41 +01009278 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01009279 return *value_handle;
9280 }
9281
Ben Murdochc7cc0282012-03-05 14:35:55 +00009282 if (structure->IsAccessorPair()) {
9283 Handle<Object> setter(AccessorPair::cast(structure)->setter());
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009284 if (setter->IsSpecFunction()) {
9285 // TODO(rossberg): nicer would be to cast to some JSCallable here...
9286 return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
Leon Clarkef7060e22010-06-03 12:02:55 +01009287 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009288 if (strict_mode == kNonStrictMode) {
9289 return value;
9290 }
Steve Block44f0eee2011-05-26 01:26:41 +01009291 Handle<Object> holder_handle(holder, isolate);
9292 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Leon Clarkef7060e22010-06-03 12:02:55 +01009293 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01009294 return isolate->Throw(
9295 *isolate->factory()->NewTypeError("no_setter_in_callback",
9296 HandleVector(args, 2)));
Leon Clarkef7060e22010-06-03 12:02:55 +01009297 }
9298 }
9299
9300 UNREACHABLE();
9301 return NULL;
9302}
9303
9304
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009305bool JSObject::HasFastArgumentsElements() {
9306 Heap* heap = GetHeap();
9307 if (!elements()->IsFixedArray()) return false;
9308 FixedArray* elements = FixedArray::cast(this->elements());
9309 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9310 return false;
9311 }
9312 FixedArray* arguments = FixedArray::cast(elements->get(1));
9313 return !arguments->IsDictionary();
9314}
9315
9316
9317bool JSObject::HasDictionaryArgumentsElements() {
9318 Heap* heap = GetHeap();
9319 if (!elements()->IsFixedArray()) return false;
9320 FixedArray* elements = FixedArray::cast(this->elements());
9321 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9322 return false;
9323 }
9324 FixedArray* arguments = FixedArray::cast(elements->get(1));
9325 return arguments->IsDictionary();
9326}
9327
9328
Steve Blocka7e24c12009-10-30 11:49:00 +00009329// Adding n elements in fast case is O(n*n).
9330// Note: revisit design to have dual undefined values to capture absent
9331// elements.
Steve Block9fac8402011-05-12 15:51:54 +01009332MaybeObject* JSObject::SetFastElement(uint32_t index,
9333 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009334 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01009335 bool check_prototype) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009336 ASSERT(HasFastTypeElements() ||
9337 HasFastArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009338
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009339 FixedArray* backing_store = FixedArray::cast(elements());
9340 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
9341 backing_store = FixedArray::cast(backing_store->get(1));
9342 } else {
9343 Object* writable;
9344 MaybeObject* maybe = EnsureWritableFastElements();
9345 if (!maybe->ToObject(&writable)) return maybe;
9346 backing_store = FixedArray::cast(writable);
John Reck59135872010-11-02 12:39:01 -07009347 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009348 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00009349
Steve Block9fac8402011-05-12 15:51:54 +01009350 if (check_prototype &&
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009351 (index >= capacity || backing_store->get(index)->IsTheHole())) {
Steve Block1e0659c2011-05-24 12:43:12 +01009352 bool found;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009353 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9354 value,
9355 &found,
9356 strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +01009357 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00009358 }
9359
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009360 uint32_t new_capacity = capacity;
9361 // Check if the length property of this object needs to be updated.
9362 uint32_t array_length = 0;
9363 bool must_update_array_length = false;
9364 if (IsJSArray()) {
9365 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9366 if (index >= array_length) {
9367 must_update_array_length = true;
9368 array_length = index + 1;
9369 }
9370 }
9371 // Check if the capacity of the backing store needs to be increased, or if
9372 // a transition to slow elements is necessary.
9373 if (index >= capacity) {
9374 bool convert_to_slow = true;
9375 if ((index - capacity) < kMaxGap) {
9376 new_capacity = NewElementsCapacity(index + 1);
9377 ASSERT(new_capacity > index);
9378 if (!ShouldConvertToSlowElements(new_capacity)) {
9379 convert_to_slow = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009380 }
9381 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009382 if (convert_to_slow) {
9383 MaybeObject* result = NormalizeElements();
9384 if (result->IsFailure()) return result;
9385 return SetDictionaryElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009386 }
9387 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009388 // Convert to fast double elements if appropriate.
9389 if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) {
9390 MaybeObject* maybe =
9391 SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
9392 if (maybe->IsFailure()) return maybe;
9393 FixedDoubleArray::cast(elements())->set(index, value->Number());
9394 return value;
9395 }
9396 // Change elements kind from SMI_ONLY to generic FAST if necessary.
9397 if (HasFastSmiOnlyElements() && !value->IsSmi()) {
9398 MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS);
9399 Map* new_map;
9400 if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
9401 set_map(new_map);
9402 if (FLAG_trace_elements_transitions) {
9403 PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
9404 FAST_ELEMENTS, elements());
9405 }
9406 }
9407 // Increase backing store capacity if that's been decided previously.
9408 if (new_capacity != capacity) {
9409 Object* new_elements;
9410 SetFastElementsCapacityMode set_capacity_mode =
9411 value->IsSmi() && HasFastSmiOnlyElements()
9412 ? kAllowSmiOnlyElements
9413 : kDontAllowSmiOnlyElements;
9414 MaybeObject* maybe =
9415 SetFastElementsCapacityAndLength(new_capacity,
9416 array_length,
9417 set_capacity_mode);
9418 if (!maybe->ToObject(&new_elements)) return maybe;
9419 FixedArray::cast(new_elements)->set(index, value);
9420 return value;
9421 }
9422 // Finally, set the new element and length.
9423 ASSERT(elements()->IsFixedArray());
9424 backing_store->set(index, value);
9425 if (must_update_array_length) {
9426 JSArray::cast(this)->set_length(Smi::FromInt(array_length));
9427 }
9428 return value;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009429}
9430
9431
9432MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
9433 Object* value,
9434 StrictModeFlag strict_mode,
9435 bool check_prototype) {
9436 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9437 Isolate* isolate = GetIsolate();
9438 Heap* heap = isolate->heap();
9439
9440 // Insert element in the dictionary.
9441 FixedArray* elements = FixedArray::cast(this->elements());
9442 bool is_arguments =
9443 (elements->map() == heap->non_strict_arguments_elements_map());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009444 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009445 if (is_arguments) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009446 dictionary = SeededNumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009447 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009448 dictionary = SeededNumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009449 }
9450
9451 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00009452 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009453 Object* element = dictionary->ValueAt(entry);
9454 PropertyDetails details = dictionary->DetailsAt(entry);
9455 if (details.type() == CALLBACKS) {
9456 return SetElementWithCallback(element, index, value, this, strict_mode);
9457 } else {
9458 dictionary->UpdateMaxNumberKey(index);
9459 // If put fails in strict mode, throw an exception.
9460 if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) {
9461 Handle<Object> holder(this);
9462 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9463 Handle<Object> args[2] = { number, holder };
9464 Handle<Object> error =
9465 isolate->factory()->NewTypeError("strict_read_only_property",
9466 HandleVector(args, 2));
9467 return isolate->Throw(*error);
9468 }
9469 }
9470 } else {
9471 // Index not already used. Look for an accessor in the prototype chain.
9472 if (check_prototype) {
9473 bool found;
9474 MaybeObject* result =
9475 SetElementWithCallbackSetterInPrototypes(
9476 index, value, &found, strict_mode);
9477 if (found) return result;
9478 }
9479 // When we set the is_extensible flag to false we always force the
9480 // element into dictionary mode (and force them to stay there).
9481 if (!map()->is_extensible()) {
9482 if (strict_mode == kNonStrictMode) {
9483 return isolate->heap()->undefined_value();
9484 } else {
9485 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9486 Handle<String> name = isolate->factory()->NumberToString(number);
9487 Handle<Object> args[1] = { name };
9488 Handle<Object> error =
9489 isolate->factory()->NewTypeError("object_not_extensible",
9490 HandleVector(args, 1));
9491 return isolate->Throw(*error);
9492 }
9493 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009494 FixedArrayBase* new_dictionary;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009495 MaybeObject* maybe = dictionary->AtNumberPut(index, value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009496 if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
Ben Murdochc7cc0282012-03-05 14:35:55 +00009497 if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009498 if (is_arguments) {
9499 elements->set(1, new_dictionary);
9500 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009501 set_elements(new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009502 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00009503 dictionary = SeededNumberDictionary::cast(new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009504 }
9505 }
9506
9507 // Update the array length if this JSObject is an array.
9508 if (IsJSArray()) {
9509 MaybeObject* result =
9510 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
9511 if (result->IsFailure()) return result;
9512 }
9513
9514 // Attempt to put this object back in fast case.
9515 if (ShouldConvertToFastElements()) {
9516 uint32_t new_length = 0;
9517 if (IsJSArray()) {
9518 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
9519 } else {
9520 new_length = dictionary->max_number_key() + 1;
9521 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00009522 SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays
9523 ? kAllowSmiOnlyElements
9524 : kDontAllowSmiOnlyElements;
9525 bool has_smi_only_elements = false;
9526 bool should_convert_to_fast_double_elements =
9527 ShouldConvertToFastDoubleElements(&has_smi_only_elements);
9528 if (has_smi_only_elements) {
9529 set_capacity_mode = kForceSmiOnlyElements;
9530 }
9531 MaybeObject* result = should_convert_to_fast_double_elements
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009532 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009533 : SetFastElementsCapacityAndLength(new_length,
9534 new_length,
Ben Murdochc7cc0282012-03-05 14:35:55 +00009535 set_capacity_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009536 if (result->IsFailure()) return result;
9537#ifdef DEBUG
9538 if (FLAG_trace_normalization) {
9539 PrintF("Object elements are fast case again:\n");
9540 Print();
9541 }
9542#endif
9543 }
9544 return value;
9545}
9546
9547
9548MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
9549 uint32_t index,
9550 Object* value,
9551 StrictModeFlag strict_mode,
9552 bool check_prototype) {
9553 ASSERT(HasFastDoubleElements());
9554
9555 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
9556 uint32_t elms_length = static_cast<uint32_t>(elms->length());
9557
9558 // If storing to an element that isn't in the array, pass the store request
9559 // up the prototype chain before storing in the receiver's elements.
9560 if (check_prototype &&
9561 (index >= elms_length || elms->is_the_hole(index))) {
9562 bool found;
9563 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9564 value,
9565 &found,
9566 strict_mode);
9567 if (found) return result;
9568 }
9569
9570 // If the value object is not a heap number, switch to fast elements and try
9571 // again.
9572 bool value_is_smi = value->IsSmi();
9573 if (!value->IsNumber()) {
9574 Object* obj;
9575 uint32_t length = elms_length;
9576 if (IsJSArray()) {
9577 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9578 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009579 MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
9580 elms_length,
9581 length,
9582 kDontAllowSmiOnlyElements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009583 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009584 return SetFastElement(index,
9585 value,
9586 strict_mode,
9587 check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009588 }
9589
9590 double double_value = value_is_smi
9591 ? static_cast<double>(Smi::cast(value)->value())
9592 : HeapNumber::cast(value)->value();
9593
9594 // Check whether there is extra space in the fixed array.
Steve Blocka7e24c12009-10-30 11:49:00 +00009595 if (index < elms_length) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009596 elms->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009597 if (IsJSArray()) {
9598 // Update the length of the array if needed.
9599 uint32_t array_length = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009600 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00009601 if (index >= array_length) {
Leon Clarke4515c472010-02-03 11:58:03 +00009602 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00009603 }
9604 }
9605 return value;
9606 }
9607
9608 // Allow gap in fast case.
9609 if ((index - elms_length) < kMaxGap) {
9610 // Try allocating extra space.
9611 int new_capacity = NewElementsCapacity(index+1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009612 if (!ShouldConvertToSlowElements(new_capacity)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009613 ASSERT(static_cast<uint32_t>(new_capacity) > index);
John Reck59135872010-11-02 12:39:01 -07009614 Object* obj;
9615 { MaybeObject* maybe_obj =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009616 SetFastDoubleElementsCapacityAndLength(new_capacity,
9617 index + 1);
John Reck59135872010-11-02 12:39:01 -07009618 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9619 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009620 FixedDoubleArray::cast(elements())->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009621 return value;
9622 }
9623 }
9624
9625 // Otherwise default to slow case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009626 ASSERT(HasFastDoubleElements());
9627 ASSERT(map()->has_fast_double_elements());
9628 ASSERT(elements()->IsFixedDoubleArray());
John Reck59135872010-11-02 12:39:01 -07009629 Object* obj;
9630 { MaybeObject* maybe_obj = NormalizeElements();
9631 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9632 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009633 ASSERT(HasDictionaryElements());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009634 return SetElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009635}
9636
Iain Merrick75681382010-08-19 15:07:18 +01009637
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009638MaybeObject* JSReceiver::SetElement(uint32_t index,
9639 Object* value,
9640 StrictModeFlag strict_mode,
9641 bool check_proto) {
9642 return IsJSProxy()
9643 ? JSProxy::cast(this)->SetElementWithHandler(index, value, strict_mode)
9644 : JSObject::cast(this)->SetElement(index, value, strict_mode, check_proto)
9645 ;
9646}
9647
9648
Ben Murdochc7cc0282012-03-05 14:35:55 +00009649Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
9650 uint32_t index,
9651 Handle<Object> value,
9652 StrictModeFlag strict_mode) {
9653 ASSERT(!object->HasExternalArrayElements());
9654 CALL_HEAP_FUNCTION(object->GetIsolate(),
9655 object->SetElement(index, *value, strict_mode, false),
9656 Object);
9657}
9658
9659
9660Handle<Object> JSObject::SetElement(Handle<JSObject> object,
9661 uint32_t index,
9662 Handle<Object> value,
9663 StrictModeFlag strict_mode) {
9664 if (object->HasExternalArrayElements()) {
9665 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
9666 bool has_exception;
9667 Handle<Object> number = Execution::ToNumber(value, &has_exception);
9668 if (has_exception) return Handle<Object>();
9669 value = number;
9670 }
9671 }
9672 CALL_HEAP_FUNCTION(object->GetIsolate(),
9673 object->SetElement(index, *value, strict_mode, true),
9674 Object);
9675}
9676
9677
Steve Block9fac8402011-05-12 15:51:54 +01009678MaybeObject* JSObject::SetElement(uint32_t index,
9679 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009680 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01009681 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009682 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009683 if (IsAccessCheckNeeded()) {
9684 Heap* heap = GetHeap();
9685 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009686 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01009687 Handle<Object> value_handle(value);
9688 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
9689 return *value_handle;
9690 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009691 }
9692
9693 if (IsJSGlobalProxy()) {
9694 Object* proto = GetPrototype();
9695 if (proto->IsNull()) return value;
9696 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009697 return JSObject::cast(proto)->SetElement(index,
9698 value,
9699 strict_mode,
9700 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009701 }
9702
9703 // Check for lookup interceptor
9704 if (HasIndexedInterceptor()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009705 return SetElementWithInterceptor(index,
9706 value,
9707 strict_mode,
9708 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009709 }
9710
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009711 return SetElementWithoutInterceptor(index,
9712 value,
9713 strict_mode,
9714 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009715}
9716
9717
John Reck59135872010-11-02 12:39:01 -07009718MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01009719 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009720 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01009721 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01009722 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00009723 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009724 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00009725 case FAST_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009726 return SetFastElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009727 case FAST_DOUBLE_ELEMENTS:
9728 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01009729 case EXTERNAL_PIXEL_ELEMENTS: {
9730 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009731 return pixels->SetValue(index, value);
9732 }
Steve Block3ce2e202009-11-05 08:53:23 +00009733 case EXTERNAL_BYTE_ELEMENTS: {
9734 ExternalByteArray* array = ExternalByteArray::cast(elements());
9735 return array->SetValue(index, value);
9736 }
9737 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9738 ExternalUnsignedByteArray* array =
9739 ExternalUnsignedByteArray::cast(elements());
9740 return array->SetValue(index, value);
9741 }
9742 case EXTERNAL_SHORT_ELEMENTS: {
9743 ExternalShortArray* array = ExternalShortArray::cast(elements());
9744 return array->SetValue(index, value);
9745 }
9746 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9747 ExternalUnsignedShortArray* array =
9748 ExternalUnsignedShortArray::cast(elements());
9749 return array->SetValue(index, value);
9750 }
9751 case EXTERNAL_INT_ELEMENTS: {
9752 ExternalIntArray* array = ExternalIntArray::cast(elements());
9753 return array->SetValue(index, value);
9754 }
9755 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9756 ExternalUnsignedIntArray* array =
9757 ExternalUnsignedIntArray::cast(elements());
9758 return array->SetValue(index, value);
9759 }
9760 case EXTERNAL_FLOAT_ELEMENTS: {
9761 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
9762 return array->SetValue(index, value);
9763 }
Ben Murdoch257744e2011-11-30 15:57:28 +00009764 case EXTERNAL_DOUBLE_ELEMENTS: {
9765 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
9766 return array->SetValue(index, value);
9767 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009768 case DICTIONARY_ELEMENTS:
9769 return SetDictionaryElement(index, value, strict_mode, check_prototype);
9770 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9771 FixedArray* parameter_map = FixedArray::cast(elements());
9772 uint32_t length = parameter_map->length();
9773 Object* probe =
9774 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
9775 if (probe != NULL && !probe->IsTheHole()) {
9776 Context* context = Context::cast(parameter_map->get(0));
9777 int context_index = Smi::cast(probe)->value();
9778 ASSERT(!context->get(context_index)->IsTheHole());
9779 context->set(context_index, value);
9780 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00009781 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009782 // Object is not mapped, defer to the arguments.
9783 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9784 if (arguments->IsDictionary()) {
9785 return SetDictionaryElement(index, value, strict_mode,
9786 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009787 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009788 return SetFastElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009789 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009790 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009791 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009792 }
9793 // All possible cases have been handled above. Add a return to avoid the
9794 // complaints from the compiler.
9795 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01009796 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009797}
9798
9799
Ben Murdochc7cc0282012-03-05 14:35:55 +00009800Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
9801 ElementsKind to_kind) {
9802 CALL_HEAP_FUNCTION(object->GetIsolate(),
9803 object->TransitionElementsKind(to_kind),
9804 Object);
9805}
9806
9807
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009808MUST_USE_RESULT MaybeObject* JSObject::TransitionElementsKind(
9809 ElementsKind to_kind) {
9810 ElementsKind from_kind = map()->elements_kind();
9811 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9812 uint32_t capacity = static_cast<uint32_t>(elms->length());
9813 uint32_t length = capacity;
Ben Murdochc7cc0282012-03-05 14:35:55 +00009814
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009815 if (IsJSArray()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009816 Object* raw_length = JSArray::cast(this)->length();
9817 if (raw_length->IsUndefined()) {
9818 // If length is undefined, then JSArray is being initialized and has no
9819 // elements, assume a length of zero.
9820 length = 0;
9821 } else {
9822 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009823 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00009824 }
9825
9826 if ((from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) ||
9827 (length == 0)) {
9828 MaybeObject* maybe_new_map = GetElementsTransitionMap(to_kind);
9829 Map* new_map;
9830 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9831 if (FLAG_trace_elements_transitions) {
9832 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
9833 }
9834 set_map(new_map);
9835 return this;
9836 }
9837
9838 if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9839 to_kind == FAST_DOUBLE_ELEMENTS) {
9840 MaybeObject* maybe_result =
9841 SetFastDoubleElementsCapacityAndLength(capacity, length);
9842 if (maybe_result->IsFailure()) return maybe_result;
9843 return this;
9844 }
9845
9846 if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009847 MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
9848 capacity, length, kDontAllowSmiOnlyElements);
9849 if (maybe_result->IsFailure()) return maybe_result;
9850 return this;
9851 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00009852
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009853 // This method should never be called for any other case than the ones
9854 // handled above.
9855 UNREACHABLE();
9856 return GetIsolate()->heap()->null_value();
9857}
9858
9859
9860// static
9861bool Map::IsValidElementsTransition(ElementsKind from_kind,
9862 ElementsKind to_kind) {
9863 return
9864 (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9865 (to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) ||
9866 (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS);
9867}
9868
9869
John Reck59135872010-11-02 12:39:01 -07009870MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
9871 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009872 uint32_t old_len = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009873 CHECK(length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +00009874 // Check to see if we need to update the length. For now, we make
9875 // sure that the length stays within 32-bits (unsigned).
9876 if (index >= old_len && index != 0xffffffff) {
John Reck59135872010-11-02 12:39:01 -07009877 Object* len;
9878 { MaybeObject* maybe_len =
Steve Block44f0eee2011-05-26 01:26:41 +01009879 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
John Reck59135872010-11-02 12:39:01 -07009880 if (!maybe_len->ToObject(&len)) return maybe_len;
9881 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009882 set_length(len);
9883 }
9884 return value;
9885}
9886
9887
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009888MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07009889 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01009890 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00009891 // Make sure that the top context does not change when doing
9892 // callbacks or interceptor calls.
9893 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01009894 HandleScope scope(isolate);
9895 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
9896 Handle<Object> this_handle(receiver, isolate);
9897 Handle<JSObject> holder_handle(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009898 if (!interceptor->getter()->IsUndefined()) {
9899 v8::IndexedPropertyGetter getter =
9900 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01009901 LOG(isolate,
9902 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
9903 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00009904 v8::AccessorInfo info(args.end());
9905 v8::Handle<v8::Value> result;
9906 {
9907 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01009908 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009909 result = getter(index, info);
9910 }
Steve Block44f0eee2011-05-26 01:26:41 +01009911 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009912 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
9913 }
9914
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009915 Heap* heap = holder_handle->GetHeap();
9916 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
9917 MaybeObject* raw_result = handler->Get(holder_handle->elements(),
9918 index,
9919 *holder_handle,
9920 *this_handle);
9921 if (raw_result != heap->the_hole_value()) return raw_result;
9922
Steve Block44f0eee2011-05-26 01:26:41 +01009923 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009924
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009925 Object* pt = holder_handle->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01009926 if (pt == heap->null_value()) return heap->undefined_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009927 return pt->GetElementWithReceiver(*this_handle, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00009928}
9929
9930
9931bool JSObject::HasDenseElements() {
9932 int capacity = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009933 int used = 0;
9934 GetElementsCapacityAndUsage(&capacity, &used);
9935 return (capacity == 0) || (used > (capacity / 2));
9936}
9937
9938
9939void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
9940 *capacity = 0;
9941 *used = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00009942
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009943 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
9944 FixedArray* backing_store = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00009945 switch (GetElementsKind()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009946 case NON_STRICT_ARGUMENTS_ELEMENTS:
9947 backing_store_base =
9948 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
9949 backing_store = FixedArray::cast(backing_store_base);
9950 if (backing_store->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009951 SeededNumberDictionary* dictionary =
9952 SeededNumberDictionary::cast(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009953 *capacity = dictionary->Capacity();
9954 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009955 break;
9956 }
9957 // Fall through.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009958 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009959 case FAST_ELEMENTS:
9960 backing_store = FixedArray::cast(backing_store_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009961 *capacity = backing_store->length();
9962 for (int i = 0; i < *capacity; ++i) {
9963 if (!backing_store->get(i)->IsTheHole()) ++(*used);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009964 }
9965 break;
9966 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009967 SeededNumberDictionary* dictionary =
9968 SeededNumberDictionary::cast(FixedArray::cast(elements()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009969 *capacity = dictionary->Capacity();
9970 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009971 break;
9972 }
9973 case FAST_DOUBLE_ELEMENTS: {
9974 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009975 *capacity = elms->length();
9976 for (int i = 0; i < *capacity; i++) {
9977 if (!elms->is_the_hole(i)) ++(*used);
Steve Blocka7e24c12009-10-30 11:49:00 +00009978 }
9979 break;
9980 }
Steve Block3ce2e202009-11-05 08:53:23 +00009981 case EXTERNAL_BYTE_ELEMENTS:
9982 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9983 case EXTERNAL_SHORT_ELEMENTS:
9984 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9985 case EXTERNAL_INT_ELEMENTS:
9986 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009987 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009988 case EXTERNAL_DOUBLE_ELEMENTS:
9989 case EXTERNAL_PIXEL_ELEMENTS:
9990 // External arrays are considered 100% used.
9991 ExternalArray* external_array = ExternalArray::cast(elements());
9992 *capacity = external_array->length();
9993 *used = external_array->length();
9994 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00009995 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009996}
9997
9998
9999bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010000 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
10001 kMaxUncheckedFastElementsLength);
10002 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
10003 (new_capacity <= kMaxUncheckedFastElementsLength &&
10004 GetHeap()->InNewSpace(this))) {
10005 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010006 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010007 // If the fast-case backing storage takes up roughly three times as
10008 // much space (in machine words) as a dictionary backing storage
10009 // would, the object should have slow elements.
10010 int old_capacity = 0;
10011 int used_elements = 0;
10012 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdochc7cc0282012-03-05 14:35:55 +000010013 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
10014 SeededNumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010015 return 3 * dictionary_size <= new_capacity;
Steve Blocka7e24c12009-10-30 11:49:00 +000010016}
10017
10018
10019bool JSObject::ShouldConvertToFastElements() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010020 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000010021 // If the elements are sparse, we should not go back to fast case.
10022 if (!HasDenseElements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000010023 // An object requiring access checks is never allowed to have fast
10024 // elements. If it had fast elements we would skip security checks.
10025 if (IsAccessCheckNeeded()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010026
10027 FixedArray* elements = FixedArray::cast(this->elements());
Ben Murdochc7cc0282012-03-05 14:35:55 +000010028 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010029 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010030 dictionary = SeededNumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010031 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010032 dictionary = SeededNumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010033 }
10034 // If an element has been added at a very high index in the elements
10035 // dictionary, we cannot go back to fast case.
10036 if (dictionary->requires_slow_elements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000010037 // If the dictionary backing storage takes up roughly half as much
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010038 // space (in machine words) as a fast-case backing storage would,
10039 // the object should have fast elements.
10040 uint32_t array_size = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000010041 if (IsJSArray()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010042 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000010043 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010044 array_size = dictionary->max_number_key();
Steve Blocka7e24c12009-10-30 11:49:00 +000010045 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010046 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
Ben Murdochc7cc0282012-03-05 14:35:55 +000010047 SeededNumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010048 return 2 * dictionary_size >= array_size;
Steve Blocka7e24c12009-10-30 11:49:00 +000010049}
10050
10051
Ben Murdochc7cc0282012-03-05 14:35:55 +000010052bool JSObject::ShouldConvertToFastDoubleElements(
10053 bool* has_smi_only_elements) {
10054 *has_smi_only_elements = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010055 if (FLAG_unbox_double_arrays) {
10056 ASSERT(HasDictionaryElements());
Ben Murdochc7cc0282012-03-05 14:35:55 +000010057 SeededNumberDictionary* dictionary =
10058 SeededNumberDictionary::cast(elements());
10059 bool found_double = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010060 for (int i = 0; i < dictionary->Capacity(); i++) {
10061 Object* key = dictionary->KeyAt(i);
10062 if (key->IsNumber()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010063 Object* value = dictionary->ValueAt(i);
10064 if (!value->IsNumber()) return false;
10065 if (!value->IsSmi()) {
10066 found_double = true;
10067 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010068 }
10069 }
Ben Murdochc7cc0282012-03-05 14:35:55 +000010070 *has_smi_only_elements = !found_double;
10071 return found_double;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010072 } else {
10073 return false;
10074 }
10075}
10076
10077
Steve Blocka7e24c12009-10-30 11:49:00 +000010078// Certain compilers request function template instantiation when they
10079// see the definition of the other template functions in the
10080// class. This requires us to have the template functions put
10081// together, so even though this function belongs in objects-debug.cc,
10082// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +010010083#ifdef OBJECT_PRINT
Steve Blocka7e24c12009-10-30 11:49:00 +000010084template<typename Shape, typename Key>
Ben Murdochb0fe1622011-05-05 13:52:32 +010010085void Dictionary<Shape, Key>::Print(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010086 int capacity = HashTable<Shape, Key>::Capacity();
10087 for (int i = 0; i < capacity; i++) {
10088 Object* k = HashTable<Shape, Key>::KeyAt(i);
10089 if (HashTable<Shape, Key>::IsKey(k)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010010090 PrintF(out, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +000010091 if (k->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010010092 String::cast(k)->StringPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +000010093 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +010010094 k->ShortPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +000010095 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010010096 PrintF(out, ": ");
10097 ValueAt(i)->ShortPrint(out);
10098 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +000010099 }
10100 }
10101}
10102#endif
10103
10104
10105template<typename Shape, typename Key>
10106void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
10107 int pos = 0;
10108 int capacity = HashTable<Shape, Key>::Capacity();
Leon Clarke4515c472010-02-03 11:58:03 +000010109 AssertNoAllocation no_gc;
10110 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +000010111 for (int i = 0; i < capacity; i++) {
10112 Object* k = Dictionary<Shape, Key>::KeyAt(i);
10113 if (Dictionary<Shape, Key>::IsKey(k)) {
10114 elements->set(pos++, ValueAt(i), mode);
10115 }
10116 }
10117 ASSERT(pos == elements->length());
10118}
10119
10120
10121InterceptorInfo* JSObject::GetNamedInterceptor() {
10122 ASSERT(map()->has_named_interceptor());
10123 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +010010124 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +000010125 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +010010126 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +000010127 return InterceptorInfo::cast(result);
10128}
10129
10130
10131InterceptorInfo* JSObject::GetIndexedInterceptor() {
10132 ASSERT(map()->has_indexed_interceptor());
10133 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +010010134 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +000010135 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +010010136 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +000010137 return InterceptorInfo::cast(result);
10138}
10139
10140
John Reck59135872010-11-02 12:39:01 -070010141MaybeObject* JSObject::GetPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010142 JSReceiver* receiver,
John Reck59135872010-11-02 12:39:01 -070010143 String* name,
10144 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010145 // Check local property in holder, ignore interceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010146 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000010147 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +000010148 if (result.IsProperty()) {
10149 return GetProperty(receiver, &result, name, attributes);
10150 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010151 // Continue searching via the prototype chain.
10152 Object* pt = GetPrototype();
10153 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010154 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010155 return pt->GetPropertyWithReceiver(receiver, name, attributes);
10156}
10157
10158
John Reck59135872010-11-02 12:39:01 -070010159MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010160 JSReceiver* receiver,
Steve Blockd0582a62009-12-15 09:54:21 +000010161 String* name,
10162 PropertyAttributes* attributes) {
10163 // Check local property in holder, ignore interceptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010164 LookupResult result(GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +000010165 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +000010166 if (result.IsProperty()) {
10167 return GetProperty(receiver, &result, name, attributes);
10168 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010010169 return GetHeap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +000010170}
10171
10172
John Reck59135872010-11-02 12:39:01 -070010173MaybeObject* JSObject::GetPropertyWithInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010174 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +000010175 String* name,
10176 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +010010177 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000010178 InterceptorInfo* interceptor = GetNamedInterceptor();
Steve Block44f0eee2011-05-26 01:26:41 +010010179 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010180 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +000010181 Handle<JSObject> holder_handle(this);
10182 Handle<String> name_handle(name);
10183
10184 if (!interceptor->getter()->IsUndefined()) {
10185 v8::NamedPropertyGetter getter =
10186 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +010010187 LOG(isolate,
10188 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
10189 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +000010190 v8::AccessorInfo info(args.end());
10191 v8::Handle<v8::Value> result;
10192 {
10193 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +010010194 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +000010195 result = getter(v8::Utils::ToLocal(name_handle), info);
10196 }
Steve Block44f0eee2011-05-26 01:26:41 +010010197 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010198 if (!result.IsEmpty()) {
10199 *attributes = NONE;
10200 return *v8::Utils::OpenHandle(*result);
10201 }
10202 }
10203
John Reck59135872010-11-02 12:39:01 -070010204 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +000010205 *receiver_handle,
10206 *name_handle,
10207 attributes);
Steve Block44f0eee2011-05-26 01:26:41 +010010208 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010209 return result;
10210}
10211
10212
10213bool JSObject::HasRealNamedProperty(String* key) {
10214 // Check access rights if needed.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010215 Isolate* isolate = GetIsolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +010010216 if (IsAccessCheckNeeded()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010217 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10218 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010219 return false;
10220 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010221 }
10222
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010223 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010224 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +000010225 return result.IsProperty() && (result.type() != INTERCEPTOR);
Steve Blocka7e24c12009-10-30 11:49:00 +000010226}
10227
10228
10229bool JSObject::HasRealElementProperty(uint32_t index) {
10230 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010231 if (IsAccessCheckNeeded()) {
10232 Heap* heap = GetHeap();
10233 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
10234 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10235 return false;
10236 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010237 }
10238
10239 // Handle [] on String objects.
10240 if (this->IsStringObjectWithCharacterAt(index)) return true;
10241
10242 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010243 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +000010244 case FAST_ELEMENTS: {
10245 uint32_t length = IsJSArray() ?
10246 static_cast<uint32_t>(
10247 Smi::cast(JSArray::cast(this)->length())->value()) :
10248 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10249 return (index < length) &&
10250 !FixedArray::cast(elements())->get(index)->IsTheHole();
10251 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010252 case FAST_DOUBLE_ELEMENTS: {
10253 uint32_t length = IsJSArray() ?
10254 static_cast<uint32_t>(
10255 Smi::cast(JSArray::cast(this)->length())->value()) :
10256 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
10257 return (index < length) &&
10258 !FixedDoubleArray::cast(elements())->is_the_hole(index);
10259 break;
10260 }
Steve Block44f0eee2011-05-26 01:26:41 +010010261 case EXTERNAL_PIXEL_ELEMENTS: {
10262 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +000010263 return index < static_cast<uint32_t>(pixels->length());
10264 }
Steve Block3ce2e202009-11-05 08:53:23 +000010265 case EXTERNAL_BYTE_ELEMENTS:
10266 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10267 case EXTERNAL_SHORT_ELEMENTS:
10268 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10269 case EXTERNAL_INT_ELEMENTS:
10270 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +000010271 case EXTERNAL_FLOAT_ELEMENTS:
10272 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +000010273 ExternalArray* array = ExternalArray::cast(elements());
10274 return index < static_cast<uint32_t>(array->length());
10275 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010276 case DICTIONARY_ELEMENTS: {
10277 return element_dictionary()->FindEntry(index)
Ben Murdochc7cc0282012-03-05 14:35:55 +000010278 != SeededNumberDictionary::kNotFound;
Steve Blocka7e24c12009-10-30 11:49:00 +000010279 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010280 case NON_STRICT_ARGUMENTS_ELEMENTS:
10281 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +000010282 break;
10283 }
10284 // All possibilities have been handled above already.
10285 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +010010286 return GetHeap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010287}
10288
10289
10290bool JSObject::HasRealNamedCallbackProperty(String* key) {
10291 // Check access rights if needed.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010292 Isolate* isolate = GetIsolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +010010293 if (IsAccessCheckNeeded()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010294 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10295 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010296 return false;
10297 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010298 }
10299
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010300 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010301 LocalLookupRealNamedProperty(key, &result);
Ben Murdochc7cc0282012-03-05 14:35:55 +000010302 return result.IsFound() && (result.type() == CALLBACKS);
Steve Blocka7e24c12009-10-30 11:49:00 +000010303}
10304
10305
10306int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
10307 if (HasFastProperties()) {
10308 DescriptorArray* descs = map()->instance_descriptors();
10309 int result = 0;
10310 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010311 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010312 if (details.IsProperty() && (details.attributes() & filter) == 0) {
10313 result++;
10314 }
10315 }
10316 return result;
10317 } else {
10318 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
10319 }
10320}
10321
10322
10323int JSObject::NumberOfEnumProperties() {
10324 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
10325}
10326
10327
10328void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
10329 Object* temp = get(i);
10330 set(i, get(j));
10331 set(j, temp);
10332 if (this != numbers) {
10333 temp = numbers->get(i);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010334 numbers->set(i, Smi::cast(numbers->get(j)));
10335 numbers->set(j, Smi::cast(temp));
Steve Blocka7e24c12009-10-30 11:49:00 +000010336 }
10337}
10338
10339
10340static void InsertionSortPairs(FixedArray* content,
10341 FixedArray* numbers,
10342 int len) {
10343 for (int i = 1; i < len; i++) {
10344 int j = i;
10345 while (j > 0 &&
10346 (NumberToUint32(numbers->get(j - 1)) >
10347 NumberToUint32(numbers->get(j)))) {
10348 content->SwapPairs(numbers, j - 1, j);
10349 j--;
10350 }
10351 }
10352}
10353
10354
10355void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
10356 // In-place heap sort.
10357 ASSERT(content->length() == numbers->length());
10358
10359 // Bottom-up max-heap construction.
10360 for (int i = 1; i < len; ++i) {
10361 int child_index = i;
10362 while (child_index > 0) {
10363 int parent_index = ((child_index + 1) >> 1) - 1;
10364 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10365 uint32_t child_value = NumberToUint32(numbers->get(child_index));
10366 if (parent_value < child_value) {
10367 content->SwapPairs(numbers, parent_index, child_index);
10368 } else {
10369 break;
10370 }
10371 child_index = parent_index;
10372 }
10373 }
10374
10375 // Extract elements and create sorted array.
10376 for (int i = len - 1; i > 0; --i) {
10377 // Put max element at the back of the array.
10378 content->SwapPairs(numbers, 0, i);
10379 // Sift down the new top element.
10380 int parent_index = 0;
10381 while (true) {
10382 int child_index = ((parent_index + 1) << 1) - 1;
10383 if (child_index >= i) break;
10384 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
10385 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
10386 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10387 if (child_index + 1 >= i || child1_value > child2_value) {
10388 if (parent_value > child1_value) break;
10389 content->SwapPairs(numbers, parent_index, child_index);
10390 parent_index = child_index;
10391 } else {
10392 if (parent_value > child2_value) break;
10393 content->SwapPairs(numbers, parent_index, child_index + 1);
10394 parent_index = child_index + 1;
10395 }
10396 }
10397 }
10398}
10399
10400
10401// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
10402void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
10403 ASSERT(this->length() == numbers->length());
10404 // For small arrays, simply use insertion sort.
10405 if (len <= 10) {
10406 InsertionSortPairs(this, numbers, len);
10407 return;
10408 }
10409 // Check the range of indices.
10410 uint32_t min_index = NumberToUint32(numbers->get(0));
10411 uint32_t max_index = min_index;
10412 uint32_t i;
10413 for (i = 1; i < len; i++) {
10414 if (NumberToUint32(numbers->get(i)) < min_index) {
10415 min_index = NumberToUint32(numbers->get(i));
10416 } else if (NumberToUint32(numbers->get(i)) > max_index) {
10417 max_index = NumberToUint32(numbers->get(i));
10418 }
10419 }
10420 if (max_index - min_index + 1 == len) {
10421 // Indices form a contiguous range, unless there are duplicates.
10422 // Do an in-place linear time sort assuming distinct numbers, but
10423 // avoid hanging in case they are not.
10424 for (i = 0; i < len; i++) {
10425 uint32_t p;
10426 uint32_t j = 0;
10427 // While the current element at i is not at its correct position p,
10428 // swap the elements at these two positions.
10429 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
10430 j++ < len) {
10431 SwapPairs(numbers, i, p);
10432 }
10433 }
10434 } else {
10435 HeapSortPairs(this, numbers, len);
10436 return;
10437 }
10438}
10439
10440
10441// Fill in the names of local properties into the supplied storage. The main
10442// purpose of this function is to provide reflection information for the object
10443// mirrors.
10444void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
10445 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
10446 if (HasFastProperties()) {
10447 DescriptorArray* descs = map()->instance_descriptors();
10448 for (int i = 0; i < descs->number_of_descriptors(); i++) {
10449 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
10450 }
10451 ASSERT(storage->length() >= index);
10452 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010453 property_dictionary()->CopyKeysTo(storage,
10454 index,
10455 StringDictionary::UNSORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000010456 }
10457}
10458
10459
10460int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
10461 return GetLocalElementKeys(NULL, filter);
10462}
10463
10464
10465int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +000010466 // Fast case for objects with no elements.
10467 if (!IsJSValue() && HasFastElements()) {
10468 uint32_t length = IsJSArray() ?
10469 static_cast<uint32_t>(
10470 Smi::cast(JSArray::cast(this)->length())->value()) :
10471 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10472 if (length == 0) return 0;
10473 }
10474 // Compute the number of enumerable elements.
Steve Blocka7e24c12009-10-30 11:49:00 +000010475 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
10476}
10477
10478
10479int JSObject::GetLocalElementKeys(FixedArray* storage,
10480 PropertyAttributes filter) {
10481 int counter = 0;
10482 switch (GetElementsKind()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010483 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +000010484 case FAST_ELEMENTS: {
10485 int length = IsJSArray() ?
10486 Smi::cast(JSArray::cast(this)->length())->value() :
10487 FixedArray::cast(elements())->length();
10488 for (int i = 0; i < length; i++) {
10489 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
10490 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000010491 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010492 }
10493 counter++;
10494 }
10495 }
10496 ASSERT(!storage || storage->length() >= counter);
10497 break;
10498 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010499 case FAST_DOUBLE_ELEMENTS: {
10500 int length = IsJSArray() ?
10501 Smi::cast(JSArray::cast(this)->length())->value() :
10502 FixedDoubleArray::cast(elements())->length();
10503 for (int i = 0; i < length; i++) {
10504 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
10505 if (storage != NULL) {
10506 storage->set(counter, Smi::FromInt(i));
10507 }
10508 counter++;
10509 }
10510 }
10511 ASSERT(!storage || storage->length() >= counter);
10512 break;
10513 }
Steve Block44f0eee2011-05-26 01:26:41 +010010514 case EXTERNAL_PIXEL_ELEMENTS: {
10515 int length = ExternalPixelArray::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000010516 while (counter < length) {
10517 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000010518 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +000010519 }
10520 counter++;
10521 }
10522 ASSERT(!storage || storage->length() >= counter);
10523 break;
10524 }
Steve Block3ce2e202009-11-05 08:53:23 +000010525 case EXTERNAL_BYTE_ELEMENTS:
10526 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10527 case EXTERNAL_SHORT_ELEMENTS:
10528 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10529 case EXTERNAL_INT_ELEMENTS:
10530 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +000010531 case EXTERNAL_FLOAT_ELEMENTS:
10532 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +000010533 int length = ExternalArray::cast(elements())->length();
10534 while (counter < length) {
10535 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000010536 storage->set(counter, Smi::FromInt(counter));
Steve Block3ce2e202009-11-05 08:53:23 +000010537 }
10538 counter++;
10539 }
10540 ASSERT(!storage || storage->length() >= counter);
10541 break;
10542 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010543 case DICTIONARY_ELEMENTS: {
10544 if (storage != NULL) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010545 element_dictionary()->CopyKeysTo(storage,
10546 filter,
Ben Murdochc7cc0282012-03-05 14:35:55 +000010547 SeededNumberDictionary::SORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000010548 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010549 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000010550 break;
10551 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010552 case NON_STRICT_ARGUMENTS_ELEMENTS: {
10553 FixedArray* parameter_map = FixedArray::cast(elements());
10554 int mapped_length = parameter_map->length() - 2;
10555 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
10556 if (arguments->IsDictionary()) {
10557 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
10558 // will insert in storage starting at index 0.
Ben Murdochc7cc0282012-03-05 14:35:55 +000010559 SeededNumberDictionary* dictionary =
10560 SeededNumberDictionary::cast(arguments);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010561 if (storage != NULL) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010562 dictionary->CopyKeysTo(
10563 storage, filter, SeededNumberDictionary::UNSORTED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010564 }
10565 counter += dictionary->NumberOfElementsFilterAttributes(filter);
10566 for (int i = 0; i < mapped_length; ++i) {
10567 if (!parameter_map->get(i + 2)->IsTheHole()) {
10568 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10569 ++counter;
10570 }
10571 }
10572 if (storage != NULL) storage->SortPairs(storage, counter);
10573
10574 } else {
10575 int backing_length = arguments->length();
10576 int i = 0;
10577 for (; i < mapped_length; ++i) {
10578 if (!parameter_map->get(i + 2)->IsTheHole()) {
10579 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10580 ++counter;
10581 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
10582 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10583 ++counter;
10584 }
10585 }
10586 for (; i < backing_length; ++i) {
10587 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10588 ++counter;
10589 }
10590 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010591 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010592 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010593 }
10594
10595 if (this->IsJSValue()) {
10596 Object* val = JSValue::cast(this)->value();
10597 if (val->IsString()) {
10598 String* str = String::cast(val);
10599 if (storage) {
10600 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000010601 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010602 }
10603 }
10604 counter += str->length();
10605 }
10606 }
10607 ASSERT(!storage || storage->length() == counter);
10608 return counter;
10609}
10610
10611
10612int JSObject::GetEnumElementKeys(FixedArray* storage) {
10613 return GetLocalElementKeys(storage,
10614 static_cast<PropertyAttributes>(DONT_ENUM));
10615}
10616
10617
Steve Blocka7e24c12009-10-30 11:49:00 +000010618// StringKey simply carries a string object as key.
10619class StringKey : public HashTableKey {
10620 public:
10621 explicit StringKey(String* string) :
10622 string_(string),
10623 hash_(HashForObject(string)) { }
10624
10625 bool IsMatch(Object* string) {
10626 // We know that all entries in a hash table had their hash keys created.
10627 // Use that knowledge to have fast failure.
10628 if (hash_ != HashForObject(string)) {
10629 return false;
10630 }
10631 return string_->Equals(String::cast(string));
10632 }
10633
10634 uint32_t Hash() { return hash_; }
10635
10636 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
10637
10638 Object* AsObject() { return string_; }
10639
10640 String* string_;
10641 uint32_t hash_;
10642};
10643
10644
10645// StringSharedKeys are used as keys in the eval cache.
10646class StringSharedKey : public HashTableKey {
10647 public:
Steve Block1e0659c2011-05-24 12:43:12 +010010648 StringSharedKey(String* source,
10649 SharedFunctionInfo* shared,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010650 LanguageMode language_mode,
10651 int scope_position)
Steve Block1e0659c2011-05-24 12:43:12 +010010652 : source_(source),
10653 shared_(shared),
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010654 language_mode_(language_mode),
10655 scope_position_(scope_position) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000010656
10657 bool IsMatch(Object* other) {
10658 if (!other->IsFixedArray()) return false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010659 FixedArray* other_array = FixedArray::cast(other);
10660 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
Steve Blocka7e24c12009-10-30 11:49:00 +000010661 if (shared != shared_) return false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010662 int language_unchecked = Smi::cast(other_array->get(2))->value();
10663 ASSERT(language_unchecked == CLASSIC_MODE ||
10664 language_unchecked == STRICT_MODE ||
10665 language_unchecked == EXTENDED_MODE);
10666 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10667 if (language_mode != language_mode_) return false;
10668 int scope_position = Smi::cast(other_array->get(3))->value();
10669 if (scope_position != scope_position_) return false;
10670 String* source = String::cast(other_array->get(1));
Steve Blocka7e24c12009-10-30 11:49:00 +000010671 return source->Equals(source_);
10672 }
10673
10674 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +010010675 SharedFunctionInfo* shared,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010676 LanguageMode language_mode,
10677 int scope_position) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010678 uint32_t hash = source->Hash();
10679 if (shared->HasSourceCode()) {
10680 // Instead of using the SharedFunctionInfo pointer in the hash
10681 // code computation, we use a combination of the hash of the
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010682 // script source code and the start position of the calling scope.
10683 // We do this to ensure that the cache entries can survive garbage
Steve Blocka7e24c12009-10-30 11:49:00 +000010684 // collection.
10685 Script* script = Script::cast(shared->script());
10686 hash ^= String::cast(script->source())->Hash();
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010687 if (language_mode == STRICT_MODE) hash ^= 0x8000;
10688 if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
10689 hash += scope_position;
Steve Blocka7e24c12009-10-30 11:49:00 +000010690 }
10691 return hash;
10692 }
10693
10694 uint32_t Hash() {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010695 return StringSharedHashHelper(
10696 source_, shared_, language_mode_, scope_position_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010697 }
10698
10699 uint32_t HashForObject(Object* obj) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010700 FixedArray* other_array = FixedArray::cast(obj);
10701 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10702 String* source = String::cast(other_array->get(1));
10703 int language_unchecked = Smi::cast(other_array->get(2))->value();
10704 ASSERT(language_unchecked == CLASSIC_MODE ||
10705 language_unchecked == STRICT_MODE ||
10706 language_unchecked == EXTENDED_MODE);
10707 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10708 int scope_position = Smi::cast(other_array->get(3))->value();
10709 return StringSharedHashHelper(
10710 source, shared, language_mode, scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000010711 }
10712
John Reck59135872010-11-02 12:39:01 -070010713 MUST_USE_RESULT MaybeObject* AsObject() {
10714 Object* obj;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010715 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(4);
John Reck59135872010-11-02 12:39:01 -070010716 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10717 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010718 FixedArray* other_array = FixedArray::cast(obj);
10719 other_array->set(0, shared_);
10720 other_array->set(1, source_);
10721 other_array->set(2, Smi::FromInt(language_mode_));
10722 other_array->set(3, Smi::FromInt(scope_position_));
10723 return other_array;
Steve Blocka7e24c12009-10-30 11:49:00 +000010724 }
10725
10726 private:
10727 String* source_;
10728 SharedFunctionInfo* shared_;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000010729 LanguageMode language_mode_;
10730 int scope_position_;
Steve Blocka7e24c12009-10-30 11:49:00 +000010731};
10732
10733
10734// RegExpKey carries the source and flags of a regular expression as key.
10735class RegExpKey : public HashTableKey {
10736 public:
10737 RegExpKey(String* string, JSRegExp::Flags flags)
10738 : string_(string),
10739 flags_(Smi::FromInt(flags.value())) { }
10740
Steve Block3ce2e202009-11-05 08:53:23 +000010741 // Rather than storing the key in the hash table, a pointer to the
10742 // stored value is stored where the key should be. IsMatch then
10743 // compares the search key to the found object, rather than comparing
10744 // a key to a key.
Steve Blocka7e24c12009-10-30 11:49:00 +000010745 bool IsMatch(Object* obj) {
10746 FixedArray* val = FixedArray::cast(obj);
10747 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
10748 && (flags_ == val->get(JSRegExp::kFlagsIndex));
10749 }
10750
10751 uint32_t Hash() { return RegExpHash(string_, flags_); }
10752
10753 Object* AsObject() {
10754 // Plain hash maps, which is where regexp keys are used, don't
10755 // use this function.
10756 UNREACHABLE();
10757 return NULL;
10758 }
10759
10760 uint32_t HashForObject(Object* obj) {
10761 FixedArray* val = FixedArray::cast(obj);
10762 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
10763 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
10764 }
10765
10766 static uint32_t RegExpHash(String* string, Smi* flags) {
10767 return string->Hash() + flags->value();
10768 }
10769
10770 String* string_;
10771 Smi* flags_;
10772};
10773
10774// Utf8SymbolKey carries a vector of chars as key.
10775class Utf8SymbolKey : public HashTableKey {
10776 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +000010777 explicit Utf8SymbolKey(Vector<const char> string, uint32_t seed)
10778 : string_(string), hash_field_(0), seed_(seed) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000010779
10780 bool IsMatch(Object* string) {
10781 return String::cast(string)->IsEqualTo(string_);
10782 }
10783
10784 uint32_t Hash() {
Steve Blockd0582a62009-12-15 09:54:21 +000010785 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +000010786 unibrow::Utf8InputBuffer<> buffer(string_.start(),
10787 static_cast<unsigned>(string_.length()));
10788 chars_ = buffer.Length();
Ben Murdochc7cc0282012-03-05 14:35:55 +000010789 hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
Steve Blockd0582a62009-12-15 09:54:21 +000010790 uint32_t result = hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +000010791 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10792 return result;
10793 }
10794
10795 uint32_t HashForObject(Object* other) {
10796 return String::cast(other)->Hash();
10797 }
10798
John Reck59135872010-11-02 12:39:01 -070010799 MaybeObject* AsObject() {
Steve Blockd0582a62009-12-15 09:54:21 +000010800 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +010010801 return Isolate::Current()->heap()->AllocateSymbol(
10802 string_, chars_, hash_field_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010803 }
10804
10805 Vector<const char> string_;
Steve Blockd0582a62009-12-15 09:54:21 +000010806 uint32_t hash_field_;
Steve Blocka7e24c12009-10-30 11:49:00 +000010807 int chars_; // Caches the number of characters when computing the hash code.
Ben Murdochc7cc0282012-03-05 14:35:55 +000010808 uint32_t seed_;
Steve Blocka7e24c12009-10-30 11:49:00 +000010809};
10810
10811
Steve Block9fac8402011-05-12 15:51:54 +010010812template <typename Char>
10813class SequentialSymbolKey : public HashTableKey {
10814 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +000010815 explicit SequentialSymbolKey(Vector<const Char> string, uint32_t seed)
10816 : string_(string), hash_field_(0), seed_(seed) { }
Steve Block9fac8402011-05-12 15:51:54 +010010817
10818 uint32_t Hash() {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010819 StringHasher hasher(string_.length(), seed_);
Steve Block9fac8402011-05-12 15:51:54 +010010820
10821 // Very long strings have a trivial hash that doesn't inspect the
10822 // string contents.
10823 if (hasher.has_trivial_hash()) {
10824 hash_field_ = hasher.GetHashField();
10825 } else {
10826 int i = 0;
10827 // Do the iterative array index computation as long as there is a
10828 // chance this is an array index.
10829 while (i < string_.length() && hasher.is_array_index()) {
10830 hasher.AddCharacter(static_cast<uc32>(string_[i]));
10831 i++;
10832 }
10833
10834 // Process the remaining characters without updating the array
10835 // index.
10836 while (i < string_.length()) {
10837 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
10838 i++;
10839 }
10840 hash_field_ = hasher.GetHashField();
10841 }
10842
10843 uint32_t result = hash_field_ >> String::kHashShift;
10844 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10845 return result;
10846 }
10847
10848
10849 uint32_t HashForObject(Object* other) {
10850 return String::cast(other)->Hash();
10851 }
10852
10853 Vector<const Char> string_;
10854 uint32_t hash_field_;
Ben Murdochc7cc0282012-03-05 14:35:55 +000010855 uint32_t seed_;
Steve Block9fac8402011-05-12 15:51:54 +010010856};
10857
10858
10859
10860class AsciiSymbolKey : public SequentialSymbolKey<char> {
10861 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +000010862 AsciiSymbolKey(Vector<const char> str, uint32_t seed)
10863 : SequentialSymbolKey<char>(str, seed) { }
Steve Block9fac8402011-05-12 15:51:54 +010010864
10865 bool IsMatch(Object* string) {
10866 return String::cast(string)->IsAsciiEqualTo(string_);
10867 }
10868
10869 MaybeObject* AsObject() {
10870 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +010010871 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +010010872 }
10873};
10874
10875
Ben Murdoch257744e2011-11-30 15:57:28 +000010876class SubStringAsciiSymbolKey : public HashTableKey {
10877 public:
10878 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
10879 int from,
Ben Murdochc7cc0282012-03-05 14:35:55 +000010880 int length,
10881 uint32_t seed)
10882 : string_(string), from_(from), length_(length), seed_(seed) { }
Ben Murdoch257744e2011-11-30 15:57:28 +000010883
10884 uint32_t Hash() {
10885 ASSERT(length_ >= 0);
10886 ASSERT(from_ + length_ <= string_->length());
Ben Murdochc7cc0282012-03-05 14:35:55 +000010887 StringHasher hasher(length_, string_->GetHeap()->HashSeed());
Ben Murdoch257744e2011-11-30 15:57:28 +000010888
10889 // Very long strings have a trivial hash that doesn't inspect the
10890 // string contents.
10891 if (hasher.has_trivial_hash()) {
10892 hash_field_ = hasher.GetHashField();
10893 } else {
10894 int i = 0;
10895 // Do the iterative array index computation as long as there is a
10896 // chance this is an array index.
10897 while (i < length_ && hasher.is_array_index()) {
10898 hasher.AddCharacter(static_cast<uc32>(
10899 string_->SeqAsciiStringGet(i + from_)));
10900 i++;
10901 }
10902
10903 // Process the remaining characters without updating the array
10904 // index.
10905 while (i < length_) {
10906 hasher.AddCharacterNoIndex(static_cast<uc32>(
10907 string_->SeqAsciiStringGet(i + from_)));
10908 i++;
10909 }
10910 hash_field_ = hasher.GetHashField();
10911 }
10912
10913 uint32_t result = hash_field_ >> String::kHashShift;
10914 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10915 return result;
10916 }
10917
10918
10919 uint32_t HashForObject(Object* other) {
10920 return String::cast(other)->Hash();
10921 }
10922
10923 bool IsMatch(Object* string) {
10924 Vector<const char> chars(string_->GetChars() + from_, length_);
10925 return String::cast(string)->IsAsciiEqualTo(chars);
10926 }
10927
10928 MaybeObject* AsObject() {
10929 if (hash_field_ == 0) Hash();
10930 Vector<const char> chars(string_->GetChars() + from_, length_);
10931 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
10932 }
10933
10934 private:
10935 Handle<SeqAsciiString> string_;
10936 int from_;
10937 int length_;
10938 uint32_t hash_field_;
Ben Murdochc7cc0282012-03-05 14:35:55 +000010939 uint32_t seed_;
Ben Murdoch257744e2011-11-30 15:57:28 +000010940};
10941
10942
Steve Block9fac8402011-05-12 15:51:54 +010010943class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
10944 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +000010945 explicit TwoByteSymbolKey(Vector<const uc16> str, uint32_t seed)
10946 : SequentialSymbolKey<uc16>(str, seed) { }
Steve Block9fac8402011-05-12 15:51:54 +010010947
10948 bool IsMatch(Object* string) {
10949 return String::cast(string)->IsTwoByteEqualTo(string_);
10950 }
10951
10952 MaybeObject* AsObject() {
10953 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +010010954 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +010010955 }
10956};
10957
10958
Steve Blocka7e24c12009-10-30 11:49:00 +000010959// SymbolKey carries a string/symbol object as key.
10960class SymbolKey : public HashTableKey {
10961 public:
Steve Block44f0eee2011-05-26 01:26:41 +010010962 explicit SymbolKey(String* string)
10963 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000010964
10965 bool IsMatch(Object* string) {
10966 return String::cast(string)->Equals(string_);
10967 }
10968
10969 uint32_t Hash() { return string_->Hash(); }
10970
10971 uint32_t HashForObject(Object* other) {
10972 return String::cast(other)->Hash();
10973 }
10974
John Reck59135872010-11-02 12:39:01 -070010975 MaybeObject* AsObject() {
Leon Clarkef7060e22010-06-03 12:02:55 +010010976 // Attempt to flatten the string, so that symbols will most often
10977 // be flat strings.
10978 string_ = string_->TryFlattenGetString();
Steve Block44f0eee2011-05-26 01:26:41 +010010979 Heap* heap = string_->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010980 // Transform string to symbol if possible.
Steve Block44f0eee2011-05-26 01:26:41 +010010981 Map* map = heap->SymbolMapForString(string_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010982 if (map != NULL) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010983 string_->set_map_no_write_barrier(map);
Steve Blocka7e24c12009-10-30 11:49:00 +000010984 ASSERT(string_->IsSymbol());
10985 return string_;
10986 }
10987 // Otherwise allocate a new symbol.
10988 StringInputBuffer buffer(string_);
Steve Block44f0eee2011-05-26 01:26:41 +010010989 return heap->AllocateInternalSymbol(&buffer,
Steve Blocka7e24c12009-10-30 11:49:00 +000010990 string_->length(),
Steve Blockd0582a62009-12-15 09:54:21 +000010991 string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +000010992 }
10993
10994 static uint32_t StringHash(Object* obj) {
10995 return String::cast(obj)->Hash();
10996 }
10997
10998 String* string_;
10999};
11000
11001
11002template<typename Shape, typename Key>
11003void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
11004 IteratePointers(v, 0, kElementsStartOffset);
11005}
11006
11007
11008template<typename Shape, typename Key>
11009void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
11010 IteratePointers(v,
11011 kElementsStartOffset,
11012 kHeaderSize + length() * kPointerSize);
11013}
11014
11015
11016template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011017MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
11018 PretenureFlag pretenure) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011019 int capacity = ComputeCapacity(at_least_space_for);
11020 if (capacity > HashTable::kMaxCapacity) {
Leon Clarkee46be812010-01-19 14:06:41 +000011021 return Failure::OutOfMemoryException();
11022 }
11023
John Reck59135872010-11-02 12:39:01 -070011024 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +010011025 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
11026 AllocateHashTable(EntryToIndex(capacity), pretenure);
John Reck59135872010-11-02 12:39:01 -070011027 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000011028 }
John Reck59135872010-11-02 12:39:01 -070011029 HashTable::cast(obj)->SetNumberOfElements(0);
11030 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
11031 HashTable::cast(obj)->SetCapacity(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000011032 return obj;
11033}
11034
11035
Leon Clarkee46be812010-01-19 14:06:41 +000011036// Find entry for key otherwise return kNotFound.
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011037int StringDictionary::FindEntry(String* key) {
11038 if (!key->IsSymbol()) {
11039 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
11040 }
11041
11042 // Optimized for symbol key. Knowledge of the key type allows:
11043 // 1. Move the check if the key is a symbol out of the loop.
Ben Murdochc7cc0282012-03-05 14:35:55 +000011044 // 2. Avoid comparing hash codes in symbol to symbol comparison.
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011045 // 3. Detect a case when a dictionary key is not a symbol but the key is.
11046 // In case of positive result the dictionary key may be replaced by
11047 // the symbol with minimal performance penalty. It gives a chance to
11048 // perform further lookups in code stubs (and significant performance boost
11049 // a certain style of code).
11050
11051 // EnsureCapacity will guarantee the hash table is never full.
11052 uint32_t capacity = Capacity();
11053 uint32_t entry = FirstProbe(key->Hash(), capacity);
11054 uint32_t count = 1;
11055
11056 while (true) {
11057 int index = EntryToIndex(entry);
11058 Object* element = get(index);
11059 if (element->IsUndefined()) break; // Empty entry.
11060 if (key == element) return entry;
11061 if (!element->IsSymbol() &&
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011062 !element->IsTheHole() &&
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011063 String::cast(element)->Equals(key)) {
11064 // Replace a non-symbol key by the equivalent symbol for faster further
11065 // lookups.
11066 set(index, key);
11067 return entry;
11068 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011069 ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key));
Ben Murdoch3bec4d22010-07-22 14:51:16 +010011070 entry = NextProbe(entry, count++, capacity);
11071 }
11072 return kNotFound;
11073}
11074
11075
Steve Blocka7e24c12009-10-30 11:49:00 +000011076template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011077MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
11078 ASSERT(NumberOfElements() < new_table->Capacity());
11079
11080 AssertNoAllocation no_gc;
11081 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
11082
11083 // Copy prefix to new array.
11084 for (int i = kPrefixStartIndex;
11085 i < kPrefixStartIndex + Shape::kPrefixSize;
11086 i++) {
11087 new_table->set(i, get(i), mode);
11088 }
11089
11090 // Rehash the elements.
11091 int capacity = Capacity();
11092 for (int i = 0; i < capacity; i++) {
11093 uint32_t from_index = EntryToIndex(i);
11094 Object* k = get(from_index);
11095 if (IsKey(k)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000011096 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011097 uint32_t insertion_index =
11098 EntryToIndex(new_table->FindInsertionEntry(hash));
11099 for (int j = 0; j < Shape::kEntrySize; j++) {
11100 new_table->set(insertion_index + j, get(from_index + j), mode);
11101 }
11102 }
11103 }
11104 new_table->SetNumberOfElements(NumberOfElements());
11105 new_table->SetNumberOfDeletedElements(0);
11106 return new_table;
11107}
11108
11109
11110template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011111MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011112 int capacity = Capacity();
11113 int nof = NumberOfElements() + n;
Leon Clarkee46be812010-01-19 14:06:41 +000011114 int nod = NumberOfDeletedElements();
11115 // Return if:
11116 // 50% is still free after adding n elements and
11117 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +010011118 if (nod <= (capacity - nof) >> 1) {
11119 int needed_free = nof >> 1;
11120 if (nof + needed_free <= capacity) return this;
11121 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011122
Steve Block6ded16b2010-05-10 14:33:55 +010011123 const int kMinCapacityForPretenure = 256;
11124 bool pretenure =
Ben Murdoch8b112d22011-06-08 16:22:53 +010011125 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
John Reck59135872010-11-02 12:39:01 -070011126 Object* obj;
11127 { MaybeObject* maybe_obj =
11128 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
11129 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11130 }
Leon Clarke4515c472010-02-03 11:58:03 +000011131
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011132 return Rehash(HashTable::cast(obj), key);
11133}
Steve Blocka7e24c12009-10-30 11:49:00 +000011134
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011135
11136template<typename Shape, typename Key>
11137MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
11138 int capacity = Capacity();
11139 int nof = NumberOfElements();
11140
11141 // Shrink to fit the number of elements if only a quarter of the
11142 // capacity is filled with elements.
11143 if (nof > (capacity >> 2)) return this;
11144 // Allocate a new dictionary with room for at least the current
11145 // number of elements. The allocation method will make sure that
11146 // there is extra room in the dictionary for additions. Don't go
11147 // lower than room for 16 elements.
11148 int at_least_room_for = nof;
11149 if (at_least_room_for < 16) return this;
11150
11151 const int kMinCapacityForPretenure = 256;
11152 bool pretenure =
11153 (at_least_room_for > kMinCapacityForPretenure) &&
11154 !GetHeap()->InNewSpace(this);
11155 Object* obj;
11156 { MaybeObject* maybe_obj =
11157 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
11158 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000011159 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011160
11161 return Rehash(HashTable::cast(obj), key);
Steve Blocka7e24c12009-10-30 11:49:00 +000011162}
11163
11164
11165template<typename Shape, typename Key>
11166uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
11167 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +000011168 uint32_t entry = FirstProbe(hash, capacity);
11169 uint32_t count = 1;
11170 // EnsureCapacity will guarantee the hash table is never full.
11171 while (true) {
11172 Object* element = KeyAt(entry);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011173 if (element->IsUndefined() || element->IsTheHole()) break;
Leon Clarkee46be812010-01-19 14:06:41 +000011174 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000011175 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011176 return entry;
11177}
11178
11179// Force instantiation of template instances class.
11180// Please note this list is compiler dependent.
11181
11182template class HashTable<SymbolTableShape, HashTableKey*>;
11183
11184template class HashTable<CompilationCacheShape, HashTableKey*>;
11185
11186template class HashTable<MapCacheShape, HashTableKey*>;
11187
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011188template class HashTable<ObjectHashTableShape<1>, Object*>;
11189
11190template class HashTable<ObjectHashTableShape<2>, Object*>;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011191
Steve Blocka7e24c12009-10-30 11:49:00 +000011192template class Dictionary<StringDictionaryShape, String*>;
11193
Ben Murdochc7cc0282012-03-05 14:35:55 +000011194template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
Steve Blocka7e24c12009-10-30 11:49:00 +000011195
Ben Murdochc7cc0282012-03-05 14:35:55 +000011196template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
11197
11198template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11199 Allocate(int at_least_space_for);
11200
11201template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11202 Allocate(int at_least_space_for);
Steve Blocka7e24c12009-10-30 11:49:00 +000011203
John Reck59135872010-11-02 12:39:01 -070011204template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +000011205 int);
11206
Ben Murdochc7cc0282012-03-05 14:35:55 +000011207template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
Steve Blocka7e24c12009-10-30 11:49:00 +000011208 uint32_t, Object*);
11209
Ben Murdochc7cc0282012-03-05 14:35:55 +000011210template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11211 AtPut(uint32_t, Object*);
11212
11213template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11214 SlowReverseLookup(Object* value);
11215
11216template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11217 SlowReverseLookup(Object* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000011218
11219template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
11220 Object*);
11221
Ben Murdochc7cc0282012-03-05 14:35:55 +000011222template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011223 FixedArray*,
11224 PropertyAttributes,
Ben Murdochc7cc0282012-03-05 14:35:55 +000011225 Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000011226
11227template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
11228 int, JSObject::DeleteMode);
11229
Ben Murdochc7cc0282012-03-05 14:35:55 +000011230template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11231 DeleteProperty(int, JSObject::DeleteMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000011232
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011233template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
11234 String*);
11235
Ben Murdochc7cc0282012-03-05 14:35:55 +000011236template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011237 uint32_t);
11238
Steve Blocka7e24c12009-10-30 11:49:00 +000011239template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011240 FixedArray*,
11241 int,
11242 Dictionary<StringDictionaryShape, String*>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000011243
11244template int
11245Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
11246 PropertyAttributes);
11247
John Reck59135872010-11-02 12:39:01 -070011248template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000011249 String*, Object*, PropertyDetails);
11250
John Reck59135872010-11-02 12:39:01 -070011251template MaybeObject*
Steve Blocka7e24c12009-10-30 11:49:00 +000011252Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
11253
11254template int
Ben Murdochc7cc0282012-03-05 14:35:55 +000011255Dictionary<SeededNumberDictionaryShape, uint32_t>::
11256 NumberOfElementsFilterAttributes(PropertyAttributes);
Steve Blocka7e24c12009-10-30 11:49:00 +000011257
Ben Murdochc7cc0282012-03-05 14:35:55 +000011258template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000011259 uint32_t, Object*, PropertyDetails);
11260
Ben Murdochc7cc0282012-03-05 14:35:55 +000011261template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
11262 uint32_t, Object*, PropertyDetails);
11263
11264template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11265 EnsureCapacity(int, uint32_t);
11266
11267template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
John Reck59135872010-11-02 12:39:01 -070011268 EnsureCapacity(int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000011269
John Reck59135872010-11-02 12:39:01 -070011270template MaybeObject* Dictionary<StringDictionaryShape, String*>::
11271 EnsureCapacity(int, String*);
Steve Blocka7e24c12009-10-30 11:49:00 +000011272
Ben Murdochc7cc0282012-03-05 14:35:55 +000011273template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11274 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
11275
11276template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11277 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000011278
John Reck59135872010-11-02 12:39:01 -070011279template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +000011280 String*, Object*, PropertyDetails, uint32_t);
11281
11282template
Ben Murdochc7cc0282012-03-05 14:35:55 +000011283int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000011284
11285template
11286int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
11287
Leon Clarkee46be812010-01-19 14:06:41 +000011288template
Ben Murdochc7cc0282012-03-05 14:35:55 +000011289int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
Leon Clarkee46be812010-01-19 14:06:41 +000011290
11291
Steve Blocka7e24c12009-10-30 11:49:00 +000011292// Collates undefined and unexisting elements below limit from position
11293// zero of the elements. The object stays in Dictionary mode.
John Reck59135872010-11-02 12:39:01 -070011294MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011295 ASSERT(HasDictionaryElements());
11296 // Must stay in dictionary mode, either because of requires_slow_elements,
11297 // or because we are not going to sort (and therefore compact) all of the
11298 // elements.
Ben Murdochc7cc0282012-03-05 14:35:55 +000011299 SeededNumberDictionary* dict = element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +000011300 HeapNumber* result_double = NULL;
11301 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11302 // Allocate space for result before we start mutating the object.
John Reck59135872010-11-02 12:39:01 -070011303 Object* new_double;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011304 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070011305 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11306 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011307 result_double = HeapNumber::cast(new_double);
11308 }
11309
John Reck59135872010-11-02 12:39:01 -070011310 Object* obj;
11311 { MaybeObject* maybe_obj =
Ben Murdochc7cc0282012-03-05 14:35:55 +000011312 SeededNumberDictionary::Allocate(dict->NumberOfElements());
John Reck59135872010-11-02 12:39:01 -070011313 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11314 }
Ben Murdochc7cc0282012-03-05 14:35:55 +000011315 SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +000011316
11317 AssertNoAllocation no_alloc;
11318
11319 uint32_t pos = 0;
11320 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010011321 int capacity = dict->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000011322 for (int i = 0; i < capacity; i++) {
11323 Object* k = dict->KeyAt(i);
11324 if (dict->IsKey(k)) {
11325 ASSERT(k->IsNumber());
11326 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
11327 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
11328 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
11329 Object* value = dict->ValueAt(i);
11330 PropertyDetails details = dict->DetailsAt(i);
11331 if (details.type() == CALLBACKS) {
11332 // Bail out and do the sorting of undefineds and array holes in JS.
11333 return Smi::FromInt(-1);
11334 }
11335 uint32_t key = NumberToUint32(k);
John Reck59135872010-11-02 12:39:01 -070011336 // In the following we assert that adding the entry to the new dictionary
11337 // does not cause GC. This is the case because we made sure to allocate
11338 // the dictionary big enough above, so it need not grow.
Steve Blocka7e24c12009-10-30 11:49:00 +000011339 if (key < limit) {
11340 if (value->IsUndefined()) {
11341 undefs++;
11342 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010011343 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11344 // Adding an entry with the key beyond smi-range requires
11345 // allocation. Bailout.
11346 return Smi::FromInt(-1);
11347 }
John Reck59135872010-11-02 12:39:01 -070011348 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000011349 pos++;
11350 }
11351 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010011352 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
11353 // Adding an entry with the key beyond smi-range requires
11354 // allocation. Bailout.
11355 return Smi::FromInt(-1);
11356 }
John Reck59135872010-11-02 12:39:01 -070011357 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000011358 }
11359 }
11360 }
11361
11362 uint32_t result = pos;
11363 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011364 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000011365 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010011366 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11367 // Adding an entry with the key beyond smi-range requires
11368 // allocation. Bailout.
11369 return Smi::FromInt(-1);
11370 }
Steve Block44f0eee2011-05-26 01:26:41 +010011371 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
John Reck59135872010-11-02 12:39:01 -070011372 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000011373 pos++;
11374 undefs--;
11375 }
11376
11377 set_elements(new_dict);
11378
11379 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11380 return Smi::FromInt(static_cast<int>(result));
11381 }
11382
11383 ASSERT_NE(NULL, result_double);
11384 result_double->set_value(static_cast<double>(result));
11385 return result_double;
11386}
11387
11388
11389// Collects all defined (non-hole) and non-undefined (array) elements at
11390// the start of the elements array.
11391// If the object is in dictionary mode, it is converted to fast elements
11392// mode.
John Reck59135872010-11-02 12:39:01 -070011393MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011394 Heap* heap = GetHeap();
11395
Steve Blocka7e24c12009-10-30 11:49:00 +000011396 if (HasDictionaryElements()) {
11397 // Convert to fast elements containing only the existing properties.
11398 // Ordering is irrelevant, since we are going to sort anyway.
Ben Murdochc7cc0282012-03-05 14:35:55 +000011399 SeededNumberDictionary* dict = element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +000011400 if (IsJSArray() || dict->requires_slow_elements() ||
11401 dict->max_number_key() >= limit) {
11402 return PrepareSlowElementsForSort(limit);
11403 }
11404 // Convert to fast elements.
11405
John Reck59135872010-11-02 12:39:01 -070011406 Object* obj;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011407 { MaybeObject* maybe_obj = GetElementsTransitionMap(FAST_ELEMENTS);
John Reck59135872010-11-02 12:39:01 -070011408 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11409 }
Steve Block8defd9f2010-07-08 12:39:36 +010011410 Map* new_map = Map::cast(obj);
11411
Steve Block44f0eee2011-05-26 01:26:41 +010011412 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
John Reck59135872010-11-02 12:39:01 -070011413 Object* new_array;
11414 { MaybeObject* maybe_new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010011415 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
John Reck59135872010-11-02 12:39:01 -070011416 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
11417 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011418 FixedArray* fast_elements = FixedArray::cast(new_array);
11419 dict->CopyValuesTo(fast_elements);
Steve Block8defd9f2010-07-08 12:39:36 +010011420
11421 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +000011422 set_elements(fast_elements);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011423 } else if (HasExternalArrayElements()) {
11424 // External arrays cannot have holes or undefined elements.
11425 return Smi::FromInt(ExternalArray::cast(elements())->length());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011426 } else if (!HasFastDoubleElements()) {
John Reck59135872010-11-02 12:39:01 -070011427 Object* obj;
11428 { MaybeObject* maybe_obj = EnsureWritableFastElements();
11429 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11430 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011431 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011432 ASSERT(HasFastTypeElements() || HasFastDoubleElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000011433
11434 // Collect holes at the end, undefined before that and the rest at the
11435 // start, and return the number of non-hole, non-undefined values.
11436
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011437 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
11438 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000011439 if (limit > elements_length) {
11440 limit = elements_length ;
11441 }
11442 if (limit == 0) {
11443 return Smi::FromInt(0);
11444 }
11445
11446 HeapNumber* result_double = NULL;
11447 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11448 // Pessimistically allocate space for return value before
11449 // we start mutating the array.
John Reck59135872010-11-02 12:39:01 -070011450 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +010011451 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070011452 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11453 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011454 result_double = HeapNumber::cast(new_double);
11455 }
11456
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011457 uint32_t result = 0;
11458 if (elements_base->map() == heap->fixed_double_array_map()) {
11459 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
11460 // Split elements into defined and the_hole, in that order.
11461 unsigned int holes = limit;
11462 // Assume most arrays contain no holes and undefined values, so minimize the
11463 // number of stores of non-undefined, non-the-hole values.
11464 for (unsigned int i = 0; i < holes; i++) {
11465 if (elements->is_the_hole(i)) {
11466 holes--;
11467 } else {
11468 continue;
11469 }
11470 // Position i needs to be filled.
11471 while (holes > i) {
11472 if (elements->is_the_hole(holes)) {
11473 holes--;
11474 } else {
11475 elements->set(i, elements->get_scalar(holes));
11476 break;
11477 }
11478 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011479 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011480 result = holes;
11481 while (holes < limit) {
11482 elements->set_the_hole(holes);
11483 holes++;
11484 }
11485 } else {
11486 FixedArray* elements = FixedArray::cast(elements_base);
11487 AssertNoAllocation no_alloc;
11488
11489 // Split elements into defined, undefined and the_hole, in that order. Only
11490 // count locations for undefined and the hole, and fill them afterwards.
11491 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
11492 unsigned int undefs = limit;
11493 unsigned int holes = limit;
11494 // Assume most arrays contain no holes and undefined values, so minimize the
11495 // number of stores of non-undefined, non-the-hole values.
11496 for (unsigned int i = 0; i < undefs; i++) {
11497 Object* current = elements->get(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000011498 if (current->IsTheHole()) {
11499 holes--;
11500 undefs--;
11501 } else if (current->IsUndefined()) {
11502 undefs--;
11503 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011504 continue;
11505 }
11506 // Position i needs to be filled.
11507 while (undefs > i) {
11508 current = elements->get(undefs);
11509 if (current->IsTheHole()) {
11510 holes--;
11511 undefs--;
11512 } else if (current->IsUndefined()) {
11513 undefs--;
11514 } else {
11515 elements->set(i, current, write_barrier);
11516 break;
11517 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011518 }
11519 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011520 result = undefs;
11521 while (undefs < holes) {
11522 elements->set_undefined(undefs);
11523 undefs++;
11524 }
11525 while (holes < limit) {
11526 elements->set_the_hole(holes);
11527 holes++;
11528 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011529 }
11530
11531 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11532 return Smi::FromInt(static_cast<int>(result));
11533 }
11534 ASSERT_NE(NULL, result_double);
11535 result_double->set_value(static_cast<double>(result));
11536 return result_double;
11537}
11538
11539
Steve Block44f0eee2011-05-26 01:26:41 +010011540Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011541 uint8_t clamped_value = 0;
11542 if (index < static_cast<uint32_t>(length())) {
11543 if (value->IsSmi()) {
11544 int int_value = Smi::cast(value)->value();
11545 if (int_value < 0) {
11546 clamped_value = 0;
11547 } else if (int_value > 255) {
11548 clamped_value = 255;
11549 } else {
11550 clamped_value = static_cast<uint8_t>(int_value);
11551 }
11552 } else if (value->IsHeapNumber()) {
11553 double double_value = HeapNumber::cast(value)->value();
11554 if (!(double_value > 0)) {
11555 // NaN and less than zero clamp to zero.
11556 clamped_value = 0;
11557 } else if (double_value > 255) {
11558 // Greater than 255 clamp to 255.
11559 clamped_value = 255;
11560 } else {
11561 // Other doubles are rounded to the nearest integer.
11562 clamped_value = static_cast<uint8_t>(double_value + 0.5);
11563 }
11564 } else {
11565 // Clamp undefined to zero (default). All other types have been
11566 // converted to a number type further up in the call chain.
11567 ASSERT(value->IsUndefined());
11568 }
11569 set(index, clamped_value);
11570 }
11571 return Smi::FromInt(clamped_value);
11572}
11573
11574
Steve Block3ce2e202009-11-05 08:53:23 +000011575template<typename ExternalArrayClass, typename ValueType>
Steve Block44f0eee2011-05-26 01:26:41 +010011576static MaybeObject* ExternalArrayIntSetter(Heap* heap,
11577 ExternalArrayClass* receiver,
John Reck59135872010-11-02 12:39:01 -070011578 uint32_t index,
11579 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011580 ValueType cast_value = 0;
11581 if (index < static_cast<uint32_t>(receiver->length())) {
11582 if (value->IsSmi()) {
11583 int int_value = Smi::cast(value)->value();
11584 cast_value = static_cast<ValueType>(int_value);
11585 } else if (value->IsHeapNumber()) {
11586 double double_value = HeapNumber::cast(value)->value();
11587 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
11588 } else {
11589 // Clamp undefined to zero (default). All other types have been
11590 // converted to a number type further up in the call chain.
11591 ASSERT(value->IsUndefined());
11592 }
11593 receiver->set(index, cast_value);
11594 }
Steve Block44f0eee2011-05-26 01:26:41 +010011595 return heap->NumberFromInt32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000011596}
11597
11598
John Reck59135872010-11-02 12:39:01 -070011599MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011600 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011601 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011602}
11603
11604
John Reck59135872010-11-02 12:39:01 -070011605MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
11606 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011607 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011608 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011609}
11610
11611
John Reck59135872010-11-02 12:39:01 -070011612MaybeObject* ExternalShortArray::SetValue(uint32_t index,
11613 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011614 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011615 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011616}
11617
11618
John Reck59135872010-11-02 12:39:01 -070011619MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
11620 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011621 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011622 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011623}
11624
11625
John Reck59135872010-11-02 12:39:01 -070011626MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011627 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011628 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011629}
11630
11631
John Reck59135872010-11-02 12:39:01 -070011632MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011633 uint32_t cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010011634 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000011635 if (index < static_cast<uint32_t>(length())) {
11636 if (value->IsSmi()) {
11637 int int_value = Smi::cast(value)->value();
11638 cast_value = static_cast<uint32_t>(int_value);
11639 } else if (value->IsHeapNumber()) {
11640 double double_value = HeapNumber::cast(value)->value();
11641 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
11642 } else {
11643 // Clamp undefined to zero (default). All other types have been
11644 // converted to a number type further up in the call chain.
11645 ASSERT(value->IsUndefined());
11646 }
11647 set(index, cast_value);
11648 }
Steve Block44f0eee2011-05-26 01:26:41 +010011649 return heap->NumberFromUint32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000011650}
11651
11652
John Reck59135872010-11-02 12:39:01 -070011653MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011654 float cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010011655 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000011656 if (index < static_cast<uint32_t>(length())) {
11657 if (value->IsSmi()) {
11658 int int_value = Smi::cast(value)->value();
11659 cast_value = static_cast<float>(int_value);
11660 } else if (value->IsHeapNumber()) {
11661 double double_value = HeapNumber::cast(value)->value();
11662 cast_value = static_cast<float>(double_value);
11663 } else {
11664 // Clamp undefined to zero (default). All other types have been
11665 // converted to a number type further up in the call chain.
11666 ASSERT(value->IsUndefined());
11667 }
11668 set(index, cast_value);
11669 }
Steve Block44f0eee2011-05-26 01:26:41 +010011670 return heap->AllocateHeapNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000011671}
11672
11673
Ben Murdoch257744e2011-11-30 15:57:28 +000011674MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
11675 double double_value = 0;
11676 Heap* heap = GetHeap();
11677 if (index < static_cast<uint32_t>(length())) {
11678 if (value->IsSmi()) {
11679 int int_value = Smi::cast(value)->value();
11680 double_value = static_cast<double>(int_value);
11681 } else if (value->IsHeapNumber()) {
11682 double_value = HeapNumber::cast(value)->value();
11683 } else {
11684 // Clamp undefined to zero (default). All other types have been
11685 // converted to a number type further up in the call chain.
11686 ASSERT(value->IsUndefined());
11687 }
11688 set(index, double_value);
11689 }
11690 return heap->AllocateHeapNumber(double_value);
11691}
11692
11693
Ben Murdochb0fe1622011-05-05 13:52:32 +010011694JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011695 ASSERT(!HasFastProperties());
11696 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011697 return JSGlobalPropertyCell::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000011698}
11699
11700
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011701Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
11702 Handle<GlobalObject> global,
11703 Handle<String> name) {
11704 Isolate* isolate = global->GetIsolate();
11705 CALL_HEAP_FUNCTION(isolate,
11706 global->EnsurePropertyCell(*name),
11707 JSGlobalPropertyCell);
11708}
11709
11710
John Reck59135872010-11-02 12:39:01 -070011711MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011712 ASSERT(!HasFastProperties());
11713 int entry = property_dictionary()->FindEntry(name);
11714 if (entry == StringDictionary::kNotFound) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011715 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -070011716 Object* cell;
11717 { MaybeObject* maybe_cell =
Steve Block44f0eee2011-05-26 01:26:41 +010011718 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
John Reck59135872010-11-02 12:39:01 -070011719 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
11720 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011721 PropertyDetails details(NONE, NORMAL);
11722 details = details.AsDeleted();
John Reck59135872010-11-02 12:39:01 -070011723 Object* dictionary;
11724 { MaybeObject* maybe_dictionary =
11725 property_dictionary()->Add(name, cell, details);
11726 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
11727 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011728 set_properties(StringDictionary::cast(dictionary));
11729 return cell;
11730 } else {
11731 Object* value = property_dictionary()->ValueAt(entry);
11732 ASSERT(value->IsJSGlobalPropertyCell());
11733 return value;
11734 }
11735}
11736
11737
John Reck59135872010-11-02 12:39:01 -070011738MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011739 SymbolKey key(string);
11740 return LookupKey(&key, s);
11741}
11742
11743
Steve Blockd0582a62009-12-15 09:54:21 +000011744// This class is used for looking up two character strings in the symbol table.
11745// If we don't have a hit we don't want to waste much time so we unroll the
11746// string hash calculation loop here for speed. Doesn't work if the two
11747// characters form a decimal integer, since such strings have a different hash
11748// algorithm.
11749class TwoCharHashTableKey : public HashTableKey {
11750 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +000011751 TwoCharHashTableKey(uint32_t c1, uint32_t c2, uint32_t seed)
Steve Blockd0582a62009-12-15 09:54:21 +000011752 : c1_(c1), c2_(c2) {
11753 // Char 1.
Ben Murdochc7cc0282012-03-05 14:35:55 +000011754 uint32_t hash = seed;
11755 hash += c1;
11756 hash += hash << 10;
Steve Blockd0582a62009-12-15 09:54:21 +000011757 hash ^= hash >> 6;
11758 // Char 2.
11759 hash += c2;
11760 hash += hash << 10;
11761 hash ^= hash >> 6;
11762 // GetHash.
11763 hash += hash << 3;
11764 hash ^= hash >> 11;
11765 hash += hash << 15;
Ben Murdochc7cc0282012-03-05 14:35:55 +000011766 if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash;
Steve Blockd0582a62009-12-15 09:54:21 +000011767#ifdef DEBUG
Ben Murdochc7cc0282012-03-05 14:35:55 +000011768 StringHasher hasher(2, seed);
Steve Blockd0582a62009-12-15 09:54:21 +000011769 hasher.AddCharacter(c1);
11770 hasher.AddCharacter(c2);
11771 // If this assert fails then we failed to reproduce the two-character
11772 // version of the string hashing algorithm above. One reason could be
11773 // that we were passed two digits as characters, since the hash
11774 // algorithm is different in that case.
11775 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
11776#endif
11777 hash_ = hash;
11778 }
11779
11780 bool IsMatch(Object* o) {
11781 if (!o->IsString()) return false;
11782 String* other = String::cast(o);
11783 if (other->length() != 2) return false;
11784 if (other->Get(0) != c1_) return false;
11785 return other->Get(1) == c2_;
11786 }
11787
11788 uint32_t Hash() { return hash_; }
11789 uint32_t HashForObject(Object* key) {
11790 if (!key->IsString()) return 0;
11791 return String::cast(key)->Hash();
11792 }
11793
11794 Object* AsObject() {
11795 // The TwoCharHashTableKey is only used for looking in the symbol
11796 // table, not for adding to it.
11797 UNREACHABLE();
11798 return NULL;
11799 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011800
Steve Blockd0582a62009-12-15 09:54:21 +000011801 private:
11802 uint32_t c1_;
11803 uint32_t c2_;
11804 uint32_t hash_;
11805};
11806
11807
Steve Blocka7e24c12009-10-30 11:49:00 +000011808bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
11809 SymbolKey key(string);
11810 int entry = FindEntry(&key);
11811 if (entry == kNotFound) {
11812 return false;
11813 } else {
11814 String* result = String::cast(KeyAt(entry));
11815 ASSERT(StringShape(result).IsSymbol());
11816 *symbol = result;
11817 return true;
11818 }
11819}
11820
11821
Steve Blockd0582a62009-12-15 09:54:21 +000011822bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
11823 uint32_t c2,
11824 String** symbol) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000011825 TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
Steve Blockd0582a62009-12-15 09:54:21 +000011826 int entry = FindEntry(&key);
11827 if (entry == kNotFound) {
11828 return false;
11829 } else {
11830 String* result = String::cast(KeyAt(entry));
11831 ASSERT(StringShape(result).IsSymbol());
11832 *symbol = result;
11833 return true;
11834 }
11835}
11836
11837
Ben Murdochc7cc0282012-03-05 14:35:55 +000011838MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str,
11839 Object** s) {
11840 Utf8SymbolKey key(str, GetHeap()->HashSeed());
Steve Blocka7e24c12009-10-30 11:49:00 +000011841 return LookupKey(&key, s);
11842}
11843
11844
Steve Block9fac8402011-05-12 15:51:54 +010011845MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
11846 Object** s) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000011847 AsciiSymbolKey key(str, GetHeap()->HashSeed());
Steve Block9fac8402011-05-12 15:51:54 +010011848 return LookupKey(&key, s);
11849}
11850
11851
Ben Murdoch257744e2011-11-30 15:57:28 +000011852MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
11853 int from,
11854 int length,
11855 Object** s) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000011856 SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
Ben Murdoch257744e2011-11-30 15:57:28 +000011857 return LookupKey(&key, s);
11858}
11859
11860
Steve Block9fac8402011-05-12 15:51:54 +010011861MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
11862 Object** s) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000011863 TwoByteSymbolKey key(str, GetHeap()->HashSeed());
Steve Block9fac8402011-05-12 15:51:54 +010011864 return LookupKey(&key, s);
11865}
11866
John Reck59135872010-11-02 12:39:01 -070011867MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011868 int entry = FindEntry(key);
11869
11870 // Symbol already in table.
11871 if (entry != kNotFound) {
11872 *s = KeyAt(entry);
11873 return this;
11874 }
11875
11876 // Adding new symbol. Grow table if needed.
John Reck59135872010-11-02 12:39:01 -070011877 Object* obj;
11878 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11879 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11880 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011881
11882 // Create symbol object.
John Reck59135872010-11-02 12:39:01 -070011883 Object* symbol;
11884 { MaybeObject* maybe_symbol = key->AsObject();
11885 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
11886 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011887
11888 // If the symbol table grew as part of EnsureCapacity, obj is not
11889 // the current symbol table and therefore we cannot use
11890 // SymbolTable::cast here.
11891 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
11892
11893 // Add the new symbol and return it along with the symbol table.
11894 entry = table->FindInsertionEntry(key->Hash());
11895 table->set(EntryToIndex(entry), symbol);
11896 table->ElementAdded();
11897 *s = symbol;
11898 return table;
11899}
11900
11901
11902Object* CompilationCacheTable::Lookup(String* src) {
11903 StringKey key(src);
11904 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011905 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011906 return get(EntryToIndex(entry) + 1);
11907}
11908
11909
Steve Block1e0659c2011-05-24 12:43:12 +010011910Object* CompilationCacheTable::LookupEval(String* src,
11911 Context* context,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011912 LanguageMode language_mode,
11913 int scope_position) {
11914 StringSharedKey key(src,
11915 context->closure()->shared(),
11916 language_mode,
11917 scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000011918 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +010011919 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011920 return get(EntryToIndex(entry) + 1);
11921}
11922
11923
11924Object* CompilationCacheTable::LookupRegExp(String* src,
11925 JSRegExp::Flags flags) {
11926 RegExpKey key(src, flags);
11927 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011928 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011929 return get(EntryToIndex(entry) + 1);
11930}
11931
11932
John Reck59135872010-11-02 12:39:01 -070011933MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011934 StringKey key(src);
John Reck59135872010-11-02 12:39:01 -070011935 Object* obj;
11936 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11937 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11938 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011939
11940 CompilationCacheTable* cache =
11941 reinterpret_cast<CompilationCacheTable*>(obj);
11942 int entry = cache->FindInsertionEntry(key.Hash());
11943 cache->set(EntryToIndex(entry), src);
11944 cache->set(EntryToIndex(entry) + 1, value);
11945 cache->ElementAdded();
11946 return cache;
11947}
11948
11949
John Reck59135872010-11-02 12:39:01 -070011950MaybeObject* CompilationCacheTable::PutEval(String* src,
11951 Context* context,
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011952 SharedFunctionInfo* value,
11953 int scope_position) {
Steve Block1e0659c2011-05-24 12:43:12 +010011954 StringSharedKey key(src,
11955 context->closure()->shared(),
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011956 value->language_mode(),
11957 scope_position);
John Reck59135872010-11-02 12:39:01 -070011958 Object* obj;
11959 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11960 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11961 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011962
11963 CompilationCacheTable* cache =
11964 reinterpret_cast<CompilationCacheTable*>(obj);
11965 int entry = cache->FindInsertionEntry(key.Hash());
11966
John Reck59135872010-11-02 12:39:01 -070011967 Object* k;
11968 { MaybeObject* maybe_k = key.AsObject();
11969 if (!maybe_k->ToObject(&k)) return maybe_k;
11970 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011971
11972 cache->set(EntryToIndex(entry), k);
11973 cache->set(EntryToIndex(entry) + 1, value);
11974 cache->ElementAdded();
11975 return cache;
11976}
11977
11978
John Reck59135872010-11-02 12:39:01 -070011979MaybeObject* CompilationCacheTable::PutRegExp(String* src,
11980 JSRegExp::Flags flags,
11981 FixedArray* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011982 RegExpKey key(src, flags);
John Reck59135872010-11-02 12:39:01 -070011983 Object* obj;
11984 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11985 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11986 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011987
11988 CompilationCacheTable* cache =
11989 reinterpret_cast<CompilationCacheTable*>(obj);
11990 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000011991 // We store the value in the key slot, and compare the search key
11992 // to the stored value with a custon IsMatch function during lookups.
Steve Blocka7e24c12009-10-30 11:49:00 +000011993 cache->set(EntryToIndex(entry), value);
11994 cache->set(EntryToIndex(entry) + 1, value);
11995 cache->ElementAdded();
11996 return cache;
11997}
11998
11999
Ben Murdochb0fe1622011-05-05 13:52:32 +010012000void CompilationCacheTable::Remove(Object* value) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012001 Object* the_hole_value = GetHeap()->the_hole_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010012002 for (int entry = 0, size = Capacity(); entry < size; entry++) {
12003 int entry_index = EntryToIndex(entry);
12004 int value_index = entry_index + 1;
12005 if (get(value_index) == value) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012006 NoWriteBarrierSet(this, entry_index, the_hole_value);
12007 NoWriteBarrierSet(this, value_index, the_hole_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010012008 ElementRemoved();
12009 }
12010 }
12011 return;
12012}
12013
12014
Steve Blocka7e24c12009-10-30 11:49:00 +000012015// SymbolsKey used for HashTable where key is array of symbols.
12016class SymbolsKey : public HashTableKey {
12017 public:
12018 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
12019
12020 bool IsMatch(Object* symbols) {
12021 FixedArray* o = FixedArray::cast(symbols);
12022 int len = symbols_->length();
12023 if (o->length() != len) return false;
12024 for (int i = 0; i < len; i++) {
12025 if (o->get(i) != symbols_->get(i)) return false;
12026 }
12027 return true;
12028 }
12029
12030 uint32_t Hash() { return HashForObject(symbols_); }
12031
12032 uint32_t HashForObject(Object* obj) {
12033 FixedArray* symbols = FixedArray::cast(obj);
12034 int len = symbols->length();
12035 uint32_t hash = 0;
12036 for (int i = 0; i < len; i++) {
12037 hash ^= String::cast(symbols->get(i))->Hash();
12038 }
12039 return hash;
12040 }
12041
12042 Object* AsObject() { return symbols_; }
12043
12044 private:
12045 FixedArray* symbols_;
12046};
12047
12048
12049Object* MapCache::Lookup(FixedArray* array) {
12050 SymbolsKey key(array);
12051 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010012052 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012053 return get(EntryToIndex(entry) + 1);
12054}
12055
12056
John Reck59135872010-11-02 12:39:01 -070012057MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012058 SymbolsKey key(array);
John Reck59135872010-11-02 12:39:01 -070012059 Object* obj;
12060 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
12061 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12062 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012063
12064 MapCache* cache = reinterpret_cast<MapCache*>(obj);
12065 int entry = cache->FindInsertionEntry(key.Hash());
12066 cache->set(EntryToIndex(entry), array);
12067 cache->set(EntryToIndex(entry) + 1, value);
12068 cache->ElementAdded();
12069 return cache;
12070}
12071
12072
12073template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070012074MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
12075 Object* obj;
12076 { MaybeObject* maybe_obj =
12077 HashTable<Shape, Key>::Allocate(at_least_space_for);
12078 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000012079 }
John Reck59135872010-11-02 12:39:01 -070012080 // Initialize the next enumeration index.
12081 Dictionary<Shape, Key>::cast(obj)->
12082 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
Steve Blocka7e24c12009-10-30 11:49:00 +000012083 return obj;
12084}
12085
12086
12087template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070012088MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Steve Block44f0eee2011-05-26 01:26:41 +010012089 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000012090 int length = HashTable<Shape, Key>::NumberOfElements();
12091
12092 // Allocate and initialize iteration order array.
John Reck59135872010-11-02 12:39:01 -070012093 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +010012094 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070012095 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12096 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012097 FixedArray* iteration_order = FixedArray::cast(obj);
12098 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000012099 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000012100 }
12101
12102 // Allocate array with enumeration order.
Steve Block44f0eee2011-05-26 01:26:41 +010012103 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070012104 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12105 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012106 FixedArray* enumeration_order = FixedArray::cast(obj);
12107
12108 // Fill the enumeration order array with property details.
12109 int capacity = HashTable<Shape, Key>::Capacity();
12110 int pos = 0;
12111 for (int i = 0; i < capacity; i++) {
12112 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
Leon Clarke4515c472010-02-03 11:58:03 +000012113 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000012114 }
12115 }
12116
12117 // Sort the arrays wrt. enumeration order.
12118 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
12119
12120 // Overwrite the enumeration_order with the enumeration indices.
12121 for (int i = 0; i < length; i++) {
12122 int index = Smi::cast(iteration_order->get(i))->value();
12123 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +000012124 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +000012125 }
12126
12127 // Update the dictionary with new indices.
12128 capacity = HashTable<Shape, Key>::Capacity();
12129 pos = 0;
12130 for (int i = 0; i < capacity; i++) {
12131 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
12132 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
12133 PropertyDetails details = DetailsAt(i);
12134 PropertyDetails new_details =
12135 PropertyDetails(details.attributes(), details.type(), enum_index);
12136 DetailsAtPut(i, new_details);
12137 }
12138 }
12139
12140 // Set the next enumeration index.
12141 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
12142 return this;
12143}
12144
12145template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070012146MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012147 // Check whether there are enough enumeration indices to add n elements.
12148 if (Shape::kIsEnumerable &&
12149 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
12150 // If not, we generate new indices for the properties.
John Reck59135872010-11-02 12:39:01 -070012151 Object* result;
12152 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12153 if (!maybe_result->ToObject(&result)) return maybe_result;
12154 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012155 }
12156 return HashTable<Shape, Key>::EnsureCapacity(n, key);
12157}
12158
12159
Steve Blocka7e24c12009-10-30 11:49:00 +000012160template<typename Shape, typename Key>
12161Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012162 JSReceiver::DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +010012163 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000012164 PropertyDetails details = DetailsAt(entry);
12165 // Ignore attributes if forcing a deletion.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012166 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
Steve Block44f0eee2011-05-26 01:26:41 +010012167 return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012168 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012169 SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012170 HashTable<Shape, Key>::ElementRemoved();
Steve Block44f0eee2011-05-26 01:26:41 +010012171 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012172}
12173
12174
12175template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012176MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
12177 return HashTable<Shape, Key>::Shrink(key);
12178}
12179
12180
12181template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070012182MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012183 int entry = this->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000012184
12185 // If the entry is present set the value;
12186 if (entry != Dictionary<Shape, Key>::kNotFound) {
12187 ValueAtPut(entry, value);
12188 return this;
12189 }
12190
12191 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070012192 Object* obj;
12193 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12194 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12195 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012196
John Reck59135872010-11-02 12:39:01 -070012197 Object* k;
12198 { MaybeObject* maybe_k = Shape::AsObject(key);
12199 if (!maybe_k->ToObject(&k)) return maybe_k;
12200 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012201 PropertyDetails details = PropertyDetails(NONE, NORMAL);
Ben Murdochc7cc0282012-03-05 14:35:55 +000012202
12203 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12204 Dictionary<Shape, Key>::Hash(key));
Steve Blocka7e24c12009-10-30 11:49:00 +000012205}
12206
12207
12208template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070012209MaybeObject* Dictionary<Shape, Key>::Add(Key key,
12210 Object* value,
12211 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012212 // Valdate key is absent.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012213 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000012214 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070012215 Object* obj;
12216 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12217 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12218 }
Ben Murdochc7cc0282012-03-05 14:35:55 +000012219
12220 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12221 Dictionary<Shape, Key>::Hash(key));
Steve Blocka7e24c12009-10-30 11:49:00 +000012222}
12223
12224
12225// Add a key, value pair to the dictionary.
12226template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070012227MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
12228 Object* value,
12229 PropertyDetails details,
12230 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012231 // Compute the key object.
John Reck59135872010-11-02 12:39:01 -070012232 Object* k;
12233 { MaybeObject* maybe_k = Shape::AsObject(key);
12234 if (!maybe_k->ToObject(&k)) return maybe_k;
12235 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012236
12237 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
12238 // Insert element at empty or deleted entry
12239 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
12240 // Assign an enumeration index to the property and update
12241 // SetNextEnumerationIndex.
12242 int index = NextEnumerationIndex();
12243 details = PropertyDetails(details.attributes(), details.type(), index);
12244 SetNextEnumerationIndex(index + 1);
12245 }
12246 SetEntry(entry, k, value, details);
12247 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
12248 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
12249 HashTable<Shape, Key>::ElementAdded();
12250 return this;
12251}
12252
12253
Ben Murdochc7cc0282012-03-05 14:35:55 +000012254void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012255 // If the dictionary requires slow elements an element has already
12256 // been added at a high index.
12257 if (requires_slow_elements()) return;
12258 // Check if this index is high enough that we should require slow
12259 // elements.
12260 if (key > kRequiresSlowElementsLimit) {
12261 set_requires_slow_elements();
12262 return;
12263 }
12264 // Update max key value.
12265 Object* max_index_object = get(kMaxNumberKeyIndex);
12266 if (!max_index_object->IsSmi() || max_number_key() < key) {
12267 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000012268 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000012269 }
12270}
12271
12272
Ben Murdochc7cc0282012-03-05 14:35:55 +000012273MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
12274 Object* value,
12275 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012276 UpdateMaxNumberKey(key);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012277 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +000012278 return Add(key, value, details);
12279}
12280
12281
Ben Murdochc7cc0282012-03-05 14:35:55 +000012282MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
12283 Object* value) {
12284 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
12285 return Add(key, value, PropertyDetails(NONE, NORMAL));
12286}
12287
12288
12289MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012290 UpdateMaxNumberKey(key);
12291 return AtPut(key, value);
12292}
12293
12294
Ben Murdochc7cc0282012-03-05 14:35:55 +000012295MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
12296 Object* value) {
12297 return AtPut(key, value);
12298}
12299
12300
12301Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
12302 Handle<SeededNumberDictionary> dictionary,
12303 uint32_t index,
12304 Handle<Object> value,
12305 PropertyDetails details) {
12306 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12307 dictionary->Set(index, *value, details),
12308 SeededNumberDictionary);
12309}
12310
12311
12312Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
12313 Handle<UnseededNumberDictionary> dictionary,
12314 uint32_t index,
12315 Handle<Object> value) {
12316 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12317 dictionary->Set(index, *value),
12318 UnseededNumberDictionary);
12319}
12320
12321
12322MaybeObject* SeededNumberDictionary::Set(uint32_t key,
12323 Object* value,
12324 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012325 int entry = FindEntry(key);
12326 if (entry == kNotFound) return AddNumberEntry(key, value, details);
12327 // Preserve enumeration index.
12328 details = PropertyDetails(details.attributes(),
12329 details.type(),
12330 DetailsAt(entry).index());
Ben Murdochc7cc0282012-03-05 14:35:55 +000012331 MaybeObject* maybe_object_key = SeededNumberDictionaryShape::AsObject(key);
John Reck59135872010-11-02 12:39:01 -070012332 Object* object_key;
12333 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
Ben Murdochf87a2032010-10-22 12:50:53 +010012334 SetEntry(entry, object_key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000012335 return this;
12336}
12337
12338
Ben Murdochc7cc0282012-03-05 14:35:55 +000012339MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
12340 Object* value) {
12341 int entry = FindEntry(key);
12342 if (entry == kNotFound) return AddNumberEntry(key, value);
12343 MaybeObject* maybe_object_key = UnseededNumberDictionaryShape::AsObject(key);
12344 Object* object_key;
12345 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
12346 SetEntry(entry, object_key, value);
12347 return this;
12348}
12349
12350
Steve Blocka7e24c12009-10-30 11:49:00 +000012351
12352template<typename Shape, typename Key>
12353int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
12354 PropertyAttributes filter) {
12355 int capacity = HashTable<Shape, Key>::Capacity();
12356 int result = 0;
12357 for (int i = 0; i < capacity; i++) {
12358 Object* k = HashTable<Shape, Key>::KeyAt(i);
12359 if (HashTable<Shape, Key>::IsKey(k)) {
12360 PropertyDetails details = DetailsAt(i);
12361 if (details.IsDeleted()) continue;
12362 PropertyAttributes attr = details.attributes();
12363 if ((attr & filter) == 0) result++;
12364 }
12365 }
12366 return result;
12367}
12368
12369
12370template<typename Shape, typename Key>
12371int Dictionary<Shape, Key>::NumberOfEnumElements() {
12372 return NumberOfElementsFilterAttributes(
12373 static_cast<PropertyAttributes>(DONT_ENUM));
12374}
12375
12376
12377template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012378void Dictionary<Shape, Key>::CopyKeysTo(
12379 FixedArray* storage,
12380 PropertyAttributes filter,
12381 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012382 ASSERT(storage->length() >= NumberOfEnumElements());
12383 int capacity = HashTable<Shape, Key>::Capacity();
12384 int index = 0;
12385 for (int i = 0; i < capacity; i++) {
12386 Object* k = HashTable<Shape, Key>::KeyAt(i);
12387 if (HashTable<Shape, Key>::IsKey(k)) {
12388 PropertyDetails details = DetailsAt(i);
12389 if (details.IsDeleted()) continue;
12390 PropertyAttributes attr = details.attributes();
12391 if ((attr & filter) == 0) storage->set(index++, k);
12392 }
12393 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012394 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12395 storage->SortPairs(storage, index);
12396 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012397 ASSERT(storage->length() >= index);
12398}
12399
12400
12401void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
12402 FixedArray* sort_array) {
12403 ASSERT(storage->length() >= NumberOfEnumElements());
12404 int capacity = Capacity();
12405 int index = 0;
12406 for (int i = 0; i < capacity; i++) {
12407 Object* k = KeyAt(i);
12408 if (IsKey(k)) {
12409 PropertyDetails details = DetailsAt(i);
12410 if (details.IsDeleted() || details.IsDontEnum()) continue;
12411 storage->set(index, k);
Leon Clarke4515c472010-02-03 11:58:03 +000012412 sort_array->set(index, Smi::FromInt(details.index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000012413 index++;
12414 }
12415 }
12416 storage->SortPairs(sort_array, sort_array->length());
12417 ASSERT(storage->length() >= index);
12418}
12419
12420
12421template<typename Shape, typename Key>
Ben Murdoch6d7cb002011-08-04 19:25:22 +010012422void Dictionary<Shape, Key>::CopyKeysTo(
Ben Murdoch257744e2011-11-30 15:57:28 +000012423 FixedArray* storage,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012424 int index,
12425 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012426 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
12427 static_cast<PropertyAttributes>(NONE)));
12428 int capacity = HashTable<Shape, Key>::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000012429 for (int i = 0; i < capacity; i++) {
12430 Object* k = HashTable<Shape, Key>::KeyAt(i);
12431 if (HashTable<Shape, Key>::IsKey(k)) {
12432 PropertyDetails details = DetailsAt(i);
12433 if (details.IsDeleted()) continue;
12434 storage->set(index++, k);
12435 }
12436 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012437 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12438 storage->SortPairs(storage, index);
12439 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012440 ASSERT(storage->length() >= index);
12441}
12442
12443
12444// Backwards lookup (slow).
12445template<typename Shape, typename Key>
12446Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
12447 int capacity = HashTable<Shape, Key>::Capacity();
12448 for (int i = 0; i < capacity; i++) {
12449 Object* k = HashTable<Shape, Key>::KeyAt(i);
12450 if (Dictionary<Shape, Key>::IsKey(k)) {
12451 Object* e = ValueAt(i);
12452 if (e->IsJSGlobalPropertyCell()) {
12453 e = JSGlobalPropertyCell::cast(e)->value();
12454 }
12455 if (e == value) return k;
12456 }
12457 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010012458 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010012459 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012460}
12461
12462
John Reck59135872010-11-02 12:39:01 -070012463MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Steve Blocka7e24c12009-10-30 11:49:00 +000012464 JSObject* obj, int unused_property_fields) {
12465 // Make sure we preserve dictionary representation if there are too many
12466 // descriptors.
12467 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
12468
12469 // Figure out if it is necessary to generate new enumeration indices.
12470 int max_enumeration_index =
12471 NextEnumerationIndex() +
12472 (DescriptorArray::kMaxNumberOfDescriptors -
12473 NumberOfElements());
12474 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
John Reck59135872010-11-02 12:39:01 -070012475 Object* result;
12476 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12477 if (!maybe_result->ToObject(&result)) return maybe_result;
12478 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012479 }
12480
12481 int instance_descriptor_length = 0;
12482 int number_of_fields = 0;
12483
Ben Murdoch8b112d22011-06-08 16:22:53 +010012484 Heap* heap = GetHeap();
12485
Steve Blocka7e24c12009-10-30 11:49:00 +000012486 // Compute the length of the instance descriptor.
12487 int capacity = Capacity();
12488 for (int i = 0; i < capacity; i++) {
12489 Object* k = KeyAt(i);
12490 if (IsKey(k)) {
12491 Object* value = ValueAt(i);
12492 PropertyType type = DetailsAt(i).type();
12493 ASSERT(type != FIELD);
12494 instance_descriptor_length++;
Leon Clarkee46be812010-01-19 14:06:41 +000012495 if (type == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +010012496 (!value->IsJSFunction() || heap->InNewSpace(value))) {
Leon Clarkee46be812010-01-19 14:06:41 +000012497 number_of_fields += 1;
12498 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012499 }
12500 }
12501
12502 // Allocate the instance descriptor.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012503 DescriptorArray* descriptors;
12504 { MaybeObject* maybe_descriptors =
John Reck59135872010-11-02 12:39:01 -070012505 DescriptorArray::Allocate(instance_descriptor_length);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012506 if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) {
12507 return maybe_descriptors;
John Reck59135872010-11-02 12:39:01 -070012508 }
12509 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012510
12511 DescriptorArray::WhitenessWitness witness(descriptors);
Steve Blocka7e24c12009-10-30 11:49:00 +000012512
12513 int inobject_props = obj->map()->inobject_properties();
12514 int number_of_allocated_fields =
12515 number_of_fields + unused_property_fields - inobject_props;
Ben Murdochf87a2032010-10-22 12:50:53 +010012516 if (number_of_allocated_fields < 0) {
12517 // There is enough inobject space for all fields (including unused).
12518 number_of_allocated_fields = 0;
12519 unused_property_fields = inobject_props - number_of_fields;
12520 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012521
12522 // Allocate the fixed array for the fields.
John Reck59135872010-11-02 12:39:01 -070012523 Object* fields;
12524 { MaybeObject* maybe_fields =
Steve Block44f0eee2011-05-26 01:26:41 +010012525 heap->AllocateFixedArray(number_of_allocated_fields);
John Reck59135872010-11-02 12:39:01 -070012526 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
12527 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012528
12529 // Fill in the instance descriptor and the fields.
12530 int next_descriptor = 0;
12531 int current_offset = 0;
12532 for (int i = 0; i < capacity; i++) {
12533 Object* k = KeyAt(i);
12534 if (IsKey(k)) {
12535 Object* value = ValueAt(i);
12536 // Ensure the key is a symbol before writing into the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070012537 Object* key;
Steve Block44f0eee2011-05-26 01:26:41 +010012538 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
John Reck59135872010-11-02 12:39:01 -070012539 if (!maybe_key->ToObject(&key)) return maybe_key;
12540 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012541 PropertyDetails details = DetailsAt(i);
12542 PropertyType type = details.type();
12543
Steve Block44f0eee2011-05-26 01:26:41 +010012544 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012545 ConstantFunctionDescriptor d(String::cast(key),
12546 JSFunction::cast(value),
12547 details.attributes(),
12548 details.index());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012549 descriptors->Set(next_descriptor++, &d, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012550 } else if (type == NORMAL) {
12551 if (current_offset < inobject_props) {
12552 obj->InObjectPropertyAtPut(current_offset,
12553 value,
12554 UPDATE_WRITE_BARRIER);
12555 } else {
12556 int offset = current_offset - inobject_props;
12557 FixedArray::cast(fields)->set(offset, value);
12558 }
12559 FieldDescriptor d(String::cast(key),
12560 current_offset++,
12561 details.attributes(),
12562 details.index());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012563 descriptors->Set(next_descriptor++, &d, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012564 } else if (type == CALLBACKS) {
12565 CallbacksDescriptor d(String::cast(key),
12566 value,
12567 details.attributes(),
12568 details.index());
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012569 descriptors->Set(next_descriptor++, &d, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012570 } else {
12571 UNREACHABLE();
12572 }
12573 }
12574 }
12575 ASSERT(current_offset == number_of_fields);
12576
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012577 descriptors->Sort(witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012578 // Allocate new map.
John Reck59135872010-11-02 12:39:01 -070012579 Object* new_map;
12580 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
12581 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
12582 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012583
12584 // Transform the object.
12585 obj->set_map(Map::cast(new_map));
12586 obj->map()->set_instance_descriptors(descriptors);
12587 obj->map()->set_unused_property_fields(unused_property_fields);
12588
12589 obj->set_properties(FixedArray::cast(fields));
12590 ASSERT(obj->IsJSObject());
12591
12592 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
12593 // Check that it really works.
12594 ASSERT(obj->HasFastProperties());
12595
12596 return obj;
12597}
12598
12599
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012600bool ObjectHashSet::Contains(Object* key) {
12601 ASSERT(IsKey(key));
12602
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012603 // If the object does not have an identity hash, it was never used as a key.
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012604 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12605 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
12606 }
12607 return (FindEntry(key) != kNotFound);
12608}
12609
12610
12611MaybeObject* ObjectHashSet::Add(Object* key) {
12612 ASSERT(IsKey(key));
12613
12614 // Make sure the key object has an identity hash code.
12615 int hash;
12616 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12617 if (maybe_hash->IsFailure()) return maybe_hash;
12618 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12619 }
12620 int entry = FindEntry(key);
12621
12622 // Check whether key is already present.
12623 if (entry != kNotFound) return this;
12624
12625 // Check whether the hash set should be extended and add entry.
12626 Object* obj;
12627 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12628 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12629 }
12630 ObjectHashSet* table = ObjectHashSet::cast(obj);
12631 entry = table->FindInsertionEntry(hash);
12632 table->set(EntryToIndex(entry), key);
12633 table->ElementAdded();
12634 return table;
12635}
12636
12637
12638MaybeObject* ObjectHashSet::Remove(Object* key) {
12639 ASSERT(IsKey(key));
12640
12641 // If the object does not have an identity hash, it was never used as a key.
12642 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12643 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
12644 }
12645 int entry = FindEntry(key);
12646
12647 // Check whether key is actually present.
12648 if (entry == kNotFound) return this;
12649
12650 // Remove entry and try to shrink this hash set.
12651 set_the_hole(EntryToIndex(entry));
12652 ElementRemoved();
12653 return Shrink(key);
12654}
12655
12656
12657Object* ObjectHashTable::Lookup(Object* key) {
12658 ASSERT(IsKey(key));
12659
12660 // If the object does not have an identity hash, it was never used as a key.
12661 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12662 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
12663 return GetHeap()->undefined_value();
12664 }
12665 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012666 int entry = FindEntry(key);
12667 if (entry == kNotFound) return GetHeap()->undefined_value();
12668 return get(EntryToIndex(entry) + 1);
12669}
12670
12671
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012672MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
12673 ASSERT(IsKey(key));
12674
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012675 // Make sure the key object has an identity hash code.
12676 int hash;
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012677 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012678 if (maybe_hash->IsFailure()) return maybe_hash;
12679 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12680 }
12681 int entry = FindEntry(key);
12682
12683 // Check whether to perform removal operation.
12684 if (value->IsUndefined()) {
12685 if (entry == kNotFound) return this;
12686 RemoveEntry(entry);
12687 return Shrink(key);
12688 }
12689
12690 // Key is already in table, just overwrite value.
12691 if (entry != kNotFound) {
12692 set(EntryToIndex(entry) + 1, value);
12693 return this;
12694 }
12695
12696 // Check whether the hash table should be extended.
12697 Object* obj;
12698 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12699 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12700 }
12701 ObjectHashTable* table = ObjectHashTable::cast(obj);
12702 table->AddEntry(table->FindInsertionEntry(hash), key, value);
12703 return table;
12704}
12705
12706
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012707void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012708 set(EntryToIndex(entry), key);
12709 set(EntryToIndex(entry) + 1, value);
12710 ElementAdded();
12711}
12712
12713
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012714void ObjectHashTable::RemoveEntry(int entry) {
12715 set_the_hole(EntryToIndex(entry));
12716 set_the_hole(EntryToIndex(entry) + 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012717 ElementRemoved();
12718}
12719
12720
Steve Blocka7e24c12009-10-30 11:49:00 +000012721#ifdef ENABLE_DEBUGGER_SUPPORT
12722// Check if there is a break point at this code position.
12723bool DebugInfo::HasBreakPoint(int code_position) {
12724 // Get the break point info object for this code position.
12725 Object* break_point_info = GetBreakPointInfo(code_position);
12726
12727 // If there is no break point info object or no break points in the break
12728 // point info object there is no break point at this code position.
12729 if (break_point_info->IsUndefined()) return false;
12730 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
12731}
12732
12733
12734// Get the break point info object for this code position.
12735Object* DebugInfo::GetBreakPointInfo(int code_position) {
12736 // Find the index of the break point info object for this code position.
12737 int index = GetBreakPointInfoIndex(code_position);
12738
12739 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012740 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012741 return BreakPointInfo::cast(break_points()->get(index));
12742}
12743
12744
12745// Clear a break point at the specified code position.
12746void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
12747 int code_position,
12748 Handle<Object> break_point_object) {
12749 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12750 if (break_point_info->IsUndefined()) return;
12751 BreakPointInfo::ClearBreakPoint(
12752 Handle<BreakPointInfo>::cast(break_point_info),
12753 break_point_object);
12754}
12755
12756
12757void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
12758 int code_position,
12759 int source_position,
12760 int statement_position,
12761 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010012762 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000012763 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12764 if (!break_point_info->IsUndefined()) {
12765 BreakPointInfo::SetBreakPoint(
12766 Handle<BreakPointInfo>::cast(break_point_info),
12767 break_point_object);
12768 return;
12769 }
12770
12771 // Adding a new break point for a code position which did not have any
12772 // break points before. Try to find a free slot.
12773 int index = kNoBreakPointInfo;
12774 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12775 if (debug_info->break_points()->get(i)->IsUndefined()) {
12776 index = i;
12777 break;
12778 }
12779 }
12780 if (index == kNoBreakPointInfo) {
12781 // No free slot - extend break point info array.
12782 Handle<FixedArray> old_break_points =
12783 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000012784 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010012785 isolate->factory()->NewFixedArray(
12786 old_break_points->length() +
12787 Debug::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010012788
12789 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000012790 for (int i = 0; i < old_break_points->length(); i++) {
12791 new_break_points->set(i, old_break_points->get(i));
12792 }
12793 index = old_break_points->length();
12794 }
12795 ASSERT(index != kNoBreakPointInfo);
12796
12797 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010012798 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
12799 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000012800 new_break_point_info->set_code_position(Smi::FromInt(code_position));
12801 new_break_point_info->set_source_position(Smi::FromInt(source_position));
12802 new_break_point_info->
12803 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010012804 new_break_point_info->set_break_point_objects(
12805 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012806 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
12807 debug_info->break_points()->set(index, *new_break_point_info);
12808}
12809
12810
12811// Get the break point objects for a code position.
12812Object* DebugInfo::GetBreakPointObjects(int code_position) {
12813 Object* break_point_info = GetBreakPointInfo(code_position);
12814 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010012815 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012816 }
12817 return BreakPointInfo::cast(break_point_info)->break_point_objects();
12818}
12819
12820
12821// Get the total number of break points.
12822int DebugInfo::GetBreakPointCount() {
12823 if (break_points()->IsUndefined()) return 0;
12824 int count = 0;
12825 for (int i = 0; i < break_points()->length(); i++) {
12826 if (!break_points()->get(i)->IsUndefined()) {
12827 BreakPointInfo* break_point_info =
12828 BreakPointInfo::cast(break_points()->get(i));
12829 count += break_point_info->GetBreakPointCount();
12830 }
12831 }
12832 return count;
12833}
12834
12835
12836Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
12837 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010012838 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010012839 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012840 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12841 if (!debug_info->break_points()->get(i)->IsUndefined()) {
12842 Handle<BreakPointInfo> break_point_info =
12843 Handle<BreakPointInfo>(BreakPointInfo::cast(
12844 debug_info->break_points()->get(i)));
12845 if (BreakPointInfo::HasBreakPointObject(break_point_info,
12846 break_point_object)) {
12847 return *break_point_info;
12848 }
12849 }
12850 }
Steve Block44f0eee2011-05-26 01:26:41 +010012851 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012852}
12853
12854
12855// Find the index of the break point info object for the specified code
12856// position.
12857int DebugInfo::GetBreakPointInfoIndex(int code_position) {
12858 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
12859 for (int i = 0; i < break_points()->length(); i++) {
12860 if (!break_points()->get(i)->IsUndefined()) {
12861 BreakPointInfo* break_point_info =
12862 BreakPointInfo::cast(break_points()->get(i));
12863 if (break_point_info->code_position()->value() == code_position) {
12864 return i;
12865 }
12866 }
12867 }
12868 return kNoBreakPointInfo;
12869}
12870
12871
12872// Remove the specified break point object.
12873void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
12874 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010012875 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000012876 // If there are no break points just ignore.
12877 if (break_point_info->break_point_objects()->IsUndefined()) return;
12878 // If there is a single break point clear it if it is the same.
12879 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12880 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010012881 break_point_info->set_break_point_objects(
12882 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012883 }
12884 return;
12885 }
12886 // If there are multiple break points shrink the array
12887 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
12888 Handle<FixedArray> old_array =
12889 Handle<FixedArray>(
12890 FixedArray::cast(break_point_info->break_point_objects()));
12891 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010012892 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000012893 int found_count = 0;
12894 for (int i = 0; i < old_array->length(); i++) {
12895 if (old_array->get(i) == *break_point_object) {
12896 ASSERT(found_count == 0);
12897 found_count++;
12898 } else {
12899 new_array->set(i - found_count, old_array->get(i));
12900 }
12901 }
12902 // If the break point was found in the list change it.
12903 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
12904}
12905
12906
12907// Add the specified break point object.
12908void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
12909 Handle<Object> break_point_object) {
12910 // If there was no break point objects before just set it.
12911 if (break_point_info->break_point_objects()->IsUndefined()) {
12912 break_point_info->set_break_point_objects(*break_point_object);
12913 return;
12914 }
12915 // If the break point object is the same as before just ignore.
12916 if (break_point_info->break_point_objects() == *break_point_object) return;
12917 // If there was one break point object before replace with array.
12918 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Steve Block44f0eee2011-05-26 01:26:41 +010012919 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000012920 array->set(0, break_point_info->break_point_objects());
12921 array->set(1, *break_point_object);
12922 break_point_info->set_break_point_objects(*array);
12923 return;
12924 }
12925 // If there was more than one break point before extend array.
12926 Handle<FixedArray> old_array =
12927 Handle<FixedArray>(
12928 FixedArray::cast(break_point_info->break_point_objects()));
12929 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010012930 FACTORY->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000012931 for (int i = 0; i < old_array->length(); i++) {
12932 // If the break point was there before just ignore.
12933 if (old_array->get(i) == *break_point_object) return;
12934 new_array->set(i, old_array->get(i));
12935 }
12936 // Add the new break point.
12937 new_array->set(old_array->length(), *break_point_object);
12938 break_point_info->set_break_point_objects(*new_array);
12939}
12940
12941
12942bool BreakPointInfo::HasBreakPointObject(
12943 Handle<BreakPointInfo> break_point_info,
12944 Handle<Object> break_point_object) {
12945 // No break point.
12946 if (break_point_info->break_point_objects()->IsUndefined()) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012947 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000012948 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12949 return break_point_info->break_point_objects() == *break_point_object;
12950 }
12951 // Multiple break points.
12952 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
12953 for (int i = 0; i < array->length(); i++) {
12954 if (array->get(i) == *break_point_object) {
12955 return true;
12956 }
12957 }
12958 return false;
12959}
12960
12961
12962// Get the number of break points.
12963int BreakPointInfo::GetBreakPointCount() {
12964 // No break point.
12965 if (break_point_objects()->IsUndefined()) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012966 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000012967 if (!break_point_objects()->IsFixedArray()) return 1;
12968 // Multiple break points.
12969 return FixedArray::cast(break_point_objects())->length();
12970}
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012971#endif // ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +000012972
12973
12974} } // namespace v8::internal