blob: bb2f2d3d3bb52a3270f896bd39bda9f0484a2767 [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000031#include "arguments.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "bootstrapper.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000033#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000034#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000035#include "deoptimizer.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000036#include "elements.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "execution.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000038#include "full-codegen.h"
39#include "hydrogen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "objects-inl.h"
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000041#include "objects-visiting.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000042#include "objects-visiting-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "macro-assembler.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000044#include "mark-compact.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000045#include "safepoint-table.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "string-stream.h"
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000047#include "utils.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049
mads.s.ager31e71382008-08-13 09:32:07 +000050#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051#include "disasm.h"
mads.s.ager31e71382008-08-13 09:32:07 +000052#include "disassembler.h"
53#endif
54
kasperl@chromium.org71affb52009-05-26 05:44:31 +000055namespace v8 {
56namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000058void PrintElementsKind(FILE* out, ElementsKind kind) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000059 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
60 PrintF(out, "%s", accessor->name());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000061}
62
63
lrn@chromium.org303ada72010-10-27 09:33:13 +000064MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
65 Object* value) {
66 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 { MaybeObject* maybe_result =
68 constructor->GetHeap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +000069 if (!maybe_result->ToObject(&result)) return maybe_result;
70 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071 JSValue::cast(result)->set_value(value);
72 return result;
73}
74
75
lrn@chromium.org303ada72010-10-27 09:33:13 +000076MaybeObject* Object::ToObject(Context* global_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077 if (IsNumber()) {
78 return CreateJSValue(global_context->number_function(), this);
79 } else if (IsBoolean()) {
80 return CreateJSValue(global_context->boolean_function(), this);
81 } else if (IsString()) {
82 return CreateJSValue(global_context->string_function(), this);
83 }
84 ASSERT(IsJSObject());
85 return this;
86}
87
88
lrn@chromium.org303ada72010-10-27 09:33:13 +000089MaybeObject* Object::ToObject() {
lrn@chromium.org34e60782011-09-15 07:25:40 +000090 if (IsJSReceiver()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091 return this;
92 } else if (IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000093 Isolate* isolate = Isolate::Current();
94 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095 return CreateJSValue(global_context->number_function(), this);
96 } else if (IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000097 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
98 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099 return CreateJSValue(global_context->boolean_function(), this);
100 } else if (IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000101 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
102 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103 return CreateJSValue(global_context->string_function(), this);
104 }
105
106 // Throw a type error.
107 return Failure::InternalError();
108}
109
110
111Object* Object::ToBoolean() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 if (IsTrue()) return this;
113 if (IsFalse()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000114 if (IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000115 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000116 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000117 HeapObject* heap_object = HeapObject::cast(this);
118 if (heap_object->IsUndefined() || heap_object->IsNull()) {
119 return heap_object->GetHeap()->false_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000120 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121 // Undetectable object is false
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000122 if (heap_object->IsUndetectableObject()) {
123 return heap_object->GetHeap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000125 if (heap_object->IsString()) {
126 return heap_object->GetHeap()->ToBoolean(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000127 String::cast(this)->length() != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000128 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000129 if (heap_object->IsHeapNumber()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000130 return HeapNumber::cast(this)->HeapNumberToBoolean();
131 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000132 return heap_object->GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000133}
134
135
136void Object::Lookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000137 Object* holder = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000138 if (IsJSReceiver()) {
139 holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000140 } else {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000141 Context* global_context = Isolate::Current()->context()->global_context();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000142 if (IsNumber()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000143 holder = global_context->number_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000144 } else if (IsString()) {
145 holder = global_context->string_function()->instance_prototype();
146 } else if (IsBoolean()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000147 holder = global_context->boolean_function()->instance_prototype();
148 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000150 ASSERT(holder != NULL); // Cannot handle null or undefined.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000151 JSReceiver::cast(holder)->Lookup(name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000152}
153
154
lrn@chromium.org303ada72010-10-27 09:33:13 +0000155MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
156 String* name,
157 PropertyAttributes* attributes) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000158 LookupResult result(name->GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 Lookup(name, &result);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000160 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000161 ASSERT(*attributes <= ABSENT);
162 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000163}
164
165
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000166MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
167 Object* structure,
168 String* name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000169 Isolate* isolate = name->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000170 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000171 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000173 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000174 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000175 reinterpret_cast<AccessorDescriptor*>(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000176 Foreign::cast(structure)->foreign_address());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000177 MaybeObject* value = (callback->getter)(receiver, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000178 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000179 return value;
180 }
181
182 // api style callbacks.
183 if (structure->IsAccessorInfo()) {
184 AccessorInfo* data = AccessorInfo::cast(structure);
185 Object* fun_obj = data->getter();
186 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000187 HandleScope scope(isolate);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000188 JSObject* self = JSObject::cast(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000190 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000191 CustomArguments args(isolate, data->data(), self, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000192 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193 v8::Handle<v8::Value> result;
194 {
195 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000196 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000197 result = call_fun(v8::Utils::ToLocal(key), info);
198 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000199 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
200 if (result.IsEmpty()) {
201 return isolate->heap()->undefined_value();
202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203 return *v8::Utils::OpenHandle(*result);
204 }
205
206 // __defineGetter__ callback
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000207 if (structure->IsAccessorPair()) {
208 Object* getter = AccessorPair::cast(structure)->getter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000209 if (getter->IsSpecFunction()) {
210 // TODO(rossberg): nicer would be to cast to some JSCallable here...
211 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212 }
213 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000214 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000215 }
216
217 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000218 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219}
220
221
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000222MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
223 String* name_raw) {
224 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000225 HandleScope scope(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000226 Handle<Object> receiver(receiver_raw);
227 Handle<Object> name(name_raw);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000228
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000229 Handle<Object> args[] = { receiver, name };
230 Handle<Object> result = CallTrap(
231 "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000232 if (isolate->has_pending_exception()) return Failure::Exception();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000233
234 return *result;
235}
236
237
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000238Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
239 Isolate* isolate = object->IsHeapObject()
240 ? Handle<HeapObject>::cast(object)->GetIsolate()
241 : Isolate::Current();
242 CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
243}
244
245
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000246MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
247 uint32_t index) {
248 String* name;
249 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
250 if (!maybe->To<String>(&name)) return maybe;
251 return GetPropertyWithHandler(receiver, name);
252}
253
254
255MaybeObject* JSProxy::SetElementWithHandler(uint32_t index,
256 Object* value,
257 StrictModeFlag strict_mode) {
258 String* name;
259 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
260 if (!maybe->To<String>(&name)) return maybe;
261 return SetPropertyWithHandler(name, value, NONE, strict_mode);
262}
263
264
265bool JSProxy::HasElementWithHandler(uint32_t index) {
266 String* name;
267 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
268 if (!maybe->To<String>(&name)) return maybe;
269 return HasPropertyWithHandler(name);
270}
271
272
lrn@chromium.org303ada72010-10-27 09:33:13 +0000273MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000274 JSReceiver* getter) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000275 HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000276 Handle<JSReceiver> fun(getter);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000277 Handle<Object> self(receiver);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000278#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000279 Debug* debug = fun->GetHeap()->isolate()->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000280 // Handle stepping into a getter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000281 // TODO(rossberg): should this apply to getters that are function proxies?
282 if (debug->StepInActive() && fun->IsJSFunction()) {
283 debug->HandleStepIn(
284 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000285 }
286#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000287
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000288 bool has_pending_exception;
289 Handle<Object> result =
290 Execution::Call(fun, self, 0, NULL, &has_pending_exception);
291 // Check for pending exception and return the result.
292 if (has_pending_exception) return Failure::Exception();
293 return *result;
294}
295
296
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297// Only deal with CALLBACKS and INTERCEPTOR
lrn@chromium.org303ada72010-10-27 09:33:13 +0000298MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
ager@chromium.org8bb60582008-12-11 12:02:20 +0000299 Object* receiver,
300 LookupResult* result,
301 String* name,
302 PropertyAttributes* attributes) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000303 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304 switch (result->type()) {
305 case CALLBACKS: {
306 // Only allow API accessors.
307 Object* obj = result->GetCallbackObject();
308 if (obj->IsAccessorInfo()) {
309 AccessorInfo* info = AccessorInfo::cast(obj);
310 if (info->all_can_read()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000311 *attributes = result->GetAttributes();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000312 return result->holder()->GetPropertyWithCallback(
313 receiver, result->GetCallbackObject(), name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314 }
315 }
316 break;
317 }
318 case NORMAL:
319 case FIELD:
320 case CONSTANT_FUNCTION: {
321 // Search ALL_CAN_READ accessors in prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000322 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000324 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000325 return GetPropertyWithFailedAccessCheck(receiver,
326 &r,
327 name,
328 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000329 }
330 break;
331 }
332 case INTERCEPTOR: {
333 // If the object has an interceptor, try real named properties.
334 // No access check in GetPropertyAttributeWithInterceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000335 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336 result->holder()->LookupRealNamedProperty(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000337 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000338 return GetPropertyWithFailedAccessCheck(receiver,
339 &r,
340 name,
341 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000342 }
ager@chromium.org9ed6c322010-02-19 12:24:05 +0000343 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000344 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000345 default:
346 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000347 }
348 }
349
ager@chromium.org8bb60582008-12-11 12:02:20 +0000350 // No accessible property found.
351 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000352 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000353 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
354 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355}
356
357
ager@chromium.org870a0b62008-11-04 11:43:05 +0000358PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
359 Object* receiver,
360 LookupResult* result,
361 String* name,
362 bool continue_search) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000363 if (result->IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000364 switch (result->type()) {
365 case CALLBACKS: {
366 // Only allow API accessors.
367 Object* obj = result->GetCallbackObject();
368 if (obj->IsAccessorInfo()) {
369 AccessorInfo* info = AccessorInfo::cast(obj);
370 if (info->all_can_read()) {
371 return result->GetAttributes();
372 }
373 }
374 break;
375 }
376
377 case NORMAL:
378 case FIELD:
379 case CONSTANT_FUNCTION: {
380 if (!continue_search) break;
381 // Search ALL_CAN_READ accessors in prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000382 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000383 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000384 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000385 return GetPropertyAttributeWithFailedAccessCheck(receiver,
386 &r,
387 name,
388 continue_search);
389 }
390 break;
391 }
392
393 case INTERCEPTOR: {
394 // If the object has an interceptor, try real named properties.
395 // No access check in GetPropertyAttributeWithInterceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000396 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000397 if (continue_search) {
398 result->holder()->LookupRealNamedProperty(name, &r);
399 } else {
400 result->holder()->LocalLookupRealNamedProperty(name, &r);
401 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000402 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000403 return GetPropertyAttributeWithFailedAccessCheck(receiver,
404 &r,
405 name,
406 continue_search);
407 }
408 break;
409 }
410
ager@chromium.org5c838252010-02-19 08:53:10 +0000411 default:
412 UNREACHABLE();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000413 }
414 }
415
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000416 GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000417 return ABSENT;
418}
419
420
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000421Object* JSObject::GetNormalizedProperty(LookupResult* result) {
422 ASSERT(!HasFastProperties());
423 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
424 if (IsGlobalObject()) {
425 value = JSGlobalPropertyCell::cast(value)->value();
426 }
427 ASSERT(!value->IsJSGlobalPropertyCell());
428 return value;
429}
430
431
432Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
433 ASSERT(!HasFastProperties());
434 if (IsGlobalObject()) {
435 JSGlobalPropertyCell* cell =
436 JSGlobalPropertyCell::cast(
437 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
438 cell->set_value(value);
439 } else {
440 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
441 }
442 return value;
443}
444
445
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000446Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
447 Handle<String> key,
448 Handle<Object> value,
449 PropertyDetails details) {
450 CALL_HEAP_FUNCTION(object->GetIsolate(),
451 object->SetNormalizedProperty(*key, *value, details),
452 Object);
453}
454
455
lrn@chromium.org303ada72010-10-27 09:33:13 +0000456MaybeObject* JSObject::SetNormalizedProperty(String* name,
457 Object* value,
458 PropertyDetails details) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000459 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000460 int entry = property_dictionary()->FindEntry(name);
461 if (entry == StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000462 Object* store_value = value;
463 if (IsGlobalObject()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000464 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000465 MaybeObject* maybe_store_value =
466 heap->AllocateJSGlobalPropertyCell(value);
467 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000468 }
lrn@chromium.org303ada72010-10-27 09:33:13 +0000469 Object* dict;
470 { MaybeObject* maybe_dict =
471 property_dictionary()->Add(name, store_value, details);
472 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
473 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000474 set_properties(StringDictionary::cast(dict));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000475 return value;
476 }
477 // Preserve enumeration index.
478 details = PropertyDetails(details.attributes(),
479 details.type(),
480 property_dictionary()->DetailsAt(entry).index());
481 if (IsGlobalObject()) {
482 JSGlobalPropertyCell* cell =
483 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
484 cell->set_value(value);
485 // Please note we have to update the property details.
486 property_dictionary()->DetailsAtPut(entry, details);
487 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000488 property_dictionary()->SetEntry(entry, name, value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000489 }
490 return value;
491}
492
493
lrn@chromium.org303ada72010-10-27 09:33:13 +0000494MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000495 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000496 StringDictionary* dictionary = property_dictionary();
497 int entry = dictionary->FindEntry(name);
498 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000499 // If we have a global object set the cell to the hole.
500 if (IsGlobalObject()) {
501 PropertyDetails details = dictionary->DetailsAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000502 if (details.IsDontDelete()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000503 if (mode != FORCE_DELETION) return GetHeap()->false_value();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000504 // When forced to delete global properties, we have to make a
505 // map change to invalidate any ICs that think they can load
506 // from the DontDelete cell without checking if it contains
507 // the hole value.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000508 Object* new_map;
509 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
510 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
511 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000512 set_map(Map::cast(new_map));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000513 }
514 JSGlobalPropertyCell* cell =
515 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000516 cell->set_value(cell->GetHeap()->the_hole_value());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000517 dictionary->DetailsAtPut(entry, details.AsDeleted());
518 } else {
ager@chromium.org04921a82011-06-27 13:21:41 +0000519 Object* deleted = dictionary->DeleteProperty(entry, mode);
520 if (deleted == GetHeap()->true_value()) {
521 FixedArray* new_properties = NULL;
522 MaybeObject* maybe_properties = dictionary->Shrink(name);
523 if (!maybe_properties->To(&new_properties)) {
524 return maybe_properties;
525 }
526 set_properties(new_properties);
527 }
528 return deleted;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000529 }
530 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000531 return GetHeap()->true_value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000532}
533
534
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000535bool JSObject::IsDirty() {
536 Object* cons_obj = map()->constructor();
537 if (!cons_obj->IsJSFunction())
538 return true;
539 JSFunction* fun = JSFunction::cast(cons_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000540 if (!fun->shared()->IsApiFunction())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000541 return true;
542 // If the object is fully fast case and has the same map it was
543 // created with then no changes can have been made to it.
544 return map() != fun->initial_map()
545 || !HasFastElements()
546 || !HasFastProperties();
547}
548
549
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000550Handle<Object> Object::GetProperty(Handle<Object> object,
551 Handle<Object> receiver,
552 LookupResult* result,
553 Handle<String> key,
554 PropertyAttributes* attributes) {
555 Isolate* isolate = object->IsHeapObject()
556 ? Handle<HeapObject>::cast(object)->GetIsolate()
557 : Isolate::Current();
558 CALL_HEAP_FUNCTION(
559 isolate,
560 object->GetProperty(*receiver, result, *key, attributes),
561 Object);
562}
563
564
lrn@chromium.org303ada72010-10-27 09:33:13 +0000565MaybeObject* Object::GetProperty(Object* receiver,
566 LookupResult* result,
567 String* name,
568 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569 // Make sure that the top context does not change when doing
570 // callbacks or interceptor calls.
571 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 Heap* heap = name->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573
574 // Traverse the prototype chain from the current object (this) to
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000575 // the holder and check for access rights. This avoids traversing the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576 // objects more than once in case of interceptors, because the
577 // holder will always be the interceptor holder and the search may
578 // only continue with a current object just after the interceptor
579 // holder in the prototype chain.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000580 // Proxy handlers do not use the proxy's prototype, so we can skip this.
581 if (!result->IsHandler()) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000582 Object* last = result->IsProperty()
583 ? result->holder()
584 : Object::cast(heap->null_value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000585 ASSERT(this != this->GetPrototype());
586 for (Object* current = this; true; current = current->GetPrototype()) {
587 if (current->IsAccessCheckNeeded()) {
588 // Check if we're allowed to read from the current object. Note
589 // that even though we may not actually end up loading the named
590 // property from the current object, we still check that we have
591 // access to it.
592 JSObject* checked = JSObject::cast(current);
593 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
594 return checked->GetPropertyWithFailedAccessCheck(receiver,
595 result,
596 name,
597 attributes);
598 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000600 // Stop traversing the chain once we reach the last object in the
601 // chain; either the holder of the result or null in case of an
602 // absent property.
603 if (current == last) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000604 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000605 }
606
kasper.lund44510672008-07-25 07:37:58 +0000607 if (!result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000608 *attributes = ABSENT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000610 }
611 *attributes = result->GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000612 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000613 switch (result->type()) {
614 case NORMAL:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000615 value = result->holder()->GetNormalizedProperty(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000617 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 case FIELD:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000619 value = result->holder()->FastPropertyAt(result->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622 case CONSTANT_FUNCTION:
623 return result->GetConstantFunction();
624 case CALLBACKS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000625 return result->holder()->GetPropertyWithCallback(
626 receiver, result->GetCallbackObject(), name);
627 case HANDLER:
628 return result->proxy()->GetPropertyWithHandler(receiver, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629 case INTERCEPTOR: {
630 JSObject* recvr = JSObject::cast(receiver);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000631 return result->holder()->GetPropertyWithInterceptor(
632 recvr, name, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000634 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000635 case ELEMENTS_TRANSITION:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000636 case CONSTANT_TRANSITION:
637 case NULL_DESCRIPTOR:
638 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000640 UNREACHABLE();
641 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642}
643
644
lrn@chromium.org303ada72010-10-27 09:33:13 +0000645MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000646 Heap* heap = IsSmi()
647 ? Isolate::Current()->heap()
648 : HeapObject::cast(this)->GetHeap();
649 Object* holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000650
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000651 // Iterate up the prototype chain until an element is found or the null
652 // prototype is encountered.
653 for (holder = this;
654 holder != heap->null_value();
655 holder = holder->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000656 if (!holder->IsJSObject()) {
657 Isolate* isolate = heap->isolate();
658 Context* global_context = isolate->context()->global_context();
659 if (holder->IsNumber()) {
660 holder = global_context->number_function()->instance_prototype();
661 } else if (holder->IsString()) {
662 holder = global_context->string_function()->instance_prototype();
663 } else if (holder->IsBoolean()) {
664 holder = global_context->boolean_function()->instance_prototype();
665 } else if (holder->IsJSProxy()) {
666 return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
667 } else {
668 // Undefined and null have no indexed properties.
669 ASSERT(holder->IsUndefined() || holder->IsNull());
670 return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000671 }
672 }
673
674 // Inline the case for JSObjects. Doing so significantly improves the
675 // performance of fetching elements where checking the prototype chain is
676 // necessary.
677 JSObject* js_object = JSObject::cast(holder);
678
679 // Check access rights if needed.
680 if (js_object->IsAccessCheckNeeded()) {
681 Isolate* isolate = heap->isolate();
682 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
683 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
684 return heap->undefined_value();
685 }
686 }
687
688 if (js_object->HasIndexedInterceptor()) {
689 return js_object->GetElementWithInterceptor(receiver, index);
690 }
691
692 if (js_object->elements() != heap->empty_fixed_array()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000693 MaybeObject* result = js_object->GetElementsAccessor()->Get(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000694 receiver, js_object, index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000695 if (result != heap->the_hole_value()) return result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000696 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000697 }
698
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000699 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700}
701
702
703Object* Object::GetPrototype() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000704 if (IsSmi()) {
705 Heap* heap = Isolate::Current()->heap();
706 Context* context = heap->isolate()->context()->global_context();
707 return context->number_function()->instance_prototype();
708 }
709
710 HeapObject* heap_object = HeapObject::cast(this);
711
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000712 // The object is either a number, a string, a boolean,
713 // a real JS object, or a Harmony proxy.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000714 if (heap_object->IsJSReceiver()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000715 return heap_object->map()->prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000716 }
717 Heap* heap = heap_object->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000718 Context* context = heap->isolate()->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000720 if (heap_object->IsHeapNumber()) {
721 return context->number_function()->instance_prototype();
722 }
723 if (heap_object->IsString()) {
724 return context->string_function()->instance_prototype();
725 }
726 if (heap_object->IsBoolean()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000727 return context->boolean_function()->instance_prototype();
728 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000729 return heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000730 }
731}
732
733
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000734MaybeObject* Object::GetHash(CreationFlag flag) {
735 // The object is either a number, a string, an odd-ball,
736 // a real JS object, or a Harmony proxy.
737 if (IsNumber()) {
738 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
739 return Smi::FromInt(hash & Smi::kMaxValue);
740 }
741 if (IsString()) {
742 uint32_t hash = String::cast(this)->Hash();
743 return Smi::FromInt(hash);
744 }
745 if (IsOddball()) {
746 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
747 return Smi::FromInt(hash);
748 }
749 if (IsJSReceiver()) {
750 return JSReceiver::cast(this)->GetIdentityHash(flag);
751 }
752
753 UNREACHABLE();
754 return Smi::FromInt(0);
755}
756
757
758bool Object::SameValue(Object* other) {
759 if (other == this) return true;
760 if (!IsHeapObject() || !other->IsHeapObject()) return false;
761
762 // The object is either a number, a string, an odd-ball,
763 // a real JS object, or a Harmony proxy.
764 if (IsNumber() && other->IsNumber()) {
765 double this_value = Number();
766 double other_value = other->Number();
767 return (this_value == other_value) ||
768 (isnan(this_value) && isnan(other_value));
769 }
770 if (IsString() && other->IsString()) {
771 return String::cast(this)->Equals(String::cast(other));
772 }
773 return false;
774}
775
776
whesse@chromium.org023421e2010-12-21 12:19:12 +0000777void Object::ShortPrint(FILE* out) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778 HeapStringAllocator allocator;
779 StringStream accumulator(&allocator);
780 ShortPrint(&accumulator);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000781 accumulator.OutputToFile(out);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000782}
783
784
785void Object::ShortPrint(StringStream* accumulator) {
786 if (IsSmi()) {
787 Smi::cast(this)->SmiPrint(accumulator);
788 } else if (IsFailure()) {
789 Failure::cast(this)->FailurePrint(accumulator);
790 } else {
791 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
792 }
793}
794
795
whesse@chromium.org023421e2010-12-21 12:19:12 +0000796void Smi::SmiPrint(FILE* out) {
797 PrintF(out, "%d", value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798}
799
800
801void Smi::SmiPrint(StringStream* accumulator) {
802 accumulator->Add("%d", value());
803}
804
805
806void Failure::FailurePrint(StringStream* accumulator) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000807 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808}
809
810
whesse@chromium.org023421e2010-12-21 12:19:12 +0000811void Failure::FailurePrint(FILE* out) {
812 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813}
814
815
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000816// Should a word be prefixed by 'a' or 'an' in order to read naturally in
817// English? Returns false for non-ASCII or words that don't start with
818// a capital letter. The a/an rule follows pronunciation in English.
819// We don't use the BBC's overcorrect "an historic occasion" though if
820// you speak a dialect you may well say "an 'istoric occasion".
821static bool AnWord(String* str) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000822 if (str->length() == 0) return false; // A nothing.
823 int c0 = str->Get(0);
824 int c1 = str->length() > 1 ? str->Get(1) : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000825 if (c0 == 'U') {
826 if (c1 > 'Z') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000827 return true; // An Umpire, but a UTF8String, a U.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000828 }
829 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000830 return true; // An Ape, an ABCBook.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000831 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
832 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
833 c0 == 'S' || c0 == 'X')) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000834 return true; // An MP3File, an M.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835 }
836 return false;
837}
838
839
lrn@chromium.org303ada72010-10-27 09:33:13 +0000840MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841#ifdef DEBUG
842 // Do not attempt to flatten in debug mode when allocation is not
843 // allowed. This is to avoid an assertion failure when allocating.
844 // Flattening strings is the only case where we always allow
845 // allocation because no GC is performed if the allocation fails.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000846 if (!HEAP->IsAllocationAllowed()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847#endif
848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000850 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851 case kConsStringTag: {
852 ConsString* cs = ConsString::cast(this);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000853 if (cs->second()->length() == 0) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000854 return cs->first();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000855 }
856 // There's little point in putting the flat string in new space if the
857 // cons string is in old space. It can never get GCed until there is
858 // an old space GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000860 int len = length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000861 Object* object;
862 String* result;
ager@chromium.org5ec48922009-05-05 07:25:34 +0000863 if (IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000864 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000865 if (!maybe_object->ToObject(&object)) return maybe_object;
866 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000867 result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000868 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000869 int first_length = first->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000870 char* dest = SeqAsciiString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000871 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000872 String* second = cs->second();
873 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000874 dest + first_length,
875 0,
876 len - first_length);
877 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000878 { MaybeObject* maybe_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 heap->AllocateRawTwoByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000880 if (!maybe_object->ToObject(&object)) return maybe_object;
881 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000882 result = String::cast(object);
883 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000884 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000885 int first_length = first->length();
886 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000887 String* second = cs->second();
888 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000889 dest + first_length,
890 0,
891 len - first_length);
892 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000893 cs->set_first(result);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000894 cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000895 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896 }
897 default:
898 return this;
899 }
900}
901
902
ager@chromium.org6f10e412009-02-13 10:11:16 +0000903bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000904 // Externalizing twice leaks the external resource, so it's
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000905 // prohibited by the API.
906 ASSERT(!this->IsExternalString());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000907#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +0000908 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000909 // Assert that the resource and the string are equivalent.
910 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000911 ScopedVector<uc16> smart_chars(this->length());
912 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
913 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +0000914 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000915 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000916 }
917#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000919 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000920 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000921 return false;
922 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000923 bool is_ascii = this->IsAsciiRepresentation();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000924 bool is_symbol = this->IsSymbol();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000925
926 // Morph the object to an external string by adjusting the map and
927 // reinitializing the fields.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000928 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000929 this->set_map_no_write_barrier(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000930 is_symbol
931 ? (is_ascii ? heap->external_symbol_with_ascii_data_map()
932 : heap->external_symbol_map())
933 : (is_ascii ? heap->external_string_with_ascii_data_map()
934 : heap->external_string_map()));
935 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000936 this->set_map_no_write_barrier(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000937 is_symbol
938 ? (is_ascii ? heap->short_external_symbol_with_ascii_data_map()
939 : heap->short_external_symbol_map())
940 : (is_ascii ? heap->short_external_string_with_ascii_data_map()
941 : heap->short_external_string_map()));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000942 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000943 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
944 self->set_resource(resource);
945 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +0000946
947 // Fill the remainder of the string with dead wood.
948 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000949 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000950 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000951 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
952 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000953 }
ager@chromium.org6f10e412009-02-13 10:11:16 +0000954 return true;
955}
956
957
958bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
959#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +0000960 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000961 // Assert that the resource and the string are equivalent.
962 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000963 ScopedVector<char> smart_chars(this->length());
964 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
965 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +0000966 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000967 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000968 }
969#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000970 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000971 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000972 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000973 return false;
974 }
ager@chromium.org6f10e412009-02-13 10:11:16 +0000975 bool is_symbol = this->IsSymbol();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000976
977 // Morph the object to an external string by adjusting the map and
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000978 // reinitializing the fields. Use short version if space is limited.
979 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000980 this->set_map_no_write_barrier(
981 is_symbol ? heap->external_ascii_symbol_map()
982 : heap->external_ascii_string_map());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000983 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000984 this->set_map_no_write_barrier(
985 is_symbol ? heap->short_external_ascii_symbol_map()
986 : heap->short_external_ascii_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000987 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000988 ExternalAsciiString* self = ExternalAsciiString::cast(this);
989 self->set_resource(resource);
990 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +0000991
992 // Fill the remainder of the string with dead wood.
993 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000995 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000996 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
997 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000998 }
ager@chromium.org6f10e412009-02-13 10:11:16 +0000999 return true;
1000}
1001
1002
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003void String::StringShortPrint(StringStream* accumulator) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001004 int len = length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001005 if (len > kMaxShortPrintLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006 accumulator->Add("<Very long string[%u]>", len);
1007 return;
1008 }
1009
1010 if (!LooksValid()) {
1011 accumulator->Add("<Invalid String>");
1012 return;
1013 }
1014
1015 StringInputBuffer buf(this);
1016
1017 bool truncated = false;
kasper.lund7276f142008-07-30 08:49:36 +00001018 if (len > kMaxShortPrintLength) {
1019 len = kMaxShortPrintLength;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020 truncated = true;
1021 }
1022 bool ascii = true;
1023 for (int i = 0; i < len; i++) {
1024 int c = buf.GetNext();
1025
1026 if (c < 32 || c >= 127) {
1027 ascii = false;
1028 }
1029 }
1030 buf.Reset(this);
1031 if (ascii) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001032 accumulator->Add("<String[%u]: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033 for (int i = 0; i < len; i++) {
1034 accumulator->Put(buf.GetNext());
1035 }
1036 accumulator->Put('>');
1037 } else {
1038 // Backslash indicates that the string contains control
1039 // characters and that backslashes are therefore escaped.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001040 accumulator->Add("<String[%u]\\: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041 for (int i = 0; i < len; i++) {
1042 int c = buf.GetNext();
1043 if (c == '\n') {
1044 accumulator->Add("\\n");
1045 } else if (c == '\r') {
1046 accumulator->Add("\\r");
1047 } else if (c == '\\') {
1048 accumulator->Add("\\\\");
1049 } else if (c < 32 || c > 126) {
1050 accumulator->Add("\\x%02x", c);
1051 } else {
1052 accumulator->Put(c);
1053 }
1054 }
1055 if (truncated) {
1056 accumulator->Put('.');
1057 accumulator->Put('.');
1058 accumulator->Put('.');
1059 }
1060 accumulator->Put('>');
1061 }
1062 return;
1063}
1064
1065
1066void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1067 switch (map()->instance_type()) {
1068 case JS_ARRAY_TYPE: {
1069 double length = JSArray::cast(this)->length()->Number();
1070 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
1071 break;
1072 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001073 case JS_WEAK_MAP_TYPE: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001074 accumulator->Add("<JS WeakMap>");
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001075 break;
1076 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001077 case JS_REGEXP_TYPE: {
1078 accumulator->Add("<JS RegExp>");
1079 break;
1080 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081 case JS_FUNCTION_TYPE: {
1082 Object* fun_name = JSFunction::cast(this)->shared()->name();
1083 bool printed = false;
1084 if (fun_name->IsString()) {
1085 String* str = String::cast(fun_name);
1086 if (str->length() > 0) {
1087 accumulator->Add("<JS Function ");
1088 accumulator->Put(str);
1089 accumulator->Put('>');
1090 printed = true;
1091 }
1092 }
1093 if (!printed) {
1094 accumulator->Add("<JS Function>");
1095 }
1096 break;
1097 }
1098 // All other JSObjects are rather similar to each other (JSObject,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001099 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001100 default: {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001101 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001102 Heap* heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001103 Object* constructor = map_of_this->constructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104 bool printed = false;
1105 if (constructor->IsHeapObject() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001106 !heap->Contains(HeapObject::cast(constructor))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1108 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001109 bool global_object = IsJSGlobalProxy();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001110 if (constructor->IsJSFunction()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001111 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1113 } else {
1114 Object* constructor_name =
1115 JSFunction::cast(constructor)->shared()->name();
1116 if (constructor_name->IsString()) {
1117 String* str = String::cast(constructor_name);
1118 if (str->length() > 0) {
1119 bool vowel = AnWord(str);
1120 accumulator->Add("<%sa%s ",
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001121 global_object ? "Global Object: " : "",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001122 vowel ? "n" : "");
1123 accumulator->Put(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001124 printed = true;
1125 }
1126 }
1127 }
1128 }
1129 if (!printed) {
1130 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1131 }
1132 }
1133 if (IsJSValue()) {
1134 accumulator->Add(" value = ");
1135 JSValue::cast(this)->value()->ShortPrint(accumulator);
1136 }
1137 accumulator->Put('>');
1138 break;
1139 }
1140 }
1141}
1142
1143
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001144void JSObject::PrintElementsTransition(
1145 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1146 ElementsKind to_kind, FixedArrayBase* to_elements) {
1147 if (from_kind != to_kind) {
1148 PrintF(file, "elements transition [");
1149 PrintElementsKind(file, from_kind);
1150 PrintF(file, " -> ");
1151 PrintElementsKind(file, to_kind);
1152 PrintF(file, "] in ");
1153 JavaScriptFrame::PrintTop(file, false, true);
1154 PrintF(file, " for ");
1155 ShortPrint(file);
1156 PrintF(file, " from ");
1157 from_elements->ShortPrint(file);
1158 PrintF(file, " to ");
1159 to_elements->ShortPrint(file);
1160 PrintF(file, "\n");
1161 }
1162}
1163
1164
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001166 Heap* heap = GetHeap();
1167 if (!heap->Contains(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 accumulator->Add("!!!INVALID POINTER!!!");
1169 return;
1170 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001171 if (!heap->Contains(map())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 accumulator->Add("!!!INVALID MAP!!!");
1173 return;
1174 }
1175
1176 accumulator->Add("%p ", this);
1177
1178 if (IsString()) {
1179 String::cast(this)->StringShortPrint(accumulator);
1180 return;
1181 }
1182 if (IsJSObject()) {
1183 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1184 return;
1185 }
1186 switch (map()->instance_type()) {
1187 case MAP_TYPE:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001188 accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 break;
1190 case FIXED_ARRAY_TYPE:
1191 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1192 break;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001193 case FIXED_DOUBLE_ARRAY_TYPE:
1194 accumulator->Add("<FixedDoubleArray[%u]>",
1195 FixedDoubleArray::cast(this)->length());
1196 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 case BYTE_ARRAY_TYPE:
1198 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1199 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001200 case FREE_SPACE_TYPE:
1201 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1202 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001203 case EXTERNAL_PIXEL_ARRAY_TYPE:
1204 accumulator->Add("<ExternalPixelArray[%u]>",
1205 ExternalPixelArray::cast(this)->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001206 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00001207 case EXTERNAL_BYTE_ARRAY_TYPE:
1208 accumulator->Add("<ExternalByteArray[%u]>",
1209 ExternalByteArray::cast(this)->length());
1210 break;
1211 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1212 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1213 ExternalUnsignedByteArray::cast(this)->length());
1214 break;
1215 case EXTERNAL_SHORT_ARRAY_TYPE:
1216 accumulator->Add("<ExternalShortArray[%u]>",
1217 ExternalShortArray::cast(this)->length());
1218 break;
1219 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1220 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1221 ExternalUnsignedShortArray::cast(this)->length());
1222 break;
1223 case EXTERNAL_INT_ARRAY_TYPE:
1224 accumulator->Add("<ExternalIntArray[%u]>",
1225 ExternalIntArray::cast(this)->length());
1226 break;
1227 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1228 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1229 ExternalUnsignedIntArray::cast(this)->length());
1230 break;
1231 case EXTERNAL_FLOAT_ARRAY_TYPE:
1232 accumulator->Add("<ExternalFloatArray[%u]>",
1233 ExternalFloatArray::cast(this)->length());
1234 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001235 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1236 accumulator->Add("<ExternalDoubleArray[%u]>",
1237 ExternalDoubleArray::cast(this)->length());
1238 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001239 case SHARED_FUNCTION_INFO_TYPE:
1240 accumulator->Add("<SharedFunctionInfo>");
1241 break;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001242 case JS_MESSAGE_OBJECT_TYPE:
1243 accumulator->Add("<JSMessageObject>");
1244 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245#define MAKE_STRUCT_CASE(NAME, Name, name) \
1246 case NAME##_TYPE: \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001247 accumulator->Put('<'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001248 accumulator->Add(#Name); \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001249 accumulator->Put('>'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001250 break;
1251 STRUCT_LIST(MAKE_STRUCT_CASE)
1252#undef MAKE_STRUCT_CASE
1253 case CODE_TYPE:
1254 accumulator->Add("<Code>");
1255 break;
1256 case ODDBALL_TYPE: {
1257 if (IsUndefined())
1258 accumulator->Add("<undefined>");
1259 else if (IsTheHole())
1260 accumulator->Add("<the hole>");
1261 else if (IsNull())
1262 accumulator->Add("<null>");
1263 else if (IsTrue())
1264 accumulator->Add("<true>");
1265 else if (IsFalse())
1266 accumulator->Add("<false>");
1267 else
1268 accumulator->Add("<Odd Oddball>");
1269 break;
1270 }
1271 case HEAP_NUMBER_TYPE:
1272 accumulator->Add("<Number: ");
1273 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1274 accumulator->Put('>');
1275 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001276 case JS_PROXY_TYPE:
1277 accumulator->Add("<JSProxy>");
1278 break;
1279 case JS_FUNCTION_PROXY_TYPE:
1280 accumulator->Add("<JSFunctionProxy>");
1281 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001282 case FOREIGN_TYPE:
1283 accumulator->Add("<Foreign>");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001285 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1286 accumulator->Add("Cell for ");
1287 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1288 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001289 default:
1290 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1291 break;
1292 }
1293}
1294
1295
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296void HeapObject::Iterate(ObjectVisitor* v) {
1297 // Handle header
1298 IteratePointer(v, kMapOffset);
1299 // Handle object body
1300 Map* m = map();
1301 IterateBody(m->instance_type(), SizeFromMap(m), v);
1302}
1303
1304
1305void HeapObject::IterateBody(InstanceType type, int object_size,
1306 ObjectVisitor* v) {
1307 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1308 // During GC, the map pointer field is encoded.
1309 if (type < FIRST_NONSTRING_TYPE) {
1310 switch (type & kStringRepresentationMask) {
1311 case kSeqStringTag:
1312 break;
1313 case kConsStringTag:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001314 ConsString::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 break;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001316 case kSlicedStringTag:
1317 SlicedString::BodyDescriptor::IterateBody(this, v);
1318 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001319 case kExternalStringTag:
1320 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1321 reinterpret_cast<ExternalAsciiString*>(this)->
1322 ExternalAsciiStringIterateBody(v);
1323 } else {
1324 reinterpret_cast<ExternalTwoByteString*>(this)->
1325 ExternalTwoByteStringIterateBody(v);
1326 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 break;
1328 }
1329 return;
1330 }
1331
1332 switch (type) {
1333 case FIXED_ARRAY_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001334 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001336 case FIXED_DOUBLE_ARRAY_TYPE:
1337 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 case JS_OBJECT_TYPE:
ager@chromium.org32912102009-01-16 10:38:43 +00001339 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340 case JS_VALUE_TYPE:
1341 case JS_ARRAY_TYPE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001342 case JS_SET_TYPE:
1343 case JS_MAP_TYPE:
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001344 case JS_WEAK_MAP_TYPE:
ager@chromium.org236ad962008-09-25 09:45:57 +00001345 case JS_REGEXP_TYPE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001346 case JS_GLOBAL_PROXY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 case JS_GLOBAL_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 case JS_BUILTINS_OBJECT_TYPE:
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001349 case JS_MESSAGE_OBJECT_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001350 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351 break;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001352 case JS_FUNCTION_TYPE:
1353 reinterpret_cast<JSFunction*>(this)
1354 ->JSFunctionIterateBody(object_size, v);
1355 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 case ODDBALL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001357 Oddball::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 break;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001359 case JS_PROXY_TYPE:
1360 JSProxy::BodyDescriptor::IterateBody(this, v);
1361 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001362 case JS_FUNCTION_PROXY_TYPE:
1363 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1364 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001365 case FOREIGN_TYPE:
1366 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367 break;
1368 case MAP_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001369 Map::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 break;
1371 case CODE_TYPE:
1372 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1373 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001374 case JS_GLOBAL_PROPERTY_CELL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001375 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001376 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377 case HEAP_NUMBER_TYPE:
1378 case FILLER_TYPE:
1379 case BYTE_ARRAY_TYPE:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001380 case FREE_SPACE_TYPE:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001381 case EXTERNAL_PIXEL_ARRAY_TYPE:
ager@chromium.org3811b432009-10-28 14:53:37 +00001382 case EXTERNAL_BYTE_ARRAY_TYPE:
1383 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1384 case EXTERNAL_SHORT_ARRAY_TYPE:
1385 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1386 case EXTERNAL_INT_ARRAY_TYPE:
1387 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1388 case EXTERNAL_FLOAT_ARRAY_TYPE:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001389 case EXTERNAL_DOUBLE_ARRAY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001391 case SHARED_FUNCTION_INFO_TYPE:
1392 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001394
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001395#define MAKE_STRUCT_CASE(NAME, Name, name) \
1396 case NAME##_TYPE:
1397 STRUCT_LIST(MAKE_STRUCT_CASE)
1398#undef MAKE_STRUCT_CASE
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001399 StructBodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 break;
1401 default:
1402 PrintF("Unknown type: %d\n", type);
1403 UNREACHABLE();
1404 }
1405}
1406
1407
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408Object* HeapNumber::HeapNumberToBoolean() {
1409 // NaN, +0, and -0 should return the false object
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001410#if __BYTE_ORDER == __LITTLE_ENDIAN
1411 union IeeeDoubleLittleEndianArchType u;
1412#elif __BYTE_ORDER == __BIG_ENDIAN
1413 union IeeeDoubleBigEndianArchType u;
1414#endif
1415 u.d = value();
1416 if (u.bits.exp == 2047) {
1417 // Detect NaN for IEEE double precision floating point.
1418 if ((u.bits.man_low | u.bits.man_high) != 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 return GetHeap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001421 if (u.bits.exp == 0) {
1422 // Detect +0, and -0 for IEEE double precision floating point.
1423 if ((u.bits.man_low | u.bits.man_high) == 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001424 return GetHeap()->false_value();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001425 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001426 return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001427}
1428
1429
whesse@chromium.org023421e2010-12-21 12:19:12 +00001430void HeapNumber::HeapNumberPrint(FILE* out) {
1431 PrintF(out, "%.16g", Number());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001432}
1433
1434
1435void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1436 // The Windows version of vsnprintf can allocate when printing a %g string
1437 // into a buffer that may not be big enough. We don't want random memory
1438 // allocation when producing post-crash stack traces, so we print into a
1439 // buffer that is plenty big enough for any floating point number, then
1440 // print that using vsnprintf (which may truncate but never allocate if
1441 // there is no more space in the buffer).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001442 EmbeddedVector<char, 100> buffer;
1443 OS::SNPrintF(buffer, "%.16g", Number());
1444 accumulator->Add("%s", buffer.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445}
1446
1447
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001448String* JSReceiver::class_name() {
1449 if (IsJSFunction() && IsJSFunctionProxy()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001450 return GetHeap()->function_class_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001451 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452 if (map()->constructor()->IsJSFunction()) {
1453 JSFunction* constructor = JSFunction::cast(map()->constructor());
1454 return String::cast(constructor->shared()->instance_class_name());
1455 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001456 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 return GetHeap()->Object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458}
1459
1460
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001461String* JSReceiver::constructor_name() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001462 if (map()->constructor()->IsJSFunction()) {
1463 JSFunction* constructor = JSFunction::cast(map()->constructor());
1464 String* name = String::cast(constructor->shared()->name());
vegorov@chromium.org42841962010-10-18 11:18:59 +00001465 if (name->length() > 0) return name;
1466 String* inferred_name = constructor->shared()->inferred_name();
1467 if (inferred_name->length() > 0) return inferred_name;
1468 Object* proto = GetPrototype();
1469 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001470 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001471 // TODO(rossberg): what about proxies?
ager@chromium.orga1645e22009-09-09 19:27:10 +00001472 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001473 return GetHeap()->Object_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001474}
1475
1476
lrn@chromium.org303ada72010-10-27 09:33:13 +00001477MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1478 String* name,
1479 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 int index = new_map->PropertyIndexFor(name);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001481 if (map()->unused_property_fields() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482 ASSERT(map()->unused_property_fields() == 0);
1483 int new_unused = new_map->unused_property_fields();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001484 Object* values;
1485 { MaybeObject* maybe_values =
1486 properties()->CopySize(properties()->length() + new_unused + 1);
1487 if (!maybe_values->ToObject(&values)) return maybe_values;
1488 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489 set_properties(FixedArray::cast(values));
1490 }
1491 set_map(new_map);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001492 return FastPropertyAtPut(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493}
1494
1495
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001496static bool IsIdentifier(UnicodeCache* cache,
1497 unibrow::CharacterStream* buffer) {
1498 // Checks whether the buffer contains an identifier (no escape).
1499 if (!buffer->has_more()) return false;
1500 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1501 return false;
1502 }
1503 while (buffer->has_more()) {
1504 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1505 return false;
1506 }
1507 }
1508 return true;
1509}
1510
1511
lrn@chromium.org303ada72010-10-27 09:33:13 +00001512MaybeObject* JSObject::AddFastProperty(String* name,
1513 Object* value,
1514 PropertyAttributes attributes) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001515 ASSERT(!IsJSGlobalProxy());
1516
ager@chromium.org8c51fc92009-04-22 11:54:55 +00001517 // Normalize the object if the name is an actual string (not the
1518 // hidden symbols) and is not a real identifier.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001519 Isolate* isolate = GetHeap()->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001520 StringInputBuffer buffer(name);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001521 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001522 && name != isolate->heap()->hidden_symbol()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001523 Object* obj;
1524 { MaybeObject* maybe_obj =
1525 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1526 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1527 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528 return AddSlowProperty(name, value, attributes);
1529 }
1530
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001531 DescriptorArray* old_descriptors = map()->instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001532 // Compute the new index for new field.
1533 int index = map()->NextFreePropertyIndex();
1534
1535 // Allocate new instance descriptors with (name, index) added
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001536 FieldDescriptor new_field(name, index, attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001537 Object* new_descriptors;
1538 { MaybeObject* maybe_new_descriptors =
1539 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1540 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1541 return maybe_new_descriptors;
1542 }
1543 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001545 // Only allow map transition if the object isn't the global object and there
1546 // is not a transition for the name, or there's a transition for the name but
1547 // it's unrelated to properties.
1548 int descriptor_index = old_descriptors->Search(name);
1549
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001550 // Element transitions are stored in the descriptor for property "", which is
1551 // not a identifier and should have forced a switch to slow properties above.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001552 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001553 old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001554 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001555 old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 bool allow_map_transition =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001557 can_insert_transition &&
1558 (isolate->context()->global_context()->object_function()->map() != map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559
ager@chromium.org7c537e22008-10-16 08:43:32 +00001560 ASSERT(index < map()->inobject_properties() ||
1561 (index - map()->inobject_properties()) < properties()->length() ||
1562 map()->unused_property_fields() == 0);
1563 // Allocate a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001564 Object* r;
1565 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1566 if (!maybe_r->ToObject(&r)) return maybe_r;
1567 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001568 Map* new_map = Map::cast(r);
1569 if (allow_map_transition) {
1570 // Allocate new instance descriptors for the old map with map transition.
1571 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001572 Object* r;
1573 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1574 if (!maybe_r->ToObject(&r)) return maybe_r;
1575 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001576 old_descriptors = DescriptorArray::cast(r);
1577 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578
ager@chromium.org7c537e22008-10-16 08:43:32 +00001579 if (map()->unused_property_fields() == 0) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001580 if (properties()->length() > MaxFastProperties()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001581 Object* obj;
1582 { MaybeObject* maybe_obj =
1583 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1584 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586 return AddSlowProperty(name, value, attributes);
1587 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 // Make room for the new value
lrn@chromium.org303ada72010-10-27 09:33:13 +00001589 Object* values;
1590 { MaybeObject* maybe_values =
1591 properties()->CopySize(properties()->length() + kFieldsAdded);
1592 if (!maybe_values->ToObject(&values)) return maybe_values;
1593 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 set_properties(FixedArray::cast(values));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001595 new_map->set_unused_property_fields(kFieldsAdded - 1);
1596 } else {
1597 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001599 // We have now allocated all the necessary objects.
1600 // All the changes can be applied at once, so they are atomic.
1601 map()->set_instance_descriptors(old_descriptors);
1602 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1603 set_map(new_map);
1604 return FastPropertyAtPut(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605}
1606
1607
lrn@chromium.org303ada72010-10-27 09:33:13 +00001608MaybeObject* JSObject::AddConstantFunctionProperty(
1609 String* name,
1610 JSFunction* function,
1611 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612 // Allocate new instance descriptors with (name, function) added
1613 ConstantFunctionDescriptor d(name, function, attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001614 Object* new_descriptors;
1615 { MaybeObject* maybe_new_descriptors =
1616 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1617 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1618 return maybe_new_descriptors;
1619 }
1620 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621
1622 // Allocate a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001623 Object* new_map;
1624 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1625 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1626 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627
1628 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1629 Map::cast(new_map)->set_instance_descriptors(descriptors);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001630 Map* old_map = map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 set_map(Map::cast(new_map));
1632
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001633 // If the old map is the global object map (from new Object()),
1634 // then transitions are not added to it, so we are done.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001635 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001636 if (old_map == heap->isolate()->context()->global_context()->
1637 object_function()->map()) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001638 return function;
1639 }
1640
1641 // Do not add CONSTANT_TRANSITIONS to global objects
1642 if (IsGlobalObject()) {
1643 return function;
1644 }
1645
1646 // Add a CONSTANT_TRANSITION descriptor to the old map,
1647 // so future assignments to this property on other objects
1648 // of the same type will create a normal field, not a constant function.
1649 // Don't do this for special properties, with non-trival attributes.
1650 if (attributes != NONE) {
1651 return function;
1652 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001653 ConstTransitionDescriptor mark(name, Map::cast(new_map));
lrn@chromium.org303ada72010-10-27 09:33:13 +00001654 { MaybeObject* maybe_new_descriptors =
1655 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1656 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1657 // We have accomplished the main goal, so return success.
1658 return function;
1659 }
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001660 }
1661 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1662
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001663 return function;
1664}
1665
1666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001667// Add property in slow mode
lrn@chromium.org303ada72010-10-27 09:33:13 +00001668MaybeObject* JSObject::AddSlowProperty(String* name,
1669 Object* value,
1670 PropertyAttributes attributes) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001671 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001672 StringDictionary* dict = property_dictionary();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001673 Object* store_value = value;
1674 if (IsGlobalObject()) {
1675 // In case name is an orphaned property reuse the cell.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001676 int entry = dict->FindEntry(name);
1677 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001678 store_value = dict->ValueAt(entry);
1679 JSGlobalPropertyCell::cast(store_value)->set_value(value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001680 // Assign an enumeration index to the property and update
1681 // SetNextEnumerationIndex.
1682 int index = dict->NextEnumerationIndex();
1683 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1684 dict->SetNextEnumerationIndex(index + 1);
1685 dict->SetEntry(entry, name, store_value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001686 return value;
1687 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001688 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001689 { MaybeObject* maybe_store_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001690 heap->AllocateJSGlobalPropertyCell(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001691 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1692 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001693 JSGlobalPropertyCell::cast(store_value)->set_value(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001694 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001695 PropertyDetails details = PropertyDetails(attributes, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001696 Object* result;
1697 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1698 if (!maybe_result->ToObject(&result)) return maybe_result;
1699 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001700 if (dict != result) set_properties(StringDictionary::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001701 return value;
1702}
1703
1704
lrn@chromium.org303ada72010-10-27 09:33:13 +00001705MaybeObject* JSObject::AddProperty(String* name,
1706 Object* value,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001707 PropertyAttributes attributes,
1708 StrictModeFlag strict_mode) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001709 ASSERT(!IsJSGlobalProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001710 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001711 Heap* heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001712 if (!map_of_this->is_extensible()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001713 if (strict_mode == kNonStrictMode) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001714 return value;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001715 } else {
1716 Handle<Object> args[1] = {Handle<String>(name)};
1717 return heap->isolate()->Throw(
1718 *FACTORY->NewTypeError("object_not_extensible",
1719 HandleVector(args, 1)));
1720 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001721 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001722 if (HasFastProperties()) {
1723 // Ensure the descriptor array does not get too big.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001724 if (map_of_this->instance_descriptors()->number_of_descriptors() <
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001725 DescriptorArray::kMaxNumberOfDescriptors) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001726 if (value->IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727 return AddConstantFunctionProperty(name,
1728 JSFunction::cast(value),
1729 attributes);
1730 } else {
1731 return AddFastProperty(name, value, attributes);
1732 }
1733 } else {
1734 // Normalize the object to prevent very large instance descriptors.
1735 // This eliminates unwanted N^2 allocation and lookup behavior.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001736 Object* obj;
1737 { MaybeObject* maybe_obj =
1738 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1739 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1740 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741 }
1742 }
1743 return AddSlowProperty(name, value, attributes);
1744}
1745
1746
lrn@chromium.org303ada72010-10-27 09:33:13 +00001747MaybeObject* JSObject::SetPropertyPostInterceptor(
1748 String* name,
1749 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001750 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001751 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001752 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001753 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001754 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00001755 if (result.IsFound()) {
1756 // An existing property, a map transition or a null descriptor was
1757 // found. Use set property to handle all these cases.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001758 return SetProperty(&result, name, value, attributes, strict_mode);
ager@chromium.org5c838252010-02-19 08:53:10 +00001759 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001760 bool found = false;
1761 MaybeObject* result_object;
1762 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
1763 value,
1764 attributes,
1765 &found,
1766 strict_mode);
1767 if (found) return result_object;
ager@chromium.org5c838252010-02-19 08:53:10 +00001768 // Add a new real property.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001769 return AddProperty(name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001770}
1771
1772
lrn@chromium.org303ada72010-10-27 09:33:13 +00001773MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1774 Object* value,
1775 PropertyAttributes attributes) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001776 StringDictionary* dictionary = property_dictionary();
1777 int old_index = dictionary->FindEntry(name);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001778 int new_enumeration_index = 0; // 0 means "Use the next available index."
1779 if (old_index != -1) {
1780 // All calls to ReplaceSlowProperty have had all transitions removed.
rossberg@chromium.org994edf62012-02-06 10:12:55 +00001781 ASSERT(!dictionary->ContainsTransition(old_index));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001782 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1783 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001784
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001785 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001786 return SetNormalizedProperty(name, value, new_details);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001787}
1788
ager@chromium.org6141cbe2009-11-20 12:14:52 +00001789
lrn@chromium.org303ada72010-10-27 09:33:13 +00001790MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
ager@chromium.org7c537e22008-10-16 08:43:32 +00001791 String* name,
1792 Object* new_value,
1793 PropertyAttributes attributes) {
1794 Map* old_map = map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001795 Object* result;
1796 { MaybeObject* maybe_result =
1797 ConvertDescriptorToField(name, new_value, attributes);
1798 if (!maybe_result->ToObject(&result)) return maybe_result;
1799 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001800 // If we get to this point we have succeeded - do not return failure
1801 // after this point. Later stuff is optional.
1802 if (!HasFastProperties()) {
1803 return result;
1804 }
1805 // Do not add transitions to the map of "new Object()".
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001806 if (map() == GetIsolate()->context()->global_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001807 object_function()->map()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001808 return result;
1809 }
1810
1811 MapTransitionDescriptor transition(name,
1812 map(),
1813 attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001814 Object* new_descriptors;
1815 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1816 CopyInsert(&transition, KEEP_TRANSITIONS);
1817 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1818 return result; // Yes, return _result_.
1819 }
1820 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001821 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1822 return result;
1823}
1824
1825
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1827 Object* new_value,
1828 PropertyAttributes attributes) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001829 if (map()->unused_property_fields() == 0 &&
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001830 properties()->length() > MaxFastProperties()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001831 Object* obj;
1832 { MaybeObject* maybe_obj =
1833 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1834 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1835 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001836 return ReplaceSlowProperty(name, new_value, attributes);
1837 }
1838
1839 int index = map()->NextFreePropertyIndex();
1840 FieldDescriptor new_field(name, index, attributes);
1841 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001842 Object* descriptors_unchecked;
1843 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1844 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1845 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1846 return maybe_descriptors_unchecked;
1847 }
1848 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001849 DescriptorArray* new_descriptors =
1850 DescriptorArray::cast(descriptors_unchecked);
1851
1852 // Make a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001853 Object* new_map_unchecked;
1854 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1855 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1856 return maybe_new_map_unchecked;
1857 }
1858 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001859 Map* new_map = Map::cast(new_map_unchecked);
1860 new_map->set_instance_descriptors(new_descriptors);
1861
1862 // Make new properties array if necessary.
1863 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1864 int new_unused_property_fields = map()->unused_property_fields() - 1;
1865 if (map()->unused_property_fields() == 0) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001866 new_unused_property_fields = kFieldsAdded - 1;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001867 Object* new_properties_object;
1868 { MaybeObject* maybe_new_properties_object =
1869 properties()->CopySize(properties()->length() + kFieldsAdded);
1870 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1871 return maybe_new_properties_object;
1872 }
1873 }
1874 new_properties = FixedArray::cast(new_properties_object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001875 }
1876
1877 // Update pointers to commit changes.
1878 // Object points to the new map.
1879 new_map->set_unused_property_fields(new_unused_property_fields);
1880 set_map(new_map);
1881 if (new_properties) {
1882 set_properties(FixedArray::cast(new_properties));
1883 }
1884 return FastPropertyAtPut(index, new_value);
1885}
1886
1887
1888
lrn@chromium.org303ada72010-10-27 09:33:13 +00001889MaybeObject* JSObject::SetPropertyWithInterceptor(
1890 String* name,
1891 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001892 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001893 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001894 Isolate* isolate = GetIsolate();
1895 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 Handle<JSObject> this_handle(this);
1897 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001898 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001899 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1900 if (!interceptor->setter()->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001901 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1902 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001903 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904 v8::NamedPropertySetter setter =
1905 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1906 v8::Handle<v8::Value> result;
1907 {
1908 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001909 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001910 Handle<Object> value_unhole(value->IsTheHole() ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001911 isolate->heap()->undefined_value() :
1912 value,
1913 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914 result = setter(v8::Utils::ToLocal(name_handle),
1915 v8::Utils::ToLocal(value_unhole),
1916 info);
1917 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001918 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 if (!result.IsEmpty()) return *value_handle;
1920 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001921 MaybeObject* raw_result =
1922 this_handle->SetPropertyPostInterceptor(*name_handle,
1923 *value_handle,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001924 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001925 strict_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001926 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001927 return raw_result;
1928}
1929
1930
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001931Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
1932 Handle<String> key,
1933 Handle<Object> value,
1934 PropertyAttributes attributes,
1935 StrictModeFlag strict_mode) {
1936 CALL_HEAP_FUNCTION(object->GetIsolate(),
1937 object->SetProperty(*key, *value, attributes, strict_mode),
1938 Object);
1939}
1940
1941
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001942MaybeObject* JSReceiver::SetProperty(String* name,
1943 Object* value,
1944 PropertyAttributes attributes,
1945 StrictModeFlag strict_mode) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001946 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947 LocalLookup(name, &result);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001948 return SetProperty(&result, name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949}
1950
1951
lrn@chromium.org303ada72010-10-27 09:33:13 +00001952MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1953 String* name,
1954 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001955 JSObject* holder,
1956 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001957 Isolate* isolate = GetIsolate();
1958 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959
1960 // We should never get here to initialize a const with the hole
1961 // value since a const declaration would conflict with the setter.
1962 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001963 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001964
1965 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001966 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001967 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001968 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001969 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001970 reinterpret_cast<AccessorDescriptor*>(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001971 Foreign::cast(structure)->foreign_address());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001972 MaybeObject* obj = (callback->setter)(this, value, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001973 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001974 if (obj->IsFailure()) return obj;
1975 return *value_handle;
1976 }
1977
1978 if (structure->IsAccessorInfo()) {
1979 // api style callbacks
1980 AccessorInfo* data = AccessorInfo::cast(structure);
1981 Object* call_obj = data->setter();
1982 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1983 if (call_fun == NULL) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1986 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001987 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001988 {
1989 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001990 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991 call_fun(v8::Utils::ToLocal(key),
1992 v8::Utils::ToLocal(value_handle),
1993 info);
1994 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001995 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001996 return *value_handle;
1997 }
1998
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001999 if (structure->IsAccessorPair()) {
2000 Object* setter = AccessorPair::cast(structure)->setter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002001 if (setter->IsSpecFunction()) {
2002 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2003 return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002004 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002005 if (strict_mode == kNonStrictMode) {
2006 return value;
2007 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002009 Handle<Object> holder_handle(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002010 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002011 return isolate->Throw(
2012 *isolate->factory()->NewTypeError("no_setter_in_callback",
2013 HandleVector(args, 2)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002015 }
2016
2017 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002018 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002019}
2020
2021
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002022MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
2023 Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002024 Isolate* isolate = GetIsolate();
2025 Handle<Object> value_handle(value, isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002026 Handle<JSReceiver> fun(setter, isolate);
2027 Handle<JSReceiver> self(this, isolate);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002028#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002029 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002030 // Handle stepping into a setter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002031 // TODO(rossberg): should this apply to getters that are function proxies?
2032 if (debug->StepInActive() && fun->IsJSFunction()) {
2033 debug->HandleStepIn(
2034 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002035 }
2036#endif
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002037 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002038 Handle<Object> argv[] = { value_handle };
2039 Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002040 // Check for pending exception and return the result.
2041 if (has_pending_exception) return Failure::Exception();
2042 return *value_handle;
2043}
2044
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002045
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002046void JSObject::LookupCallbackSetterInPrototypes(String* name,
2047 LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002048 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 pt != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051 pt = pt->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002052 if (pt->IsJSProxy()) {
2053 return result->HandlerResult(JSProxy::cast(pt));
2054 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002055 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002056 if (result->IsProperty()) {
whesse@chromium.org030d38e2011-07-13 13:23:34 +00002057 if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
2058 // Found non-callback or read-only callback, stop looking.
2059 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060 }
2061 }
2062 result->NotFound();
2063}
2064
2065
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002066MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
2067 uint32_t index,
2068 Object* value,
2069 bool* found,
2070 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002071 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002072 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002073 pt != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002074 pt = pt->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002075 if (pt->IsJSProxy()) {
2076 String* name;
2077 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
2078 if (!maybe->To<String>(&name)) {
2079 *found = true; // Force abort
2080 return maybe;
2081 }
2082 return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
2083 name, value, NONE, strict_mode, found);
2084 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002085 if (!JSObject::cast(pt)->HasDictionaryElements()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002086 continue;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002087 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002088 SeededNumberDictionary* dictionary =
2089 JSObject::cast(pt)->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002090 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002091 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002092 PropertyDetails details = dictionary->DetailsAt(entry);
2093 if (details.type() == CALLBACKS) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002094 *found = true;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002095 return SetElementWithCallback(dictionary->ValueAt(entry),
2096 index,
2097 value,
2098 JSObject::cast(pt),
2099 strict_mode);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002100 }
2101 }
2102 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002103 *found = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002104 return heap->the_hole_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002105}
2106
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002107MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
2108 String* name,
2109 Object* value,
2110 PropertyAttributes attributes,
2111 bool* found,
2112 StrictModeFlag strict_mode) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002113 Heap* heap = GetHeap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002114 // We could not find a local property so let's check whether there is an
2115 // accessor that wants to handle the property.
2116 LookupResult accessor_result(heap->isolate());
2117 LookupCallbackSetterInPrototypes(name, &accessor_result);
2118 if (accessor_result.IsFound()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002119 *found = true;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002120 if (accessor_result.type() == CALLBACKS) {
2121 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002122 name,
2123 value,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002124 accessor_result.holder(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002125 strict_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002126 } else if (accessor_result.type() == HANDLER) {
2127 // There is a proxy in the prototype chain. Invoke its
2128 // getPropertyDescriptor trap.
2129 bool found = false;
2130 // SetPropertyWithHandlerIfDefiningSetter can cause GC,
2131 // make sure to use the handlified references after calling
2132 // the function.
2133 Handle<JSObject> self(this);
2134 Handle<String> hname(name);
2135 Handle<Object> hvalue(value);
2136 MaybeObject* result =
2137 accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
2138 name, value, attributes, strict_mode, &found);
2139 if (found) return result;
2140 // The proxy does not define the property as an accessor.
2141 // Consequently, it has no effect on setting the receiver.
2142 return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002143 }
2144 }
2145 *found = false;
2146 return heap->the_hole_value();
2147}
2148
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002149
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002150void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
2151 DescriptorArray* descriptors = map()->instance_descriptors();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002152 int number = descriptors->SearchWithCache(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002153 if (number != DescriptorArray::kNotFound) {
2154 result->DescriptorResult(this, descriptors->GetDetails(number), number);
2155 } else {
2156 result->NotFound();
2157 }
2158}
2159
2160
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002161void Map::LookupInDescriptors(JSObject* holder,
2162 String* name,
2163 LookupResult* result) {
2164 DescriptorArray* descriptors = instance_descriptors();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002165 DescriptorLookupCache* cache =
2166 GetHeap()->isolate()->descriptor_lookup_cache();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002167 int number = cache->Lookup(descriptors, name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002168 if (number == DescriptorLookupCache::kAbsent) {
2169 number = descriptors->Search(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002170 cache->Update(descriptors, name, number);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002171 }
2172 if (number != DescriptorArray::kNotFound) {
2173 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
2174 } else {
2175 result->NotFound();
2176 }
2177}
2178
2179
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002180static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2181 ASSERT(!map.is_null());
2182 for (int i = 0; i < maps->length(); ++i) {
2183 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2184 }
2185 return false;
2186}
2187
2188
2189template <class T>
2190static Handle<T> MaybeNull(T* p) {
2191 if (p == NULL) return Handle<T>::null();
2192 return Handle<T>(p);
2193}
2194
2195
2196Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
2197 ElementsKind elms_kind = elements_kind();
2198 if (elms_kind == FAST_DOUBLE_ELEMENTS) {
2199 bool dummy = true;
2200 Handle<Map> fast_map =
2201 MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
2202 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2203 return fast_map;
2204 }
2205 return Handle<Map>::null();
2206 }
2207 if (elms_kind == FAST_SMI_ONLY_ELEMENTS) {
2208 bool dummy = true;
2209 Handle<Map> double_map =
2210 MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy));
2211 // In the current implementation, if the DOUBLE map doesn't exist, the
2212 // FAST map can't exist either.
2213 if (double_map.is_null()) return Handle<Map>::null();
2214 Handle<Map> fast_map =
2215 MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2216 &dummy));
2217 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2218 return fast_map;
2219 }
2220 if (ContainsMap(candidates, double_map)) return double_map;
2221 }
2222 return Handle<Map>::null();
2223}
2224
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002225static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
2226 ElementsKind elements_kind) {
2227 if (descriptor_contents->IsMap()) {
2228 Map* map = Map::cast(descriptor_contents);
2229 if (map->elements_kind() == elements_kind) {
2230 return map;
2231 }
2232 return NULL;
2233 }
2234
2235 FixedArray* map_array = FixedArray::cast(descriptor_contents);
2236 for (int i = 0; i < map_array->length(); ++i) {
2237 Object* current = map_array->get(i);
2238 // Skip undefined slots, they are sentinels for reclaimed maps.
2239 if (!current->IsUndefined()) {
2240 Map* current_map = Map::cast(map_array->get(i));
2241 if (current_map->elements_kind() == elements_kind) {
2242 return current_map;
2243 }
2244 }
2245 }
2246
2247 return NULL;
2248}
2249
2250
2251static MaybeObject* AddElementsTransitionMapToDescriptor(
2252 Object* descriptor_contents,
2253 Map* new_map) {
2254 // Nothing was in the descriptor for an ELEMENTS_TRANSITION,
2255 // simply add the map.
2256 if (descriptor_contents == NULL) {
2257 return new_map;
2258 }
2259
2260 // There was already a map in the descriptor, create a 2-element FixedArray
2261 // to contain the existing map plus the new one.
2262 FixedArray* new_array;
2263 Heap* heap = new_map->GetHeap();
2264 if (descriptor_contents->IsMap()) {
2265 // Must tenure, DescriptorArray expects no new-space objects.
2266 MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED);
2267 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2268 return maybe_new_array;
2269 }
2270 new_array->set(0, descriptor_contents);
2271 new_array->set(1, new_map);
2272 return new_array;
2273 }
2274
2275 // The descriptor already contained a list of maps for different ElementKinds
2276 // of ELEMENTS_TRANSITION, first check the existing array for an undefined
2277 // slot, and if that's not available, create a FixedArray to hold the existing
2278 // maps plus the new one and fill it in.
2279 FixedArray* array = FixedArray::cast(descriptor_contents);
2280 for (int i = 0; i < array->length(); ++i) {
2281 if (array->get(i)->IsUndefined()) {
2282 array->set(i, new_map);
2283 return array;
2284 }
2285 }
2286
2287 // Must tenure, DescriptorArray expects no new-space objects.
2288 MaybeObject* maybe_new_array =
2289 heap->AllocateFixedArray(array->length() + 1, TENURED);
2290 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2291 return maybe_new_array;
2292 }
2293 int i = 0;
2294 while (i < array->length()) {
2295 new_array->set(i, array->get(i));
2296 ++i;
2297 }
2298 new_array->set(i, new_map);
2299 return new_array;
2300}
2301
2302
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002303String* Map::elements_transition_sentinel_name() {
2304 return GetHeap()->empty_symbol();
2305}
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002306
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002307
2308Object* Map::GetDescriptorContents(String* sentinel_name,
2309 bool* safe_to_add_transition) {
2310 // Get the cached index for the descriptors lookup, or find and cache it.
2311 DescriptorArray* descriptors = instance_descriptors();
2312 DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache();
2313 int index = cache->Lookup(descriptors, sentinel_name);
2314 if (index == DescriptorLookupCache::kAbsent) {
2315 index = descriptors->Search(sentinel_name);
2316 cache->Update(descriptors, sentinel_name, index);
2317 }
2318 // If the transition already exists, return its descriptor.
2319 if (index != DescriptorArray::kNotFound) {
2320 PropertyDetails details(descriptors->GetDetails(index));
2321 if (details.type() == ELEMENTS_TRANSITION) {
2322 return descriptors->GetValue(index);
2323 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002324 if (safe_to_add_transition != NULL) {
2325 *safe_to_add_transition = false;
2326 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002327 }
2328 }
2329 return NULL;
2330}
2331
2332
2333Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
2334 bool* safe_to_add_transition) {
2335 // Special case: indirect SMI->FAST transition (cf. comment in
2336 // AddElementsTransition()).
2337 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2338 elements_kind == FAST_ELEMENTS) {
2339 Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
2340 safe_to_add_transition);
2341 if (double_map == NULL) return double_map;
2342 return double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2343 safe_to_add_transition);
2344 }
2345 Object* descriptor_contents = GetDescriptorContents(
2346 elements_transition_sentinel_name(), safe_to_add_transition);
2347 if (descriptor_contents != NULL) {
2348 Map* maybe_transition_map =
2349 GetElementsTransitionMapFromDescriptor(descriptor_contents,
2350 elements_kind);
2351 ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
2352 return maybe_transition_map;
2353 }
2354 return NULL;
2355}
2356
2357
2358MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
2359 Map* transitioned_map) {
2360 // The map transition graph should be a tree, therefore the transition
2361 // from SMI to FAST elements is not done directly, but by going through
2362 // DOUBLE elements first.
2363 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2364 elements_kind == FAST_ELEMENTS) {
2365 bool safe_to_add = true;
2366 Map* double_map = this->LookupElementsTransitionMap(
2367 FAST_DOUBLE_ELEMENTS, &safe_to_add);
2368 // This method is only called when safe_to_add_transition has been found
2369 // to be true earlier.
2370 ASSERT(safe_to_add);
2371
2372 if (double_map == NULL) {
2373 MaybeObject* maybe_map = this->CopyDropTransitions();
2374 if (!maybe_map->To(&double_map)) return maybe_map;
2375 double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
2376 MaybeObject* maybe_double_transition = this->AddElementsTransition(
2377 FAST_DOUBLE_ELEMENTS, double_map);
2378 if (maybe_double_transition->IsFailure()) return maybe_double_transition;
2379 }
2380 return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map);
2381 }
2382
2383 bool safe_to_add_transition = true;
2384 Object* descriptor_contents = GetDescriptorContents(
2385 elements_transition_sentinel_name(), &safe_to_add_transition);
2386 // This method is only called when safe_to_add_transition has been found
2387 // to be true earlier.
2388 ASSERT(safe_to_add_transition);
2389 MaybeObject* maybe_new_contents =
2390 AddElementsTransitionMapToDescriptor(descriptor_contents,
2391 transitioned_map);
2392 Object* new_contents;
2393 if (!maybe_new_contents->ToObject(&new_contents)) {
2394 return maybe_new_contents;
2395 }
2396
2397 ElementsTransitionDescriptor desc(elements_transition_sentinel_name(),
2398 new_contents);
2399 Object* new_descriptors;
2400 MaybeObject* maybe_new_descriptors =
2401 instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS);
2402 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2403 return maybe_new_descriptors;
2404 }
2405 set_instance_descriptors(DescriptorArray::cast(new_descriptors));
2406 return this;
2407}
2408
2409
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002410Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
2411 ElementsKind to_kind) {
2412 Isolate* isolate = object->GetIsolate();
2413 CALL_HEAP_FUNCTION(isolate,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002414 object->GetElementsTransitionMap(isolate, to_kind),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002415 Map);
2416}
2417
2418
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002419MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002420 Map* current_map = map();
2421 ElementsKind from_kind = current_map->elements_kind();
2422
2423 if (from_kind == to_kind) return current_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002424
2425 // Only objects with FastProperties can have DescriptorArrays and can track
2426 // element-related maps. Also don't add descriptors to maps that are shared.
2427 bool safe_to_add_transition = HasFastProperties() &&
2428 !current_map->IsUndefined() &&
2429 !current_map->is_shared();
2430
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002431 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002432 // with elements that switch back and forth between dictionary and fast
2433 // element mode.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002434 if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002435 safe_to_add_transition = false;
2436 }
2437
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002438 if (safe_to_add_transition) {
2439 // It's only safe to manipulate the descriptor array if it would be
2440 // safe to add a transition.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002441 Map* maybe_transition_map = current_map->LookupElementsTransitionMap(
2442 to_kind, &safe_to_add_transition);
2443 if (maybe_transition_map != NULL) {
2444 return maybe_transition_map;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002445 }
2446 }
2447
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002448 Map* new_map = NULL;
2449
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002450 // No transition to an existing map for the given ElementsKind. Make a new
2451 // one.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002452 { MaybeObject* maybe_map = current_map->CopyDropTransitions();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002453 if (!maybe_map->To(&new_map)) return maybe_map;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002454 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002455
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002456 new_map->set_elements_kind(to_kind);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002457
2458 // Only remember the map transition if the object's map is NOT equal to the
2459 // global object_function's map and there is not an already existing
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002460 // non-matching element transition.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002461 Context* global_context = GetIsolate()->context()->global_context();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002462 bool allow_map_transition = safe_to_add_transition &&
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002463 (global_context->object_function()->map() != map());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002464 if (allow_map_transition) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002465 MaybeObject* maybe_transition =
2466 current_map->AddElementsTransition(to_kind, new_map);
2467 if (maybe_transition->IsFailure()) return maybe_transition;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002468 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002469 return new_map;
2470}
2471
2472
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002473void JSObject::LocalLookupRealNamedProperty(String* name,
2474 LookupResult* result) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002475 if (IsJSGlobalProxy()) {
2476 Object* proto = GetPrototype();
2477 if (proto->IsNull()) return result->NotFound();
2478 ASSERT(proto->IsJSGlobalObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002479 // A GlobalProxy's prototype should always be a proper JSObject.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002480 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2481 }
2482
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002483 if (HasFastProperties()) {
2484 LookupInDescriptor(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002485 if (result->IsFound()) {
2486 // A property, a map transition or a null descriptor was found.
2487 // We return all of these result types because
2488 // LocalLookupRealNamedProperty is used when setting properties
2489 // where map transitions and null descriptors are handled.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002490 ASSERT(result->holder() == this && result->type() != NORMAL);
2491 // Disallow caching for uninitialized constants. These can only
2492 // occur as fields.
2493 if (result->IsReadOnly() && result->type() == FIELD &&
ager@chromium.org7c537e22008-10-16 08:43:32 +00002494 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002495 result->DisallowCaching();
2496 }
2497 return;
2498 }
2499 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002500 int entry = property_dictionary()->FindEntry(name);
2501 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002502 Object* value = property_dictionary()->ValueAt(entry);
2503 if (IsGlobalObject()) {
2504 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2505 if (d.IsDeleted()) {
2506 result->NotFound();
2507 return;
2508 }
2509 value = JSGlobalPropertyCell::cast(value)->value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002510 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002511 // Make sure to disallow caching for uninitialized constants
2512 // found in the dictionary-mode objects.
2513 if (value->IsTheHole()) result->DisallowCaching();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002514 result->DictionaryResult(this, entry);
2515 return;
2516 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002517 }
2518 result->NotFound();
2519}
2520
2521
2522void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2523 LocalLookupRealNamedProperty(name, result);
2524 if (result->IsProperty()) return;
2525
2526 LookupRealNamedPropertyInPrototypes(name, result);
2527}
2528
2529
2530void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2531 LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002532 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002533 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002534 pt != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002535 pt = JSObject::cast(pt)->GetPrototype()) {
2536 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002537 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002538 }
2539 result->NotFound();
2540}
2541
2542
2543// We only need to deal with CALLBACKS and INTERCEPTORS
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002544MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2545 LookupResult* result,
2546 String* name,
2547 Object* value,
2548 bool check_prototype,
2549 StrictModeFlag strict_mode) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002550 if (check_prototype && !result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002551 LookupCallbackSetterInPrototypes(name, result);
2552 }
2553
2554 if (result->IsProperty()) {
2555 if (!result->IsReadOnly()) {
2556 switch (result->type()) {
2557 case CALLBACKS: {
2558 Object* obj = result->GetCallbackObject();
2559 if (obj->IsAccessorInfo()) {
2560 AccessorInfo* info = AccessorInfo::cast(obj);
2561 if (info->all_can_write()) {
2562 return SetPropertyWithCallback(result->GetCallbackObject(),
2563 name,
2564 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002565 result->holder(),
2566 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002567 }
2568 }
2569 break;
2570 }
2571 case INTERCEPTOR: {
2572 // Try lookup real named properties. Note that only property can be
2573 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002574 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002575 LookupRealNamedProperty(name, &r);
2576 if (r.IsProperty()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002577 return SetPropertyWithFailedAccessCheck(&r,
2578 name,
2579 value,
2580 check_prototype,
2581 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002582 }
2583 break;
2584 }
2585 default: {
2586 break;
2587 }
2588 }
2589 }
2590 }
2591
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002592 Isolate* isolate = GetIsolate();
2593 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002594 Handle<Object> value_handle(value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002595 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002596 return *value_handle;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002597}
2598
2599
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002600MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2601 String* key,
2602 Object* value,
2603 PropertyAttributes attributes,
2604 StrictModeFlag strict_mode) {
2605 if (result->IsFound() && result->type() == HANDLER) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002606 return result->proxy()->SetPropertyWithHandler(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002607 key, value, attributes, strict_mode);
2608 } else {
2609 return JSObject::cast(this)->SetPropertyForResult(
2610 result, key, value, attributes, strict_mode);
2611 }
2612}
2613
2614
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002615bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2616 Isolate* isolate = GetIsolate();
2617 HandleScope scope(isolate);
2618 Handle<Object> receiver(this);
2619 Handle<Object> name(name_raw);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002620
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002621 Handle<Object> args[] = { name };
2622 Handle<Object> result = CallTrap(
2623 "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002624 if (isolate->has_pending_exception()) return Failure::Exception();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002625
2626 return result->ToBoolean()->IsTrue();
2627}
2628
2629
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002630MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2631 String* name_raw,
2632 Object* value_raw,
2633 PropertyAttributes attributes,
2634 StrictModeFlag strict_mode) {
2635 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002636 HandleScope scope(isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002637 Handle<Object> receiver(this);
2638 Handle<Object> name(name_raw);
2639 Handle<Object> value(value_raw);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002640
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002641 Handle<Object> args[] = { receiver, name, value };
2642 CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002643 if (isolate->has_pending_exception()) return Failure::Exception();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002644
2645 return *value;
2646}
2647
2648
2649MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
2650 String* name_raw,
2651 Object* value_raw,
2652 PropertyAttributes attributes,
2653 StrictModeFlag strict_mode,
2654 bool* found) {
2655 *found = true; // except where defined otherwise...
2656 Isolate* isolate = GetHeap()->isolate();
2657 Handle<JSProxy> proxy(this);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002658 Handle<Object> handler(this->handler()); // Trap might morph proxy.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002659 Handle<String> name(name_raw);
2660 Handle<Object> value(value_raw);
2661 Handle<Object> args[] = { name };
2662 Handle<Object> result = proxy->CallTrap(
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002663 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002664 if (isolate->has_pending_exception()) return Failure::Exception();
2665
2666 if (!result->IsUndefined()) {
2667 // The proxy handler cares about this property.
2668 // Check whether it is virtualized as an accessor.
2669 // Emulate [[GetProperty]] semantics for proxies.
2670 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002671 Handle<Object> argv[] = { result };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002672 Handle<Object> desc =
2673 Execution::Call(isolate->to_complete_property_descriptor(), result,
2674 ARRAY_SIZE(argv), argv, &has_pending_exception);
2675 if (has_pending_exception) return Failure::Exception();
2676
2677 Handle<String> conf_name =
2678 isolate->factory()->LookupAsciiSymbol("configurable_");
2679 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
2680 ASSERT(!isolate->has_pending_exception());
2681 if (configurable->IsFalse()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002682 Handle<String> trap =
2683 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2684 Handle<Object> args[] = { handler, trap, name };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002685 Handle<Object> error = isolate->factory()->NewTypeError(
2686 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2687 return isolate->Throw(*error);
2688 }
2689 ASSERT(configurable->IsTrue());
2690
2691 // Check for AccessorDescriptor.
2692 Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
2693 Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
2694 ASSERT(!isolate->has_pending_exception());
2695 if (!setter->IsUndefined()) {
2696 // We have a setter -- invoke it.
2697 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2698 return proxy->SetPropertyWithDefinedSetter(
2699 JSReceiver::cast(*setter), *value);
2700 } else {
2701 Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
2702 Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
2703 ASSERT(!isolate->has_pending_exception());
2704 if (!getter->IsUndefined()) {
2705 // We have a getter but no setter -- the property may not be
2706 // written. In strict mode, throw an error.
2707 if (strict_mode == kNonStrictMode) return *value;
2708 Handle<Object> args[] = { name, proxy };
2709 Handle<Object> error = isolate->factory()->NewTypeError(
2710 "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
2711 return isolate->Throw(*error);
2712 }
2713 }
2714 // Fall-through.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002715 }
2716
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002717 // The proxy does not define the property as an accessor.
2718 *found = false;
ager@chromium.org04921a82011-06-27 13:21:41 +00002719 return *value;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002720}
2721
2722
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002723MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2724 String* name_raw, DeleteMode mode) {
2725 Isolate* isolate = GetIsolate();
2726 HandleScope scope(isolate);
2727 Handle<Object> receiver(this);
2728 Handle<Object> name(name_raw);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002729
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002730 Handle<Object> args[] = { name };
2731 Handle<Object> result = CallTrap(
2732 "delete", Handle<Object>(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002733 if (isolate->has_pending_exception()) return Failure::Exception();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002734
2735 Object* bool_result = result->ToBoolean();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002736 if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
2737 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2738 Handle<Object> args[] = { Handle<Object>(handler()), trap_name };
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002739 Handle<Object> error = isolate->factory()->NewTypeError(
2740 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2741 isolate->Throw(*error);
2742 return Failure::Exception();
2743 }
2744 return bool_result;
2745}
2746
2747
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002748MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
2749 uint32_t index,
2750 DeleteMode mode) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002751 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002752 HandleScope scope(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002753 Handle<String> name = isolate->factory()->Uint32ToString(index);
2754 return JSProxy::DeletePropertyWithHandler(*name, mode);
2755}
2756
2757
2758MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2759 JSReceiver* receiver_raw,
2760 String* name_raw) {
2761 Isolate* isolate = GetIsolate();
2762 HandleScope scope(isolate);
2763 Handle<JSProxy> proxy(this);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002764 Handle<Object> handler(this->handler()); // Trap might morph proxy.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002765 Handle<JSReceiver> receiver(receiver_raw);
2766 Handle<Object> name(name_raw);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002767
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002768 Handle<Object> args[] = { name };
2769 Handle<Object> result = CallTrap(
2770 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002771 if (isolate->has_pending_exception()) return NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002772
2773 if (result->IsUndefined()) return ABSENT;
2774
2775 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002776 Handle<Object> argv[] = { result };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002777 Handle<Object> desc =
2778 Execution::Call(isolate->to_complete_property_descriptor(), result,
2779 ARRAY_SIZE(argv), argv, &has_pending_exception);
2780 if (has_pending_exception) return NONE;
2781
2782 // Convert result to PropertyAttributes.
2783 Handle<String> enum_n = isolate->factory()->LookupAsciiSymbol("enumerable");
2784 Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_n));
2785 if (isolate->has_pending_exception()) return NONE;
2786 Handle<String> conf_n = isolate->factory()->LookupAsciiSymbol("configurable");
2787 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_n));
2788 if (isolate->has_pending_exception()) return NONE;
2789 Handle<String> writ_n = isolate->factory()->LookupAsciiSymbol("writable");
2790 Handle<Object> writable(v8::internal::GetProperty(desc, writ_n));
2791 if (isolate->has_pending_exception()) return NONE;
2792
2793 if (configurable->IsFalse()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002794 Handle<String> trap =
2795 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2796 Handle<Object> args[] = { handler, trap, name };
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002797 Handle<Object> error = isolate->factory()->NewTypeError(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002798 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002799 isolate->Throw(*error);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002800 return NONE;
2801 }
2802
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002803 int attributes = NONE;
2804 if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM;
2805 if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE;
2806 if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY;
2807 return static_cast<PropertyAttributes>(attributes);
2808}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002809
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002810
2811MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
2812 JSReceiver* receiver,
2813 uint32_t index) {
2814 Isolate* isolate = GetIsolate();
2815 HandleScope scope(isolate);
2816 Handle<String> name = isolate->factory()->Uint32ToString(index);
2817 return GetPropertyAttributeWithHandler(receiver, *name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002818}
2819
2820
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002821void JSProxy::Fix() {
2822 Isolate* isolate = GetIsolate();
2823 HandleScope scope(isolate);
2824 Handle<JSProxy> self(this);
2825
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002826 // Save identity hash.
2827 MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
2828
lrn@chromium.org34e60782011-09-15 07:25:40 +00002829 if (IsJSFunctionProxy()) {
2830 isolate->factory()->BecomeJSFunction(self);
2831 // Code will be set on the JavaScript side.
2832 } else {
2833 isolate->factory()->BecomeJSObject(self);
2834 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00002835 ASSERT(self->IsJSObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002836
2837 // Inherit identity, if it was present.
2838 Object* hash;
2839 if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
2840 Handle<JSObject> new_self(JSObject::cast(*self));
2841 isolate->factory()->SetIdentityHash(new_self, hash);
2842 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002843}
2844
2845
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002846MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
2847 Handle<Object> derived,
2848 int argc,
2849 Handle<Object> argv[]) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002850 Isolate* isolate = GetIsolate();
2851 Handle<Object> handler(this->handler());
2852
2853 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol(name);
2854 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2855 if (isolate->has_pending_exception()) return trap;
2856
2857 if (trap->IsUndefined()) {
2858 if (derived.is_null()) {
2859 Handle<Object> args[] = { handler, trap_name };
2860 Handle<Object> error = isolate->factory()->NewTypeError(
2861 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2862 isolate->Throw(*error);
2863 return Handle<Object>();
2864 }
2865 trap = Handle<Object>(derived);
2866 }
2867
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002868 bool threw;
2869 return Execution::Call(trap, handler, argc, argv, &threw);
2870}
2871
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002872
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002873MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
whesse@chromium.org030d38e2011-07-13 13:23:34 +00002874 String* name,
2875 Object* value,
2876 PropertyAttributes attributes,
2877 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002878 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002879 // Make sure that the top context does not change when doing callbacks or
2880 // interceptor calls.
2881 AssertNoContextChange ncc;
2882
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002883 // Optimization for 2-byte strings often used as keys in a decompression
2884 // dictionary. We make these short keys into symbols to avoid constantly
2885 // reallocating them.
2886 if (!name->IsSymbol() && name->length() <= 2) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002887 Object* symbol_version;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002888 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002889 if (maybe_symbol_version->ToObject(&symbol_version)) {
2890 name = String::cast(symbol_version);
2891 }
2892 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002893 }
2894
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002895 // Check access rights if needed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002896 if (IsAccessCheckNeeded()) {
2897 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
2898 return SetPropertyWithFailedAccessCheck(
2899 result, name, value, true, strict_mode);
2900 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002901 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002902
2903 if (IsJSGlobalProxy()) {
2904 Object* proto = GetPrototype();
2905 if (proto->IsNull()) return value;
2906 ASSERT(proto->IsJSGlobalObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002907 return JSObject::cast(proto)->SetPropertyForResult(
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002908 result, name, value, attributes, strict_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002909 }
2910
ager@chromium.org32912102009-01-16 10:38:43 +00002911 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002912 bool found = false;
2913 MaybeObject* result_object;
2914 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
2915 value,
2916 attributes,
2917 &found,
2918 strict_mode);
2919 if (found) return result_object;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002920 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002921
2922 // At this point, no GC should have happened, as this would invalidate
2923 // 'result', which we cannot handlify!
2924
ager@chromium.org5c838252010-02-19 08:53:10 +00002925 if (!result->IsFound()) {
2926 // Neither properties nor transitions found.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002927 return AddProperty(name, value, attributes, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002928 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002929 if (result->IsReadOnly() && result->IsProperty()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002930 if (strict_mode == kStrictMode) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002931 Handle<JSObject> self(this);
2932 Handle<String> hname(name);
2933 Handle<Object> args[] = { hname, self };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002934 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002935 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002936 } else {
2937 return value;
2938 }
2939 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002940 // This is a real property that is not read-only, or it is a
2941 // transition or null descriptor and there are no setters in the prototypes.
2942 switch (result->type()) {
2943 case NORMAL:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002944 return SetNormalizedProperty(result, value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002945 case FIELD:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002946 return FastPropertyAtPut(result->GetFieldIndex(), value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002947 case MAP_TRANSITION:
2948 if (attributes == result->GetAttributes()) {
2949 // Only use map transition if the attributes match.
2950 return AddFastPropertyUsingMap(result->GetTransitionMap(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002951 name,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002952 value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002953 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002954 return ConvertDescriptorToField(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002955 case CONSTANT_FUNCTION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002956 // Only replace the function if necessary.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002957 if (value == result->GetConstantFunction()) return value;
2958 // Preserve the attributes of this existing property.
2959 attributes = result->GetAttributes();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002960 return ConvertDescriptorToField(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002961 case CALLBACKS:
2962 return SetPropertyWithCallback(result->GetCallbackObject(),
2963 name,
2964 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002965 result->holder(),
2966 strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002967 case INTERCEPTOR:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002968 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002969 case CONSTANT_TRANSITION: {
2970 // If the same constant function is being added we can simply
2971 // transition to the target map.
2972 Map* target_map = result->GetTransitionMap();
2973 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2974 int number = target_descriptors->SearchWithCache(name);
2975 ASSERT(number != DescriptorArray::kNotFound);
2976 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2977 JSFunction* function =
2978 JSFunction::cast(target_descriptors->GetValue(number));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002979 if (value == function) {
2980 set_map(target_map);
2981 return value;
2982 }
2983 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2984 // FIELD, even if the value is a constant function.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002985 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002986 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002987 case NULL_DESCRIPTOR:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002988 case ELEMENTS_TRANSITION:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002989 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002990 case HANDLER:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002991 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +00002992 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002993 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00002994 UNREACHABLE(); // keep the compiler happy
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002995 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002996}
2997
2998
2999// Set a real local property, even if it is READ_ONLY. If the property is not
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003000// present, add it with attributes NONE. This code is an exact clone of
3001// SetProperty, with the check for IsReadOnly and the check for a
3002// callback setter removed. The two lines looking up the LookupResult
3003// result are also added. If one of the functions is changed, the other
3004// should be.
ricow@chromium.org2c99e282011-07-28 09:15:17 +00003005// Note that this method cannot be used to set the prototype of a function
3006// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
3007// doesn't handle function prototypes correctly.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003008Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
3009 Handle<JSObject> object,
3010 Handle<String> key,
3011 Handle<Object> value,
3012 PropertyAttributes attributes) {
3013 CALL_HEAP_FUNCTION(
3014 object->GetIsolate(),
3015 object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
3016 Object);
3017}
3018
3019
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003020MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003021 String* name,
3022 Object* value,
3023 PropertyAttributes attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003024
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025 // Make sure that the top context does not change when doing callbacks or
3026 // interceptor calls.
3027 AssertNoContextChange ncc;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003028 Isolate* isolate = GetIsolate();
3029 LookupResult result(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003030 LocalLookup(name, &result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003031 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003032 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003033 if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003034 return SetPropertyWithFailedAccessCheck(&result,
3035 name,
3036 value,
3037 false,
3038 kNonStrictMode);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003039 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003040 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003041
3042 if (IsJSGlobalProxy()) {
3043 Object* proto = GetPrototype();
3044 if (proto->IsNull()) return value;
3045 ASSERT(proto->IsJSGlobalObject());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003046 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003047 name,
3048 value,
3049 attributes);
3050 }
3051
ager@chromium.org7c537e22008-10-16 08:43:32 +00003052 // Check for accessor in prototype chain removed here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00003053 if (!result.IsFound()) {
3054 // Neither properties nor transitions found.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003055 return AddProperty(name, value, attributes, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003056 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003057
ager@chromium.org5c838252010-02-19 08:53:10 +00003058 PropertyDetails details = PropertyDetails(attributes, NORMAL);
3059
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003060 // Check of IsReadOnly removed from here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00003061 switch (result.type()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003062 case NORMAL:
ager@chromium.org5c838252010-02-19 08:53:10 +00003063 return SetNormalizedProperty(name, value, details);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003064 case FIELD:
ager@chromium.org5c838252010-02-19 08:53:10 +00003065 return FastPropertyAtPut(result.GetFieldIndex(), value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003066 case MAP_TRANSITION:
ager@chromium.org5c838252010-02-19 08:53:10 +00003067 if (attributes == result.GetAttributes()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003068 // Only use map transition if the attributes match.
ager@chromium.org5c838252010-02-19 08:53:10 +00003069 return AddFastPropertyUsingMap(result.GetTransitionMap(),
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003070 name,
3071 value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003072 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003073 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003074 case CONSTANT_FUNCTION:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003075 // Only replace the function if necessary.
ager@chromium.org5c838252010-02-19 08:53:10 +00003076 if (value == result.GetConstantFunction()) return value;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003077 // Preserve the attributes of this existing property.
ager@chromium.org5c838252010-02-19 08:53:10 +00003078 attributes = result.GetAttributes();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003079 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003080 case CALLBACKS:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003081 case INTERCEPTOR:
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003082 // Override callback in clone
3083 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003084 case CONSTANT_TRANSITION:
3085 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
3086 // if the value is a function.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003087 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003088 case NULL_DESCRIPTOR:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003089 case ELEMENTS_TRANSITION:
ager@chromium.org7c537e22008-10-16 08:43:32 +00003090 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003091 case HANDLER:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003092 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +00003093 return value;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003094 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00003095 UNREACHABLE(); // keep the compiler happy
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003096 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003097}
3098
3099
3100PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
3101 JSObject* receiver,
3102 String* name,
3103 bool continue_search) {
3104 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003105 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003106 LocalLookupRealNamedProperty(name, &result);
kasper.lund44510672008-07-25 07:37:58 +00003107 if (result.IsProperty()) return result.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003108
3109 if (continue_search) {
3110 // Continue searching via the prototype chain.
3111 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003112 if (!pt->IsNull()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003113 return JSObject::cast(pt)->
3114 GetPropertyAttributeWithReceiver(receiver, name);
3115 }
3116 }
3117 return ABSENT;
3118}
3119
3120
3121PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
3122 JSObject* receiver,
3123 String* name,
3124 bool continue_search) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003125 Isolate* isolate = GetIsolate();
3126
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003127 // Make sure that the top context does not change when doing
3128 // callbacks or interceptor calls.
3129 AssertNoContextChange ncc;
3130
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003131 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003132 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3133 Handle<JSObject> receiver_handle(receiver);
3134 Handle<JSObject> holder_handle(this);
3135 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003136 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003137 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003138 if (!interceptor->query()->IsUndefined()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003139 v8::NamedPropertyQuery query =
3140 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003141 LOG(isolate,
3142 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003143 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003144 {
3145 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003146 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003147 result = query(v8::Utils::ToLocal(name_handle), info);
3148 }
3149 if (!result.IsEmpty()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003150 ASSERT(result->IsInt32());
3151 return static_cast<PropertyAttributes>(result->Int32Value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003152 }
3153 } else if (!interceptor->getter()->IsUndefined()) {
3154 v8::NamedPropertyGetter getter =
3155 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003156 LOG(isolate,
3157 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003158 v8::Handle<v8::Value> result;
3159 {
3160 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003161 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003162 result = getter(v8::Utils::ToLocal(name_handle), info);
3163 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003164 if (!result.IsEmpty()) return DONT_ENUM;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003165 }
3166 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
3167 *name_handle,
3168 continue_search);
3169}
3170
3171
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003172PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
3173 JSReceiver* receiver,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003174 String* key) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003175 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003176 if (IsJSObject() && key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003177 return JSObject::cast(this)->HasElementWithReceiver(receiver, index)
3178 ? NONE : ABSENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003179 }
3180 // Named property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003181 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003182 Lookup(key, &result);
3183 return GetPropertyAttribute(receiver, &result, key, true);
3184}
3185
3186
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003187PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
3188 LookupResult* result,
3189 String* name,
3190 bool continue_search) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003191 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003192 if (IsAccessCheckNeeded()) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003193 JSObject* this_obj = JSObject::cast(this);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003194 Heap* heap = GetHeap();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003195 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
3196 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
3197 receiver, result, name, continue_search);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003198 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003199 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003200 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003201 switch (result->type()) {
3202 case NORMAL: // fall through
3203 case FIELD:
3204 case CONSTANT_FUNCTION:
3205 case CALLBACKS:
3206 return result->GetAttributes();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003207 case HANDLER: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003208 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler(
3209 receiver, name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003211 case INTERCEPTOR:
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003212 return result->holder()->GetPropertyAttributeWithInterceptor(
3213 JSObject::cast(receiver), name, continue_search);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003214 default:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003215 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003216 }
3217 }
3218 return ABSENT;
3219}
3220
3221
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003222PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003223 // Check whether the name is an array index.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003224 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003225 if (IsJSObject() && name->AsArrayIndex(&index)) {
3226 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003227 return ABSENT;
3228 }
3229 // Named property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003230 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003231 LocalLookup(name, &result);
3232 return GetPropertyAttribute(this, &result, name, false);
3233}
3234
3235
lrn@chromium.org303ada72010-10-27 09:33:13 +00003236MaybeObject* NormalizedMapCache::Get(JSObject* obj,
3237 PropertyNormalizationMode mode) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003238 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003239 Map* fast = obj->map();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003240 int index = fast->Hash() % kEntries;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003241 Object* result = get(index);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003242 if (result->IsMap() &&
3243 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003244#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003245 if (FLAG_verify_heap) {
3246 Map::cast(result)->SharedMapVerify();
3247 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003248 if (FLAG_enable_slow_asserts) {
3249 // The cached map should match newly created normalized map bit-by-bit.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003250 Object* fresh;
3251 { MaybeObject* maybe_fresh =
3252 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3253 if (maybe_fresh->ToObject(&fresh)) {
3254 ASSERT(memcmp(Map::cast(fresh)->address(),
3255 Map::cast(result)->address(),
3256 Map::kSize) == 0);
3257 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003258 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003259 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003260#endif
3261 return result;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003262 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003263
lrn@chromium.org303ada72010-10-27 09:33:13 +00003264 { MaybeObject* maybe_result =
3265 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3266 if (!maybe_result->ToObject(&result)) return maybe_result;
3267 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003268 set(index, result);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003269 isolate->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003270
3271 return result;
3272}
3273
3274
ricow@chromium.org65fae842010-08-25 15:26:24 +00003275void NormalizedMapCache::Clear() {
3276 int entries = length();
3277 for (int i = 0; i != entries; i++) {
3278 set_undefined(i);
3279 }
3280}
3281
3282
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003283void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
3284 Handle<String> name,
3285 Handle<Code> code) {
3286 Isolate* isolate = object->GetIsolate();
3287 CALL_HEAP_FUNCTION_VOID(isolate,
3288 object->UpdateMapCodeCache(*name, *code));
3289}
3290
3291
lrn@chromium.org303ada72010-10-27 09:33:13 +00003292MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003293 if (map()->is_shared()) {
3294 // Fast case maps are never marked as shared.
3295 ASSERT(!HasFastProperties());
3296 // Replace the map with an identical copy that can be safely modified.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003297 Object* obj;
3298 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
3299 UNIQUE_NORMALIZED_MAP);
3300 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3301 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003302 GetIsolate()->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003303
3304 set_map(Map::cast(obj));
3305 }
3306 return map()->UpdateCodeCache(name, code);
3307}
3308
3309
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003310void JSObject::NormalizeProperties(Handle<JSObject> object,
3311 PropertyNormalizationMode mode,
3312 int expected_additional_properties) {
3313 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
3314 object->NormalizeProperties(
3315 mode, expected_additional_properties));
3316}
3317
3318
lrn@chromium.org303ada72010-10-27 09:33:13 +00003319MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
3320 int expected_additional_properties) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003321 if (!HasFastProperties()) return this;
3322
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003323 // The global object is always normalized.
3324 ASSERT(!IsGlobalObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003325 // JSGlobalProxy must never be normalized
3326 ASSERT(!IsJSGlobalProxy());
3327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003328 Map* map_of_this = map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003329
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003330 // Allocate new content.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003331 int property_count = map_of_this->NumberOfDescribedProperties();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003332 if (expected_additional_properties > 0) {
3333 property_count += expected_additional_properties;
3334 } else {
3335 property_count += 2; // Make space for two more properties.
3336 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003337 StringDictionary* dictionary;
3338 { MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count);
3339 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003340 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003341
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003342 DescriptorArray* descs = map_of_this->instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003343 for (int i = 0; i < descs->number_of_descriptors(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003344 PropertyDetails details(descs->GetDetails(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003345 switch (details.type()) {
3346 case CONSTANT_FUNCTION: {
3347 PropertyDetails d =
3348 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003349 Object* value = descs->GetConstantFunction(i);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003350 MaybeObject* maybe_dictionary =
3351 dictionary->Add(descs->GetKey(i), value, d);
3352 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353 break;
3354 }
3355 case FIELD: {
3356 PropertyDetails d =
3357 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003358 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003359 MaybeObject* maybe_dictionary =
3360 dictionary->Add(descs->GetKey(i), value, d);
3361 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003362 break;
3363 }
3364 case CALLBACKS: {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003365 if (!descs->IsProperty(i)) break;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003366 Object* value = descs->GetCallbacksObject(i);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003367 if (value->IsAccessorPair()) {
3368 MaybeObject* maybe_copy =
3369 AccessorPair::cast(value)->CopyWithoutTransitions();
3370 if (!maybe_copy->To(&value)) return maybe_copy;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003371 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003372 MaybeObject* maybe_dictionary =
3373 dictionary->Add(descs->GetKey(i), value, details);
3374 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003375 break;
3376 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003377 case MAP_TRANSITION:
3378 case CONSTANT_TRANSITION:
3379 case NULL_DESCRIPTOR:
3380 case INTERCEPTOR:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003381 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003382 break;
danno@chromium.orgc612e022011-11-10 11:38:15 +00003383 case HANDLER:
3384 case NORMAL:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003385 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +00003386 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003387 }
3388 }
3389
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003390 Heap* current_heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003391
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003392 // Copy the next enumeration index from instance descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003393 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003394 dictionary->SetNextEnumerationIndex(index);
3395
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003396 Map* new_map;
3397 { MaybeObject* maybe_map =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003398 current_heap->isolate()->context()->global_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003399 normalized_map_cache()->Get(this, mode);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003400 if (!maybe_map->To(&new_map)) return maybe_map;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003401 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402
ager@chromium.org32912102009-01-16 10:38:43 +00003403 // We have now successfully allocated all the necessary objects.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003404 // Changes can now be made with the guarantee that all of them take effect.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003405
3406 // Resize the object in the heap if necessary.
3407 int new_instance_size = new_map->instance_size();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003408 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003409 ASSERT(instance_size_delta >= 0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003410 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
3411 instance_size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003412 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003413 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
3414 -instance_size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003415 }
3416
ricow@chromium.org65fae842010-08-25 15:26:24 +00003417
ager@chromium.org32912102009-01-16 10:38:43 +00003418 set_map(new_map);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003419 new_map->clear_instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003420
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003421 set_properties(dictionary);
3422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003423 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424
3425#ifdef DEBUG
3426 if (FLAG_trace_normalization) {
3427 PrintF("Object properties have been normalized:\n");
3428 Print();
3429 }
3430#endif
3431 return this;
3432}
3433
3434
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003435void JSObject::TransformToFastProperties(Handle<JSObject> object,
3436 int unused_property_fields) {
3437 CALL_HEAP_FUNCTION_VOID(
3438 object->GetIsolate(),
3439 object->TransformToFastProperties(unused_property_fields));
3440}
3441
3442
lrn@chromium.org303ada72010-10-27 09:33:13 +00003443MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003444 if (HasFastProperties()) return this;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003445 ASSERT(!IsGlobalObject());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003446 return property_dictionary()->
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003447 TransformPropertiesToFastFor(this, unused_property_fields);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448}
3449
3450
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003451Handle<SeededNumberDictionary> JSObject::NormalizeElements(
3452 Handle<JSObject> object) {
3453 CALL_HEAP_FUNCTION(object->GetIsolate(),
3454 object->NormalizeElements(),
3455 SeededNumberDictionary);
3456}
3457
3458
lrn@chromium.org303ada72010-10-27 09:33:13 +00003459MaybeObject* JSObject::NormalizeElements() {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003460 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00003461
whesse@chromium.org7b260152011-06-20 15:33:18 +00003462 // Find the backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003463 FixedArrayBase* array = FixedArrayBase::cast(elements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00003464 Map* old_map = array->map();
3465 bool is_arguments =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003466 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
whesse@chromium.org7b260152011-06-20 15:33:18 +00003467 if (is_arguments) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003468 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003469 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00003470 if (array->IsDictionary()) return array;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003472 ASSERT(HasFastElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003473 HasFastSmiOnlyElements() ||
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003474 HasFastDoubleElements() ||
3475 HasFastArgumentsElements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00003476 // Compute the effective length and allocate a new backing store.
3477 int length = IsJSArray()
3478 ? Smi::cast(JSArray::cast(this)->length())->value()
3479 : array->length();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00003480 int old_capacity = 0;
3481 int used_elements = 0;
3482 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003483 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003484 { Object* object;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003485 MaybeObject* maybe = SeededNumberDictionary::Allocate(used_elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003486 if (!maybe->ToObject(&object)) return maybe;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003487 dictionary = SeededNumberDictionary::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003488 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00003489
3490 // Copy the elements to the new backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003491 bool has_double_elements = array->IsFixedDoubleArray();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003492 for (int i = 0; i < length; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003493 Object* value = NULL;
3494 if (has_double_elements) {
3495 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
3496 if (double_array->is_the_hole(i)) {
3497 value = GetIsolate()->heap()->the_hole_value();
3498 } else {
3499 // Objects must be allocated in the old object space, since the
3500 // overall number of HeapNumbers needed for the conversion might
3501 // exceed the capacity of new space, and we would fail repeatedly
3502 // trying to convert the FixedDoubleArray.
3503 MaybeObject* maybe_value_object =
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003504 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003505 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003506 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003507 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003508 ASSERT(old_map->has_fast_elements() ||
3509 old_map->has_fast_smi_only_elements());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003510 value = FixedArray::cast(array)->get(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003511 }
3512 PropertyDetails details = PropertyDetails(NONE, NORMAL);
3513 if (!value->IsTheHole()) {
3514 Object* result;
3515 MaybeObject* maybe_result =
3516 dictionary->AddNumberEntry(i, value, details);
3517 if (!maybe_result->ToObject(&result)) return maybe_result;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003518 dictionary = SeededNumberDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003519 }
3520 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521
whesse@chromium.org7b260152011-06-20 15:33:18 +00003522 // Switch to using the dictionary as the backing storage for elements.
3523 if (is_arguments) {
3524 FixedArray::cast(elements())->set(1, dictionary);
3525 } else {
3526 // Set the new map first to satify the elements type assert in
3527 // set_elements().
3528 Object* new_map;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003529 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
3530 DICTIONARY_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003531 if (!maybe->ToObject(&new_map)) return maybe;
3532 set_map(Map::cast(new_map));
3533 set_elements(dictionary);
3534 }
3535
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003536 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
3537 Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003538
3539#ifdef DEBUG
3540 if (FLAG_trace_normalization) {
3541 PrintF("Object elements have been normalized:\n");
3542 Print();
3543 }
3544#endif
3545
whesse@chromium.org7b260152011-06-20 15:33:18 +00003546 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
3547 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003548}
3549
3550
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003551Smi* JSReceiver::GenerateIdentityHash() {
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003552 Isolate* isolate = GetIsolate();
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003553
3554 int hash_value;
3555 int attempts = 0;
3556 do {
3557 // Generate a random 32-bit hash value but limit range to fit
3558 // within a smi.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003559 hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003560 attempts++;
3561 } while (hash_value == 0 && attempts < 30);
3562 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
3563
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003564 return Smi::FromInt(hash_value);
3565}
3566
3567
3568MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
3569 MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3570 hash);
3571 if (maybe->IsFailure()) return maybe;
3572 return this;
3573}
3574
3575
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003576int JSObject::GetIdentityHash(Handle<JSObject> obj) {
3577 CALL_AND_RETRY(obj->GetIsolate(),
3578 obj->GetIdentityHash(ALLOW_CREATION),
3579 return Smi::cast(__object__)->value(),
3580 return 0);
3581}
3582
3583
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003584MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
3585 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
3586 if (stored_value->IsSmi()) return stored_value;
3587
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003588 // Do not generate permanent identity hash code if not requested.
3589 if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
3590
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003591 Smi* hash = GenerateIdentityHash();
3592 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3593 hash);
3594 if (result->IsFailure()) return result;
3595 if (result->ToObjectUnchecked()->IsUndefined()) {
3596 // Trying to get hash of detached proxy.
3597 return Smi::FromInt(0);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003598 }
3599 return hash;
3600}
3601
3602
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003603MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
3604 Object* hash = this->hash();
3605 if (!hash->IsSmi() && flag == ALLOW_CREATION) {
3606 hash = GenerateIdentityHash();
3607 set_hash(hash);
3608 }
3609 return hash;
3610}
3611
3612
3613Object* JSObject::GetHiddenProperty(String* key) {
3614 if (IsJSGlobalProxy()) {
3615 // For a proxy, use the prototype as target object.
3616 Object* proxy_parent = GetPrototype();
3617 // If the proxy is detached, return undefined.
3618 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3619 ASSERT(proxy_parent->IsJSGlobalObject());
3620 return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
3621 }
3622 ASSERT(!IsJSGlobalProxy());
3623 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3624 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3625 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
3626 return GetHeap()->undefined_value();
3627 }
3628 StringDictionary* dictionary =
3629 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3630 int entry = dictionary->FindEntry(key);
3631 if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
3632 return dictionary->ValueAt(entry);
3633}
3634
3635
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003636Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
3637 Handle<String> key,
3638 Handle<Object> value) {
3639 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3640 obj->SetHiddenProperty(*key, *value),
3641 Object);
3642}
3643
3644
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003645MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
3646 if (IsJSGlobalProxy()) {
3647 // For a proxy, use the prototype as target object.
3648 Object* proxy_parent = GetPrototype();
3649 // If the proxy is detached, return undefined.
3650 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3651 ASSERT(proxy_parent->IsJSGlobalObject());
3652 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
3653 }
3654 ASSERT(!IsJSGlobalProxy());
3655 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
3656 StringDictionary* dictionary;
3657 if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
3658
3659 // If it was found, check if the key is already in the dictionary.
3660 int entry = dictionary->FindEntry(key);
3661 if (entry != StringDictionary::kNotFound) {
3662 // If key was found, just update the value.
3663 dictionary->ValueAtPut(entry, value);
3664 return this;
3665 }
3666 // Key was not already in the dictionary, so add the entry.
3667 MaybeObject* insert_result = dictionary->Add(key,
3668 value,
3669 PropertyDetails(NONE, NORMAL));
3670 StringDictionary* new_dict;
3671 if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
3672 if (new_dict != dictionary) {
3673 // If adding the key expanded the dictionary (i.e., Add returned a new
3674 // dictionary), store it back to the object.
3675 MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
3676 if (store_result->IsFailure()) return store_result;
3677 }
3678 // Return this to mark success.
3679 return this;
3680}
3681
3682
3683void JSObject::DeleteHiddenProperty(String* key) {
3684 if (IsJSGlobalProxy()) {
3685 // For a proxy, use the prototype as target object.
3686 Object* proxy_parent = GetPrototype();
3687 // If the proxy is detached, return immediately.
3688 if (proxy_parent->IsNull()) return;
3689 ASSERT(proxy_parent->IsJSGlobalObject());
3690 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
3691 return;
3692 }
3693 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3694 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3695 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
3696 StringDictionary* dictionary =
3697 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3698 int entry = dictionary->FindEntry(key);
3699 if (entry == StringDictionary::kNotFound) {
3700 // Key wasn't in dictionary. Deletion is a success.
3701 return;
3702 }
3703 // Key was in the dictionary. Remove it.
3704 dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
3705}
3706
3707
3708bool JSObject::HasHiddenProperties() {
erik.corry@gmail.comb99cabf2011-10-07 09:45:13 +00003709 return GetPropertyAttributePostInterceptor(this,
3710 GetHeap()->hidden_symbol(),
3711 false) != ABSENT;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003712}
3713
3714
3715MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
3716 ASSERT(!IsJSGlobalProxy());
3717 if (HasFastProperties()) {
3718 // If the object has fast properties, check whether the first slot
3719 // in the descriptor array matches the hidden symbol. Since the
3720 // hidden symbols hash code is zero (and no other string has hash
3721 // code zero) it will always occupy the first entry if present.
3722 DescriptorArray* descriptors = this->map()->instance_descriptors();
3723 if ((descriptors->number_of_descriptors() > 0) &&
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00003724 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3725 if (descriptors->GetType(0) == FIELD) {
3726 Object* hidden_store =
3727 this->FastPropertyAt(descriptors->GetFieldIndex(0));
3728 return StringDictionary::cast(hidden_store);
3729 } else {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003730 ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
3731 descriptors->GetType(0) == MAP_TRANSITION);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00003732 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003733 }
3734 } else {
3735 PropertyAttributes attributes;
3736 // You can't install a getter on a property indexed by the hidden symbol,
3737 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
3738 // object.
3739 Object* lookup =
3740 GetLocalPropertyPostInterceptor(this,
3741 GetHeap()->hidden_symbol(),
3742 &attributes)->ToObjectUnchecked();
3743 if (!lookup->IsUndefined()) {
3744 return StringDictionary::cast(lookup);
3745 }
3746 }
3747 if (!create_if_absent) return GetHeap()->undefined_value();
3748 const int kInitialSize = 5;
3749 MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
3750 StringDictionary* dictionary;
3751 if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
3752 MaybeObject* store_result =
3753 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3754 dictionary,
3755 DONT_ENUM,
3756 kNonStrictMode);
3757 if (store_result->IsFailure()) return store_result;
3758 return dictionary;
3759}
3760
3761
3762MaybeObject* JSObject::SetHiddenPropertiesDictionary(
3763 StringDictionary* dictionary) {
3764 ASSERT(!IsJSGlobalProxy());
3765 ASSERT(HasHiddenProperties());
3766 if (HasFastProperties()) {
3767 // If the object has fast properties, check whether the first slot
3768 // in the descriptor array matches the hidden symbol. Since the
3769 // hidden symbols hash code is zero (and no other string has hash
3770 // code zero) it will always occupy the first entry if present.
3771 DescriptorArray* descriptors = this->map()->instance_descriptors();
3772 if ((descriptors->number_of_descriptors() > 0) &&
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00003773 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3774 if (descriptors->GetType(0) == FIELD) {
3775 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
3776 return this;
3777 } else {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003778 ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
3779 descriptors->GetType(0) == MAP_TRANSITION);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00003780 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003781 }
3782 }
3783 MaybeObject* store_result =
3784 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3785 dictionary,
3786 DONT_ENUM,
3787 kNonStrictMode);
3788 if (store_result->IsFailure()) return store_result;
3789 return this;
3790}
3791
3792
lrn@chromium.org303ada72010-10-27 09:33:13 +00003793MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3794 DeleteMode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003795 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003796 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003797 LocalLookupRealNamedProperty(name, &result);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003798 if (!result.IsProperty()) return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003799
3800 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003801 Object* obj;
3802 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3803 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3804 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003805
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003806 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003807}
3808
3809
lrn@chromium.org303ada72010-10-27 09:33:13 +00003810MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003811 Isolate* isolate = GetIsolate();
3812 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003813 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3814 Handle<String> name_handle(name);
3815 Handle<JSObject> this_handle(this);
3816 if (!interceptor->deleter()->IsUndefined()) {
3817 v8::NamedPropertyDeleter deleter =
3818 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003819 LOG(isolate,
3820 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3821 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003822 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003823 v8::Handle<v8::Boolean> result;
3824 {
3825 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003826 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003827 result = deleter(v8::Utils::ToLocal(name_handle), info);
3828 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003829 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003830 if (!result.IsEmpty()) {
3831 ASSERT(result->IsBoolean());
3832 return *v8::Utils::OpenHandle(*result);
3833 }
3834 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003835 MaybeObject* raw_result =
ager@chromium.orge2902be2009-06-08 12:21:35 +00003836 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838 return raw_result;
3839}
3840
3841
lrn@chromium.org303ada72010-10-27 09:33:13 +00003842MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003843 Isolate* isolate = GetIsolate();
3844 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003845 // Make sure that the top context does not change when doing
3846 // callbacks or interceptor calls.
3847 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003848 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003849 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003850 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003851 v8::IndexedPropertyDeleter deleter =
3852 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3853 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003854 LOG(isolate,
3855 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3856 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003857 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003858 v8::Handle<v8::Boolean> result;
3859 {
3860 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003861 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003862 result = deleter(index, info);
3863 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003864 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003865 if (!result.IsEmpty()) {
3866 ASSERT(result->IsBoolean());
3867 return *v8::Utils::OpenHandle(*result);
3868 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00003869 MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3870 *this_handle,
3871 index,
3872 NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003873 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003874 return raw_result;
3875}
3876
3877
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003878Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
3879 uint32_t index) {
3880 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3881 obj->DeleteElement(index, JSObject::NORMAL_DELETION),
3882 Object);
3883}
3884
3885
lrn@chromium.org303ada72010-10-27 09:33:13 +00003886MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003887 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003888 // Check access rights if needed.
3889 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003890 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3891 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3892 return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003893 }
3894
3895 if (IsJSGlobalProxy()) {
3896 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003897 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003898 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00003899 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003900 }
3901
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003902 if (HasIndexedInterceptor()) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003903 // Skip interceptor if forcing deletion.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003904 if (mode != FORCE_DELETION) {
3905 return DeleteElementWithInterceptor(index);
3906 }
3907 mode = JSReceiver::FORCE_DELETION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003908 }
3909
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003910 return GetElementsAccessor()->Delete(this, index, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003911}
3912
3913
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003914Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj,
3915 Handle<String> prop) {
3916 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3917 obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
3918 Object);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003919}
3920
3921
lrn@chromium.org303ada72010-10-27 09:33:13 +00003922MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003923 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003924 // ECMA-262, 3rd, 8.6.2.5
3925 ASSERT(name->IsString());
3926
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003927 // Check access rights if needed.
3928 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003929 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3930 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3931 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003932 }
3933
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003934 if (IsJSGlobalProxy()) {
3935 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003936 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003937 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00003938 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003939 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003940
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003941 uint32_t index = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003942 if (name->AsArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003943 return DeleteElement(index, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003945 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 LocalLookup(name, &result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003947 if (!result.IsProperty()) return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003948 // Ignore attributes if forcing a deletion.
3949 if (result.IsDontDelete() && mode != FORCE_DELETION) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003950 if (mode == STRICT_DELETION) {
3951 // Deleting a non-configurable property in strict mode.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003952 HandleScope scope(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003953 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003954 return isolate->Throw(*isolate->factory()->NewTypeError(
3955 "strict_delete_property", HandleVector(args, 2)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003956 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003957 return isolate->heap()->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003958 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959 // Check for interceptor.
3960 if (result.type() == INTERCEPTOR) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003961 // Skip interceptor if forcing a deletion.
3962 if (mode == FORCE_DELETION) {
3963 return DeletePropertyPostInterceptor(name, mode);
3964 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 return DeletePropertyWithInterceptor(name);
3966 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003968 Object* obj;
3969 { MaybeObject* maybe_obj =
3970 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3971 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3972 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 // Make sure the properties are normalized before removing the entry.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003974 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 }
3976}
3977
3978
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003979MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
3980 if (IsJSProxy()) {
3981 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
3982 }
3983 return JSObject::cast(this)->DeleteElement(index, mode);
3984}
3985
3986
3987MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3988 if (IsJSProxy()) {
3989 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
3990 }
3991 return JSObject::cast(this)->DeleteProperty(name, mode);
3992}
3993
3994
whesse@chromium.org7b260152011-06-20 15:33:18 +00003995bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
3996 ElementsKind kind,
3997 Object* object) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003998 ASSERT(kind == FAST_ELEMENTS ||
3999 kind == DICTIONARY_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004000 if (kind == FAST_ELEMENTS) {
4001 int length = IsJSArray()
4002 ? Smi::cast(JSArray::cast(this)->length())->value()
4003 : elements->length();
4004 for (int i = 0; i < length; ++i) {
4005 Object* element = elements->get(i);
4006 if (!element->IsTheHole() && element == object) return true;
4007 }
4008 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004009 Object* key =
4010 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004011 if (!key->IsUndefined()) return true;
4012 }
4013 return false;
4014}
4015
4016
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004017// Check whether this object references another object.
4018bool JSObject::ReferencesObject(Object* obj) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004019 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004020 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 AssertNoAllocation no_alloc;
4022
4023 // Is the object the constructor for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004024 if (map_of_this->constructor() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004025 return true;
4026 }
4027
4028 // Is the object the prototype for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004029 if (map_of_this->prototype() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030 return true;
4031 }
4032
4033 // Check if the object is among the named properties.
4034 Object* key = SlowReverseLookup(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004035 if (!key->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 return true;
4037 }
4038
4039 // Check if the object is among the indexed properties.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004040 ElementsKind kind = GetElementsKind();
4041 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004042 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00004043 case EXTERNAL_BYTE_ELEMENTS:
4044 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4045 case EXTERNAL_SHORT_ELEMENTS:
4046 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4047 case EXTERNAL_INT_ELEMENTS:
4048 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4049 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004050 case EXTERNAL_DOUBLE_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +00004051 case FAST_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00004052 // Raw pixels and external arrays do not reference other
4053 // objects.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004054 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004055 case FAST_SMI_ONLY_ELEMENTS:
4056 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004057 case FAST_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004058 case DICTIONARY_ELEMENTS: {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004059 FixedArray* elements = FixedArray::cast(this->elements());
4060 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004061 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004063 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4064 FixedArray* parameter_map = FixedArray::cast(elements());
4065 // Check the mapped parameters.
4066 int length = parameter_map->length();
4067 for (int i = 2; i < length; ++i) {
4068 Object* value = parameter_map->get(i);
4069 if (!value->IsTheHole() && value == obj) return true;
4070 }
4071 // Check the arguments.
4072 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4073 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
4074 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004075 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004076 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 }
4078
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004079 // For functions check the context.
4080 if (IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 // Get the constructor function for arguments array.
4082 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083 heap->isolate()->context()->global_context()->
4084 arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004085 JSFunction* arguments_function =
4086 JSFunction::cast(arguments_boilerplate->map()->constructor());
4087
4088 // Get the context and don't check if it is the global context.
4089 JSFunction* f = JSFunction::cast(this);
4090 Context* context = f->context();
4091 if (context->IsGlobalContext()) {
4092 return false;
4093 }
4094
4095 // Check the non-special context slots.
4096 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
4097 // Only check JS objects.
4098 if (context->get(i)->IsJSObject()) {
4099 JSObject* ctxobj = JSObject::cast(context->get(i));
4100 // If it is an arguments array check the content.
4101 if (ctxobj->map()->constructor() == arguments_function) {
4102 if (ctxobj->ReferencesObject(obj)) {
4103 return true;
4104 }
4105 } else if (ctxobj == obj) {
4106 return true;
4107 }
4108 }
4109 }
4110
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004111 // Check the context extension (if any) if it can have references.
4112 if (context->has_extension() && !context->IsCatchContext()) {
4113 return JSObject::cast(context->extension())->ReferencesObject(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 }
4115 }
4116
4117 // No references to object.
4118 return false;
4119}
4120
4121
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004122Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
4123 CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
4124}
4125
4126
lrn@chromium.org303ada72010-10-27 09:33:13 +00004127MaybeObject* JSObject::PreventExtensions() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004128 Isolate* isolate = GetIsolate();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004129 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004130 !isolate->MayNamedAccess(this,
4131 isolate->heap()->undefined_value(),
4132 v8::ACCESS_KEYS)) {
4133 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
4134 return isolate->heap()->false_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004135 }
4136
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004137 if (IsJSGlobalProxy()) {
4138 Object* proto = GetPrototype();
4139 if (proto->IsNull()) return this;
4140 ASSERT(proto->IsJSGlobalObject());
4141 return JSObject::cast(proto)->PreventExtensions();
4142 }
4143
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004144 // It's not possible to seal objects with external array elements
4145 if (HasExternalArrayElements()) {
4146 HandleScope scope(isolate);
4147 Handle<Object> object(this);
4148 Handle<Object> error =
4149 isolate->factory()->NewTypeError(
4150 "cant_prevent_ext_external_array_elements",
4151 HandleVector(&object, 1));
4152 return isolate->Throw(*error);
4153 }
4154
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004155 // If there are fast elements we normalize.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004156 SeededNumberDictionary* dictionary = NULL;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004157 { MaybeObject* maybe = NormalizeElements();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004158 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004159 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004160 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004161 // Make sure that we never go back to fast case.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004162 dictionary->set_requires_slow_elements();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004163
4164 // Do a map transition, other objects with this map may still
4165 // be extensible.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004166 Map* new_map;
4167 { MaybeObject* maybe = map()->CopyDropTransitions();
4168 if (!maybe->To<Map>(&new_map)) return maybe;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004169 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004170 new_map->set_is_extensible(false);
4171 set_map(new_map);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004172 ASSERT(!map()->is_extensible());
4173 return new_map;
4174}
4175
4176
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177// Tests for the fast common case for property enumeration:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004178// - This object and all prototypes has an enum cache (which means that
4179// it is no proxy, has no interceptors and needs no access checks).
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004180// - This object has no elements.
4181// - No prototype has enumerable properties/elements.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004182bool JSReceiver::IsSimpleEnum() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004183 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004184 for (Object* o = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004185 o != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004186 o = JSObject::cast(o)->GetPrototype()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004187 if (!o->IsJSObject()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 JSObject* curr = JSObject::cast(o);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004190 ASSERT(!curr->HasNamedInterceptor());
4191 ASSERT(!curr->HasIndexedInterceptor());
4192 ASSERT(!curr->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004193 if (curr->NumberOfEnumElements() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 if (curr != this) {
4195 FixedArray* curr_fixed_array =
4196 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004197 if (curr_fixed_array->length() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198 }
4199 }
4200 return true;
4201}
4202
4203
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004204int Map::NumberOfDescribedProperties(PropertyAttributes filter) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004206 DescriptorArray* descs = instance_descriptors();
4207 for (int i = 0; i < descs->number_of_descriptors(); i++) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004208 PropertyDetails details(descs->GetDetails(i));
4209 if (descs->IsProperty(i) && (details.attributes() & filter) == 0) {
4210 result++;
4211 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004212 }
4213 return result;
4214}
4215
4216
4217int Map::PropertyIndexFor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004218 DescriptorArray* descs = instance_descriptors();
4219 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4220 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
4221 return descs->GetFieldIndex(i);
4222 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223 }
4224 return -1;
4225}
4226
4227
4228int Map::NextFreePropertyIndex() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004229 int max_index = -1;
4230 DescriptorArray* descs = instance_descriptors();
4231 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4232 if (descs->GetType(i) == FIELD) {
4233 int current_index = descs->GetFieldIndex(i);
4234 if (current_index > max_index) max_index = current_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004235 }
4236 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004237 return max_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004238}
4239
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004240
4241AccessorDescriptor* Map::FindAccessor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004242 DescriptorArray* descs = instance_descriptors();
4243 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4244 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
4245 return descs->GetCallbacks(i);
4246 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004247 }
4248 return NULL;
4249}
4250
4251
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004252void JSReceiver::LocalLookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 ASSERT(name->IsString());
4254
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004255 Heap* heap = GetHeap();
4256
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004257 if (IsJSGlobalProxy()) {
4258 Object* proto = GetPrototype();
4259 if (proto->IsNull()) return result->NotFound();
4260 ASSERT(proto->IsJSGlobalObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004261 return JSReceiver::cast(proto)->LocalLookup(name, result);
4262 }
4263
4264 if (IsJSProxy()) {
4265 result->HandlerResult(JSProxy::cast(this));
4266 return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004267 }
4268
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004269 // Do not use inline caching if the object is a non-global object
4270 // that requires access checks.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004271 if (IsAccessCheckNeeded()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004272 result->DisallowCaching();
4273 }
4274
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004275 JSObject* js_object = JSObject::cast(this);
4276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004277 // Check __proto__ before interceptor.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004278 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004279 result->ConstantResult(js_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004280 return;
4281 }
4282
4283 // Check for lookup interceptor except when bootstrapping.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004284 if (js_object->HasNamedInterceptor() &&
4285 !heap->isolate()->bootstrapper()->IsActive()) {
4286 result->InterceptorResult(js_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004287 return;
4288 }
4289
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004290 js_object->LocalLookupRealNamedProperty(name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004291}
4292
4293
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004294void JSReceiver::Lookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004295 // Ecma-262 3rd 8.6.2.4
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004296 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004297 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004298 current != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004299 current = JSObject::cast(current)->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004300 JSReceiver::cast(current)->LocalLookup(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004301 if (result->IsProperty()) return;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004302 }
4303 result->NotFound();
4304}
4305
4306
4307// Search object and it's prototype chain for callback properties.
4308void JSObject::LookupCallback(String* name, LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004309 Heap* heap = GetHeap();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004310 for (Object* current = this;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00004311 current != heap->null_value() && current->IsJSObject();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004312 current = JSObject::cast(current)->GetPrototype()) {
4313 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004314 if (result->IsFound() && result->type() == CALLBACKS) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 }
4316 result->NotFound();
4317}
4318
4319
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004320// Try to update an accessor in an elements dictionary. Return true if the
4321// update succeeded, and false otherwise.
4322static bool UpdateGetterSetterInDictionary(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004323 SeededNumberDictionary* dictionary,
4324 uint32_t index,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004325 AccessorComponent component,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004326 Object* fun,
4327 PropertyAttributes attributes) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004328 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004329 if (entry != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004330 Object* result = dictionary->ValueAt(entry);
4331 PropertyDetails details = dictionary->DetailsAt(entry);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004332 // TODO(mstarzinger): We should check for details.IsDontDelete() here once
4333 // we only call into the runtime once to set both getter and setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004334 if (details.type() == CALLBACKS && result->IsAccessorPair()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004335 if (details.attributes() != attributes) {
4336 dictionary->DetailsAtPut(entry,
4337 PropertyDetails(attributes, CALLBACKS, index));
4338 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004339 AccessorPair::cast(result)->set(component, fun);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004340 return true;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004341 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004342 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004343 return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004344}
4345
4346
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004347MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004348 AccessorComponent component,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004349 Object* fun,
4350 PropertyAttributes attributes) {
4351 switch (GetElementsKind()) {
4352 case FAST_SMI_ONLY_ELEMENTS:
4353 case FAST_ELEMENTS:
4354 case FAST_DOUBLE_ELEMENTS:
4355 break;
4356 case EXTERNAL_PIXEL_ELEMENTS:
4357 case EXTERNAL_BYTE_ELEMENTS:
4358 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4359 case EXTERNAL_SHORT_ELEMENTS:
4360 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4361 case EXTERNAL_INT_ELEMENTS:
4362 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4363 case EXTERNAL_FLOAT_ELEMENTS:
4364 case EXTERNAL_DOUBLE_ELEMENTS:
4365 // Ignore getters and setters on pixel and external array elements.
4366 return GetHeap()->undefined_value();
4367 case DICTIONARY_ELEMENTS:
4368 if (UpdateGetterSetterInDictionary(element_dictionary(),
4369 index,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004370 component,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004371 fun,
4372 attributes)) {
4373 return GetHeap()->undefined_value();
whesse@chromium.org7b260152011-06-20 15:33:18 +00004374 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004375 break;
4376 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4377 // Ascertain whether we have read-only properties or an existing
4378 // getter/setter pair in an arguments elements dictionary backing
4379 // store.
4380 FixedArray* parameter_map = FixedArray::cast(elements());
4381 uint32_t length = parameter_map->length();
4382 Object* probe =
4383 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
4384 if (probe == NULL || probe->IsTheHole()) {
4385 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4386 if (arguments->IsDictionary()) {
4387 SeededNumberDictionary* dictionary =
4388 SeededNumberDictionary::cast(arguments);
4389 if (UpdateGetterSetterInDictionary(dictionary,
4390 index,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004391 component,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004392 fun,
4393 attributes)) {
4394 return GetHeap()->undefined_value();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004395 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004396 }
4397 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004398 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004399 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004400 }
4401
4402 AccessorPair* accessors;
4403 { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
4404 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4405 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004406 accessors->set(component, fun);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004407
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004408 return SetElementCallback(index, accessors, attributes);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004409}
4410
4411
4412MaybeObject* JSObject::DefinePropertyAccessor(String* name,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004413 AccessorComponent component,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004414 Object* fun,
4415 PropertyAttributes attributes) {
4416 // Lookup the name.
4417 LookupResult result(GetHeap()->isolate());
4418 LocalLookupRealNamedProperty(name, &result);
4419 if (result.IsFound()) {
4420 // TODO(mstarzinger): We should check for result.IsDontDelete() here once
4421 // we only call into the runtime once to set both getter and setter.
4422 if (result.type() == CALLBACKS) {
4423 Object* obj = result.GetCallbackObject();
4424 // Need to preserve old getters/setters.
4425 if (obj->IsAccessorPair()) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004426 AccessorPair* copy;
4427 { MaybeObject* maybe_copy =
4428 AccessorPair::cast(obj)->CopyWithoutTransitions();
4429 if (!maybe_copy->To(&copy)) return maybe_copy;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004430 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004431 copy->set(component, fun);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004432 // Use set to update attributes.
4433 return SetPropertyCallback(name, copy, attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004434 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004435 }
4436 }
4437
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004438 AccessorPair* accessors;
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004439 { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
4440 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004441 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004442 accessors->set(component, fun);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004443
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004444 return SetPropertyCallback(name, accessors, attributes);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004445}
4446
4447
4448bool JSObject::CanSetCallback(String* name) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004449 ASSERT(!IsAccessCheckNeeded() ||
4450 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004451
4452 // Check if there is an API defined callback object which prohibits
4453 // callback overwriting in this object or it's prototype chain.
4454 // This mechanism is needed for instance in a browser setting, where
4455 // certain accessors such as window.location should not be allowed
4456 // to be overwritten because allowing overwriting could potentially
4457 // cause security problems.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004458 LookupResult callback_result(GetIsolate());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004459 LookupCallback(name, &callback_result);
4460 if (callback_result.IsProperty()) {
4461 Object* obj = callback_result.GetCallbackObject();
4462 if (obj->IsAccessorInfo() &&
4463 AccessorInfo::cast(obj)->prohibits_overwriting()) {
4464 return false;
4465 }
4466 }
4467
4468 return true;
4469}
4470
4471
lrn@chromium.org303ada72010-10-27 09:33:13 +00004472MaybeObject* JSObject::SetElementCallback(uint32_t index,
4473 Object* structure,
4474 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004475 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4476
4477 // Normalize elements to make this operation simple.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004478 SeededNumberDictionary* dictionary;
4479 { MaybeObject* maybe_dictionary = NormalizeElements();
4480 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004481 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004482 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004483
4484 // Update the dictionary with the new CALLBACKS property.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004485 { MaybeObject* maybe_dictionary = dictionary->Set(index, structure, details);
4486 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004487 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004488
whesse@chromium.org7b260152011-06-20 15:33:18 +00004489 dictionary->set_requires_slow_elements();
4490 // Update the dictionary backing store on the object.
4491 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
4492 // Also delete any parameter alias.
4493 //
4494 // TODO(kmillikin): when deleting the last parameter alias we could
4495 // switch to a direct backing store without the parameter map. This
4496 // would allow GC of the context.
4497 FixedArray* parameter_map = FixedArray::cast(elements());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004498 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004499 parameter_map->set(index + 2, GetHeap()->the_hole_value());
4500 }
4501 parameter_map->set(1, dictionary);
4502 } else {
4503 set_elements(dictionary);
4504 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004505
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004506 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507}
4508
4509
lrn@chromium.org303ada72010-10-27 09:33:13 +00004510MaybeObject* JSObject::SetPropertyCallback(String* name,
4511 Object* structure,
4512 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004513 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4514
4515 bool convert_back_to_fast = HasFastProperties() &&
4516 (map()->instance_descriptors()->number_of_descriptors()
4517 < DescriptorArray::kMaxNumberOfDescriptors);
4518
4519 // Normalize object to make this operation simple.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004520 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004521 if (maybe_ok->IsFailure()) return maybe_ok;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004522 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004523
4524 // For the global object allocate a new map to invalidate the global inline
4525 // caches which have a global property cell reference directly in the code.
4526 if (IsGlobalObject()) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004527 Map* new_map;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004528 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004529 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004530 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004531 set_map(new_map);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004532 // When running crankshaft, changing the map is not enough. We
4533 // need to deoptimize all functions that rely on this global
4534 // object.
4535 Deoptimizer::DeoptimizeGlobalObject(this);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004536 }
4537
4538 // Update the dictionary with the new CALLBACKS property.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004539 { MaybeObject* maybe_ok = SetNormalizedProperty(name, structure, details);
4540 if (maybe_ok->IsFailure()) return maybe_ok;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004541 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004542
4543 if (convert_back_to_fast) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004544 MaybeObject* maybe_ok = TransformToFastProperties(0);
4545 if (maybe_ok->IsFailure()) return maybe_ok;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004546 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004547 return GetHeap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004548}
4549
lrn@chromium.org303ada72010-10-27 09:33:13 +00004550MaybeObject* JSObject::DefineAccessor(String* name,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004551 AccessorComponent component,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004552 Object* fun,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004553 PropertyAttributes attributes) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004554 ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004555 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004556 // Check access rights if needed.
4557 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004558 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4559 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4560 return isolate->heap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004561 }
4562
4563 if (IsJSGlobalProxy()) {
4564 Object* proto = GetPrototype();
4565 if (proto->IsNull()) return this;
4566 ASSERT(proto->IsJSGlobalObject());
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004567 return JSObject::cast(proto)->DefineAccessor(name, component,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004568 fun, attributes);
4569 }
4570
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004571 // Make sure that the top context does not change when doing callbacks or
4572 // interceptor calls.
4573 AssertNoContextChange ncc;
4574
4575 // Try to flatten before operating on the string.
4576 name->TryFlatten();
4577
4578 if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
4579
4580 uint32_t index = 0;
4581 return name->AsArrayIndex(&index) ?
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004582 DefineElementAccessor(index, component, fun, attributes) :
4583 DefinePropertyAccessor(name, component, fun, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584}
4585
4586
lrn@chromium.org303ada72010-10-27 09:33:13 +00004587MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004588 Isolate* isolate = GetIsolate();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004589 String* name = String::cast(info->name());
4590 // Check access rights if needed.
4591 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004592 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4593 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4594 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004595 }
4596
4597 if (IsJSGlobalProxy()) {
4598 Object* proto = GetPrototype();
4599 if (proto->IsNull()) return this;
4600 ASSERT(proto->IsJSGlobalObject());
4601 return JSObject::cast(proto)->DefineAccessor(info);
4602 }
4603
4604 // Make sure that the top context does not change when doing callbacks or
4605 // interceptor calls.
4606 AssertNoContextChange ncc;
4607
4608 // Try to flatten before operating on the string.
4609 name->TryFlatten();
4610
4611 if (!CanSetCallback(name)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004612 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004613 }
4614
4615 uint32_t index = 0;
4616 bool is_element = name->AsArrayIndex(&index);
4617
4618 if (is_element) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004619 if (IsJSArray()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004620
4621 // Accessors overwrite previous callbacks (cf. with getters/setters).
4622 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004623 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004624 case FAST_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00004625 case FAST_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004626 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004627 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004628 case EXTERNAL_BYTE_ELEMENTS:
4629 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4630 case EXTERNAL_SHORT_ELEMENTS:
4631 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4632 case EXTERNAL_INT_ELEMENTS:
4633 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4634 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004635 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004636 // Ignore getters and setters on pixel and external array
4637 // elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004638 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004639 case DICTIONARY_ELEMENTS:
4640 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004641 case NON_STRICT_ARGUMENTS_ELEMENTS:
4642 UNIMPLEMENTED();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004643 break;
4644 }
4645
lrn@chromium.org303ada72010-10-27 09:33:13 +00004646 { MaybeObject* maybe_ok =
4647 SetElementCallback(index, info, info->property_attributes());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004648 if (maybe_ok->IsFailure()) return maybe_ok;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004649 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004650 } else {
4651 // Lookup the name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004652 LookupResult result(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004653 LocalLookup(name, &result);
4654 // ES5 forbids turning a property into an accessor if it's not
4655 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
4656 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004657 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004658 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004659 { MaybeObject* maybe_ok =
4660 SetPropertyCallback(name, info, info->property_attributes());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004661 if (maybe_ok->IsFailure()) return maybe_ok;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004662 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004663 }
4664
4665 return this;
4666}
4667
4668
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004669Object* JSObject::LookupAccessor(String* name, AccessorComponent component) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004670 Heap* heap = GetHeap();
4671
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004672 // Make sure that the top context does not change when doing callbacks or
4673 // interceptor calls.
4674 AssertNoContextChange ncc;
4675
4676 // Check access rights if needed.
4677 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004678 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
4679 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4680 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 }
4682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683 // Make the lookup and include prototypes.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00004684 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004685 if (name->AsArrayIndex(&index)) {
4686 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004687 obj != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004688 obj = JSObject::cast(obj)->GetPrototype()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004689 JSObject* js_object = JSObject::cast(obj);
4690 if (js_object->HasDictionaryElements()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004691 SeededNumberDictionary* dictionary = js_object->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004692 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004693 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004694 Object* element = dictionary->ValueAt(entry);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004695 if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
4696 element->IsAccessorPair()) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004697 return AccessorPair::cast(element)->SafeGet(component);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004698 }
4699 }
4700 }
4701 }
4702 } else {
4703 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004704 obj != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004705 obj = JSObject::cast(obj)->GetPrototype()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004706 LookupResult result(heap->isolate());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004707 JSObject::cast(obj)->LocalLookup(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004708 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004709 if (result.IsReadOnly()) return heap->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004710 if (result.type() == CALLBACKS) {
4711 Object* obj = result.GetCallbackObject();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004712 if (obj->IsAccessorPair()) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004713 return AccessorPair::cast(obj)->SafeGet(component);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004714 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715 }
4716 }
4717 }
4718 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004719 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004720}
4721
4722
4723Object* JSObject::SlowReverseLookup(Object* value) {
4724 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004725 DescriptorArray* descs = map()->instance_descriptors();
4726 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4727 if (descs->GetType(i) == FIELD) {
4728 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
4729 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004730 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004731 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
4732 if (descs->GetConstantFunction(i) == value) {
4733 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734 }
4735 }
4736 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004737 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004738 } else {
4739 return property_dictionary()->SlowReverseLookup(value);
4740 }
4741}
4742
4743
lrn@chromium.org303ada72010-10-27 09:33:13 +00004744MaybeObject* Map::CopyDropDescriptors() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004745 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004746 Object* result;
4747 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004748 heap->AllocateMap(instance_type(), instance_size());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004749 if (!maybe_result->ToObject(&result)) return maybe_result;
4750 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004751 Map::cast(result)->set_prototype(prototype());
4752 Map::cast(result)->set_constructor(constructor());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004753 // Don't copy descriptors, so map transitions always remain a forest.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004754 // If we retained the same descriptors we would have two maps
4755 // pointing to the same transition which is bad because the garbage
4756 // collector relies on being able to reverse pointers from transitions
4757 // to maps. If properties need to be retained use CopyDropTransitions.
danno@chromium.org40cb8782011-05-25 07:58:50 +00004758 Map::cast(result)->clear_instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759 // Please note instance_type and instance_size are set when allocated.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004760 Map::cast(result)->set_inobject_properties(inobject_properties());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761 Map::cast(result)->set_unused_property_fields(unused_property_fields());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004762
4763 // If the map has pre-allocated properties always start out with a descriptor
4764 // array describing these properties.
4765 if (pre_allocated_property_fields() > 0) {
4766 ASSERT(constructor()->IsJSFunction());
4767 JSFunction* ctor = JSFunction::cast(constructor());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004768 Object* descriptors;
4769 { MaybeObject* maybe_descriptors =
4770 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4771 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4772 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004773 Map::cast(result)->set_instance_descriptors(
4774 DescriptorArray::cast(descriptors));
4775 Map::cast(result)->set_pre_allocated_property_fields(
4776 pre_allocated_property_fields());
4777 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004778 Map::cast(result)->set_bit_field(bit_field());
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004779 Map::cast(result)->set_bit_field2(bit_field2());
danno@chromium.org40cb8782011-05-25 07:58:50 +00004780 Map::cast(result)->set_bit_field3(bit_field3());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004781 Map::cast(result)->set_is_shared(false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004782 Map::cast(result)->ClearCodeCache(heap);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004783 return result;
4784}
4785
4786
lrn@chromium.org303ada72010-10-27 09:33:13 +00004787MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4788 NormalizedMapSharingMode sharing) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004789 int new_instance_size = instance_size();
4790 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4791 new_instance_size -= inobject_properties() * kPointerSize;
4792 }
4793
lrn@chromium.org303ada72010-10-27 09:33:13 +00004794 Object* result;
4795 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004796 GetHeap()->AllocateMap(instance_type(), new_instance_size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004797 if (!maybe_result->ToObject(&result)) return maybe_result;
4798 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004799
4800 if (mode != CLEAR_INOBJECT_PROPERTIES) {
4801 Map::cast(result)->set_inobject_properties(inobject_properties());
4802 }
4803
4804 Map::cast(result)->set_prototype(prototype());
4805 Map::cast(result)->set_constructor(constructor());
4806
4807 Map::cast(result)->set_bit_field(bit_field());
4808 Map::cast(result)->set_bit_field2(bit_field2());
danno@chromium.org40cb8782011-05-25 07:58:50 +00004809 Map::cast(result)->set_bit_field3(bit_field3());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004810
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004811 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4812
ricow@chromium.org65fae842010-08-25 15:26:24 +00004813#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004814 if (FLAG_verify_heap && Map::cast(result)->is_shared()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004815 Map::cast(result)->SharedMapVerify();
4816 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004817#endif
4818
4819 return result;
4820}
4821
4822
lrn@chromium.org303ada72010-10-27 09:33:13 +00004823MaybeObject* Map::CopyDropTransitions() {
4824 Object* new_map;
4825 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4826 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4827 }
4828 Object* descriptors;
4829 { MaybeObject* maybe_descriptors =
4830 instance_descriptors()->RemoveTransitions();
4831 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4832 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004833 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004834 return new_map;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004835}
4836
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004837void Map::UpdateCodeCache(Handle<Map> map,
4838 Handle<String> name,
4839 Handle<Code> code) {
4840 Isolate* isolate = map->GetIsolate();
4841 CALL_HEAP_FUNCTION_VOID(isolate,
4842 map->UpdateCodeCache(*name, *code));
4843}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004844
lrn@chromium.org303ada72010-10-27 09:33:13 +00004845MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004846 // Allocate the code cache if not present.
4847 if (code_cache()->IsFixedArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004848 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004849 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004850 if (!maybe_result->ToObject(&result)) return maybe_result;
4851 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004852 set_code_cache(result);
4853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004854
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004855 // Update the code cache.
4856 return CodeCache::cast(code_cache())->Update(name, code);
4857}
4858
4859
4860Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4861 // Do a lookup if a code cache exists.
4862 if (!code_cache()->IsFixedArray()) {
4863 return CodeCache::cast(code_cache())->Lookup(name, flags);
4864 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004865 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004866 }
4867}
4868
4869
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004870int Map::IndexInCodeCache(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004871 // Get the internal index if a code cache exists.
4872 if (!code_cache()->IsFixedArray()) {
4873 return CodeCache::cast(code_cache())->GetIndex(name, code);
4874 }
4875 return -1;
4876}
4877
4878
4879void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4880 // No GC is supposed to happen between a call to IndexInCodeCache and
4881 // RemoveFromCodeCache so the code cache must be there.
4882 ASSERT(!code_cache()->IsFixedArray());
4883 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4884}
4885
4886
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004887// An iterator over all map transitions in an descriptor array, reusing the map
4888// field of the contens array while it is running.
4889class IntrusiveMapTransitionIterator {
4890 public:
4891 explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array)
4892 : descriptor_array_(descriptor_array) { }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004893
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004894 void Start() {
4895 ASSERT(!IsIterating());
4896 if (HasContentArray()) *ContentHeader() = Smi::FromInt(0);
4897 }
4898
4899 bool IsIterating() {
4900 return HasContentArray() && (*ContentHeader())->IsSmi();
4901 }
4902
4903 Map* Next() {
4904 ASSERT(IsIterating());
4905 FixedArray* contents = ContentArray();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00004906 // Attention, tricky index manipulation ahead: Every entry in the contents
4907 // array consists of a value/details pair, so the index is typically even.
4908 // An exception is made for CALLBACKS entries: An even index means we look
4909 // at its getter, and an odd index means we look at its setter.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004910 int index = Smi::cast(*ContentHeader())->value();
4911 while (index < contents->length()) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00004912 PropertyDetails details(Smi::cast(contents->get(index | 1)));
4913 switch (details.type()) {
4914 case MAP_TRANSITION:
4915 case CONSTANT_TRANSITION:
4916 case ELEMENTS_TRANSITION:
4917 // We definitely have a map transition.
4918 *ContentHeader() = Smi::FromInt(index + 2);
4919 return static_cast<Map*>(contents->get(index));
4920 case CALLBACKS: {
4921 // We might have a map transition in a getter or in a setter.
4922 AccessorPair* accessors =
4923 static_cast<AccessorPair*>(contents->get(index & ~1));
4924 Object* accessor =
4925 ((index & 1) == 0) ? accessors->getter() : accessors->setter();
4926 index++;
4927 if (accessor->IsMap()) {
4928 *ContentHeader() = Smi::FromInt(index);
4929 return static_cast<Map*>(accessor);
4930 }
4931 break;
4932 }
4933 case NORMAL:
4934 case FIELD:
4935 case CONSTANT_FUNCTION:
4936 case HANDLER:
4937 case INTERCEPTOR:
4938 case NULL_DESCRIPTOR:
4939 // We definitely have no map transition.
4940 index += 2;
4941 break;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004942 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004943 }
4944 *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map();
4945 return NULL;
4946 }
4947
4948 private:
4949 bool HasContentArray() {
4950 return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex;
4951 }
4952
4953 FixedArray* ContentArray() {
4954 Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex);
4955 return static_cast<FixedArray*>(array);
4956 }
4957
4958 Object** ContentHeader() {
4959 return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset);
4960 }
4961
4962 DescriptorArray* descriptor_array_;
4963};
4964
4965
4966// An iterator over all prototype transitions, reusing the map field of the
4967// underlying array while it is running.
4968class IntrusivePrototypeTransitionIterator {
4969 public:
4970 explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
4971 : proto_trans_(proto_trans) { }
4972
4973 void Start() {
4974 ASSERT(!IsIterating());
4975 if (HasTransitions()) *Header() = Smi::FromInt(0);
4976 }
4977
4978 bool IsIterating() {
4979 return HasTransitions() && (*Header())->IsSmi();
4980 }
4981
4982 Map* Next() {
4983 ASSERT(IsIterating());
4984 int transitionNumber = Smi::cast(*Header())->value();
4985 if (transitionNumber < NumberOfTransitions()) {
4986 *Header() = Smi::FromInt(transitionNumber + 1);
4987 return GetTransition(transitionNumber);
4988 }
4989 *Header() = proto_trans_->GetHeap()->fixed_array_map();
4990 return NULL;
4991 }
4992
4993 private:
4994 bool HasTransitions() {
4995 return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
4996 }
4997
4998 Object** Header() {
4999 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
5000 }
5001
5002 int NumberOfTransitions() {
5003 Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
5004 return Smi::cast(num)->value();
5005 }
5006
5007 Map* GetTransition(int transitionNumber) {
5008 return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
5009 }
5010
5011 int IndexFor(int transitionNumber) {
5012 return Map::kProtoTransitionHeaderSize +
5013 Map::kProtoTransitionMapOffset +
5014 transitionNumber * Map::kProtoTransitionElementsPerEntry;
5015 }
5016
5017 FixedArray* proto_trans_;
5018};
5019
5020
5021// To traverse the transition tree iteratively, we have to store two kinds of
5022// information in a map: The parent map in the traversal and which children of a
5023// node have already been visited. To do this without additional memory, we
5024// temporarily reuse two maps with known values:
5025//
5026// (1) The map of the map temporarily holds the parent, and is restored to the
5027// meta map afterwards.
5028//
5029// (2) The info which children have already been visited depends on which part
5030// of the map we currently iterate:
5031//
5032// (a) If we currently follow normal map transitions, we temporarily store
5033// the current index in the map of the FixedArray of the desciptor
5034// array's contents, and restore it to the fixed array map afterwards.
5035// Note that a single descriptor can have 0, 1, or 2 transitions.
5036//
5037// (b) If we currently follow prototype transitions, we temporarily store
5038// the current index in the map of the FixedArray holding the prototype
5039// transitions, and restore it to the fixed array map afterwards.
5040//
5041// Note that the child iterator is just a concatenation of two iterators: One
5042// iterating over map transitions and one iterating over prototype transisitons.
5043class TraversableMap : public Map {
5044 public:
5045 // Record the parent in the traversal within this map. Note that this destroys
5046 // this map's map!
5047 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
5048
5049 // Reset the current map's map, returning the parent previously stored in it.
5050 TraversableMap* GetAndResetParent() {
5051 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
5052 set_map_no_write_barrier(GetHeap()->meta_map());
5053 return old_parent;
5054 }
5055
5056 // Start iterating over this map's children, possibly destroying a FixedArray
5057 // map (see explanation above).
5058 void ChildIteratorStart() {
5059 IntrusiveMapTransitionIterator(instance_descriptors()).Start();
5060 IntrusivePrototypeTransitionIterator(
5061 unchecked_prototype_transitions()).Start();
5062 }
5063
5064 // If we have an unvisited child map, return that one and advance. If we have
5065 // none, return NULL and reset any destroyed FixedArray maps.
5066 TraversableMap* ChildIteratorNext() {
5067 IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors());
5068 if (descriptor_iterator.IsIterating()) {
5069 Map* next = descriptor_iterator.Next();
5070 if (next != NULL) return static_cast<TraversableMap*>(next);
5071 }
5072 IntrusivePrototypeTransitionIterator
5073 proto_iterator(unchecked_prototype_transitions());
5074 if (proto_iterator.IsIterating()) {
5075 Map* next = proto_iterator.Next();
5076 if (next != NULL) return static_cast<TraversableMap*>(next);
5077 }
5078 return NULL;
5079 }
5080};
5081
5082
5083// Traverse the transition tree in postorder without using the C++ stack by
5084// doing pointer reversal.
5085void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
5086 TraversableMap* current = static_cast<TraversableMap*>(this);
5087 current->ChildIteratorStart();
5088 while (true) {
5089 TraversableMap* child = current->ChildIteratorNext();
5090 if (child != NULL) {
5091 child->ChildIteratorStart();
5092 child->SetParent(current);
5093 current = child;
5094 } else {
5095 TraversableMap* parent = current->GetAndResetParent();
5096 callback(current, data);
5097 if (current == this) break;
5098 current = parent;
5099 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005100 }
5101}
5102
5103
lrn@chromium.org303ada72010-10-27 09:33:13 +00005104MaybeObject* CodeCache::Update(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005105 // The number of monomorphic stubs for normal load/store/call IC's can grow to
5106 // a large number and therefore they need to go into a hash table. They are
5107 // used to load global properties from cells.
5108 if (code->type() == NORMAL) {
5109 // Make sure that a hash table is allocated for the normal load code cache.
5110 if (normal_type_cache()->IsUndefined()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005111 Object* result;
5112 { MaybeObject* maybe_result =
5113 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
5114 if (!maybe_result->ToObject(&result)) return maybe_result;
5115 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005116 set_normal_type_cache(result);
5117 }
5118 return UpdateNormalTypeCache(name, code);
5119 } else {
5120 ASSERT(default_cache()->IsFixedArray());
5121 return UpdateDefaultCache(name, code);
5122 }
5123}
5124
5125
lrn@chromium.org303ada72010-10-27 09:33:13 +00005126MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005127 // When updating the default code cache we disregard the type encoded in the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005128 // flags. This allows call constant stubs to overwrite call field
5129 // stubs, etc.
5130 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
5131
5132 // First check whether we can update existing code cache without
5133 // extending it.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005134 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005135 int length = cache->length();
ager@chromium.org236ad962008-09-25 09:45:57 +00005136 int deleted_index = -1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005137 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005138 Object* key = cache->get(i);
ager@chromium.org236ad962008-09-25 09:45:57 +00005139 if (key->IsNull()) {
5140 if (deleted_index < 0) deleted_index = i;
5141 continue;
5142 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005143 if (key->IsUndefined()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00005144 if (deleted_index >= 0) i = deleted_index;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005145 cache->set(i + kCodeCacheEntryNameOffset, name);
5146 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005147 return this;
5148 }
5149 if (name->Equals(String::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005150 Code::Flags found =
5151 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005152 if (Code::RemoveTypeFromFlags(found) == flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005153 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005154 return this;
5155 }
5156 }
5157 }
5158
ager@chromium.org236ad962008-09-25 09:45:57 +00005159 // Reached the end of the code cache. If there were deleted
5160 // elements, reuse the space for the first of them.
5161 if (deleted_index >= 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005162 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
5163 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
ager@chromium.org236ad962008-09-25 09:45:57 +00005164 return this;
5165 }
5166
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005167 // Extend the code cache with some new entries (at least one). Must be a
5168 // multiple of the entry size.
5169 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
5170 new_length = new_length - new_length % kCodeCacheEntrySize;
5171 ASSERT((new_length % kCodeCacheEntrySize) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005172 Object* result;
5173 { MaybeObject* maybe_result = cache->CopySize(new_length);
5174 if (!maybe_result->ToObject(&result)) return maybe_result;
5175 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005176
5177 // Add the (name, code) pair to the new cache.
5178 cache = FixedArray::cast(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005179 cache->set(length + kCodeCacheEntryNameOffset, name);
5180 cache->set(length + kCodeCacheEntryCodeOffset, code);
5181 set_default_cache(cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005182 return this;
5183}
5184
5185
lrn@chromium.org303ada72010-10-27 09:33:13 +00005186MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005187 // Adding a new entry can cause a new cache to be allocated.
5188 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
lrn@chromium.org303ada72010-10-27 09:33:13 +00005189 Object* new_cache;
5190 { MaybeObject* maybe_new_cache = cache->Put(name, code);
5191 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5192 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005193 set_normal_type_cache(new_cache);
5194 return this;
5195}
5196
5197
5198Object* CodeCache::Lookup(String* name, Code::Flags flags) {
5199 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
5200 return LookupNormalTypeCache(name, flags);
5201 } else {
5202 return LookupDefaultCache(name, flags);
5203 }
5204}
5205
5206
5207Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
5208 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005209 int length = cache->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005210 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
5211 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
ager@chromium.org236ad962008-09-25 09:45:57 +00005212 // Skip deleted elements.
5213 if (key->IsNull()) continue;
5214 if (key->IsUndefined()) return key;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005215 if (name->Equals(String::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005216 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
5217 if (code->flags() == flags) {
5218 return code;
5219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005220 }
5221 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005222 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005223}
5224
5225
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005226Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
5227 if (!normal_type_cache()->IsUndefined()) {
5228 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5229 return cache->Lookup(name, flags);
5230 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005231 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005232 }
5233}
5234
5235
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00005236int CodeCache::GetIndex(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005237 if (code->type() == NORMAL) {
5238 if (normal_type_cache()->IsUndefined()) return -1;
5239 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00005240 return cache->GetIndex(String::cast(name), code->flags());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005241 }
5242
5243 FixedArray* array = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005244 int len = array->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005245 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
5246 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005247 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005248 return -1;
5249}
5250
5251
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00005252void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005253 if (code->type() == NORMAL) {
5254 ASSERT(!normal_type_cache()->IsUndefined());
5255 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00005256 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005257 cache->RemoveByIndex(index);
5258 } else {
5259 FixedArray* array = default_cache();
5260 ASSERT(array->length() >= index && array->get(index)->IsCode());
5261 // Use null instead of undefined for deleted elements to distinguish
5262 // deleted elements from unused elements. This distinction is used
5263 // when looking up in the cache and when updating the cache.
5264 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
5265 array->set_null(index - 1); // Name.
5266 array->set_null(index); // Code.
5267 }
5268}
5269
5270
5271// The key in the code cache hash table consists of the property name and the
5272// code object. The actual match is on the name and the code flags. If a key
5273// is created using the flags and not a code object it can only be used for
5274// lookup not to create a new entry.
5275class CodeCacheHashTableKey : public HashTableKey {
5276 public:
5277 CodeCacheHashTableKey(String* name, Code::Flags flags)
5278 : name_(name), flags_(flags), code_(NULL) { }
5279
5280 CodeCacheHashTableKey(String* name, Code* code)
5281 : name_(name),
5282 flags_(code->flags()),
5283 code_(code) { }
5284
5285
5286 bool IsMatch(Object* other) {
5287 if (!other->IsFixedArray()) return false;
5288 FixedArray* pair = FixedArray::cast(other);
5289 String* name = String::cast(pair->get(0));
5290 Code::Flags flags = Code::cast(pair->get(1))->flags();
5291 if (flags != flags_) {
5292 return false;
5293 }
5294 return name_->Equals(name);
5295 }
5296
5297 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
5298 return name->Hash() ^ flags;
5299 }
5300
5301 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
5302
5303 uint32_t HashForObject(Object* obj) {
5304 FixedArray* pair = FixedArray::cast(obj);
5305 String* name = String::cast(pair->get(0));
5306 Code* code = Code::cast(pair->get(1));
5307 return NameFlagsHashHelper(name, code->flags());
5308 }
5309
lrn@chromium.org303ada72010-10-27 09:33:13 +00005310 MUST_USE_RESULT MaybeObject* AsObject() {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005311 ASSERT(code_ != NULL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005312 Object* obj;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005313 { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005314 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5315 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005316 FixedArray* pair = FixedArray::cast(obj);
5317 pair->set(0, name_);
5318 pair->set(1, code_);
5319 return pair;
5320 }
5321
5322 private:
5323 String* name_;
5324 Code::Flags flags_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005325 // TODO(jkummerow): We should be able to get by without this.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005326 Code* code_;
5327};
5328
5329
5330Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
5331 CodeCacheHashTableKey key(name, flags);
5332 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005333 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005334 return get(EntryToIndex(entry) + 1);
5335}
5336
5337
lrn@chromium.org303ada72010-10-27 09:33:13 +00005338MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005339 CodeCacheHashTableKey key(name, code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005340 Object* obj;
5341 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5342 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5343 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005344
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005345 // Don't use |this|, as the table might have grown.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005346 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
5347
5348 int entry = cache->FindInsertionEntry(key.Hash());
lrn@chromium.org303ada72010-10-27 09:33:13 +00005349 Object* k;
5350 { MaybeObject* maybe_k = key.AsObject();
5351 if (!maybe_k->ToObject(&k)) return maybe_k;
5352 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005353
5354 cache->set(EntryToIndex(entry), k);
5355 cache->set(EntryToIndex(entry) + 1, code);
5356 cache->ElementAdded();
5357 return cache;
5358}
5359
5360
5361int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
5362 CodeCacheHashTableKey key(name, flags);
5363 int entry = FindEntry(&key);
5364 return (entry == kNotFound) ? -1 : entry;
5365}
5366
5367
5368void CodeCacheHashTable::RemoveByIndex(int index) {
5369 ASSERT(index >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005370 Heap* heap = GetHeap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005371 set(EntryToIndex(index), heap->the_hole_value());
5372 set(EntryToIndex(index) + 1, heap->the_hole_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005373 ElementRemoved();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005374}
5375
5376
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005377void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
5378 MapHandleList* maps,
5379 Code::Flags flags,
5380 Handle<Code> code) {
5381 Isolate* isolate = cache->GetIsolate();
5382 CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
5383}
5384
5385
5386MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005387 Code::Flags flags,
5388 Code* code) {
5389 // Initialize cache if necessary.
5390 if (cache()->IsUndefined()) {
5391 Object* result;
5392 { MaybeObject* maybe_result =
5393 PolymorphicCodeCacheHashTable::Allocate(
5394 PolymorphicCodeCacheHashTable::kInitialSize);
5395 if (!maybe_result->ToObject(&result)) return maybe_result;
5396 }
5397 set_cache(result);
5398 } else {
5399 // This entry shouldn't be contained in the cache yet.
5400 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
5401 ->Lookup(maps, flags)->IsUndefined());
5402 }
5403 PolymorphicCodeCacheHashTable* hash_table =
5404 PolymorphicCodeCacheHashTable::cast(cache());
5405 Object* new_cache;
5406 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
5407 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5408 }
5409 set_cache(new_cache);
5410 return this;
5411}
5412
5413
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005414Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
5415 Code::Flags flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005416 if (!cache()->IsUndefined()) {
5417 PolymorphicCodeCacheHashTable* hash_table =
5418 PolymorphicCodeCacheHashTable::cast(cache());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005419 return Handle<Object>(hash_table->Lookup(maps, flags));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005420 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005421 return GetIsolate()->factory()->undefined_value();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005422 }
5423}
5424
5425
5426// Despite their name, object of this class are not stored in the actual
5427// hash table; instead they're temporarily used for lookups. It is therefore
5428// safe to have a weak (non-owning) pointer to a MapList as a member field.
5429class PolymorphicCodeCacheHashTableKey : public HashTableKey {
5430 public:
5431 // Callers must ensure that |maps| outlives the newly constructed object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005432 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005433 : maps_(maps),
5434 code_flags_(code_flags) {}
5435
5436 bool IsMatch(Object* other) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005437 MapHandleList other_maps(kDefaultListAllocationSize);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005438 int other_flags;
5439 FromObject(other, &other_flags, &other_maps);
5440 if (code_flags_ != other_flags) return false;
5441 if (maps_->length() != other_maps.length()) return false;
5442 // Compare just the hashes first because it's faster.
5443 int this_hash = MapsHashHelper(maps_, code_flags_);
5444 int other_hash = MapsHashHelper(&other_maps, other_flags);
5445 if (this_hash != other_hash) return false;
5446
5447 // Full comparison: for each map in maps_, look for an equivalent map in
5448 // other_maps. This implementation is slow, but probably good enough for
5449 // now because the lists are short (<= 4 elements currently).
5450 for (int i = 0; i < maps_->length(); ++i) {
5451 bool match_found = false;
5452 for (int j = 0; j < other_maps.length(); ++j) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00005453 if (*(maps_->at(i)) == *(other_maps.at(j))) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005454 match_found = true;
5455 break;
5456 }
5457 }
5458 if (!match_found) return false;
5459 }
5460 return true;
5461 }
5462
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005463 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005464 uint32_t hash = code_flags;
5465 for (int i = 0; i < maps->length(); ++i) {
5466 hash ^= maps->at(i)->Hash();
5467 }
5468 return hash;
5469 }
5470
5471 uint32_t Hash() {
5472 return MapsHashHelper(maps_, code_flags_);
5473 }
5474
5475 uint32_t HashForObject(Object* obj) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005476 MapHandleList other_maps(kDefaultListAllocationSize);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005477 int other_flags;
5478 FromObject(obj, &other_flags, &other_maps);
5479 return MapsHashHelper(&other_maps, other_flags);
5480 }
5481
5482 MUST_USE_RESULT MaybeObject* AsObject() {
5483 Object* obj;
5484 // The maps in |maps_| must be copied to a newly allocated FixedArray,
5485 // both because the referenced MapList is short-lived, and because C++
5486 // objects can't be stored in the heap anyway.
5487 { MaybeObject* maybe_obj =
5488 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
5489 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5490 }
5491 FixedArray* list = FixedArray::cast(obj);
5492 list->set(0, Smi::FromInt(code_flags_));
5493 for (int i = 0; i < maps_->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005494 list->set(i + 1, *maps_->at(i));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005495 }
5496 return list;
5497 }
5498
5499 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005500 static MapHandleList* FromObject(Object* obj,
5501 int* code_flags,
5502 MapHandleList* maps) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005503 FixedArray* list = FixedArray::cast(obj);
5504 maps->Rewind(0);
5505 *code_flags = Smi::cast(list->get(0))->value();
5506 for (int i = 1; i < list->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005507 maps->Add(Handle<Map>(Map::cast(list->get(i))));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005508 }
5509 return maps;
5510 }
5511
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005512 MapHandleList* maps_; // weak.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005513 int code_flags_;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005514 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005515};
5516
5517
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005518Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
5519 int code_flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005520 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5521 int entry = FindEntry(&key);
5522 if (entry == kNotFound) return GetHeap()->undefined_value();
5523 return get(EntryToIndex(entry) + 1);
5524}
5525
5526
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005527MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005528 int code_flags,
5529 Code* code) {
5530 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5531 Object* obj;
5532 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5533 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5534 }
5535 PolymorphicCodeCacheHashTable* cache =
5536 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
5537 int entry = cache->FindInsertionEntry(key.Hash());
5538 { MaybeObject* maybe_obj = key.AsObject();
5539 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5540 }
5541 cache->set(EntryToIndex(entry), obj);
5542 cache->set(EntryToIndex(entry) + 1, code);
5543 cache->ElementAdded();
5544 return cache;
5545}
5546
5547
lrn@chromium.org303ada72010-10-27 09:33:13 +00005548MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005549 ElementsAccessor* accessor = array->GetElementsAccessor();
5550 MaybeObject* maybe_result =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005551 accessor->AddElementsToFixedArray(array, array, this);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005552 FixedArray* result;
5553 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
5554#ifdef DEBUG
5555 if (FLAG_enable_slow_asserts) {
5556 for (int i = 0; i < result->length(); i++) {
5557 Object* current = result->get(i);
5558 ASSERT(current->IsNumber() || current->IsString());
5559 }
5560 }
5561#endif
5562 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005563}
5564
5565
lrn@chromium.org303ada72010-10-27 09:33:13 +00005566MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00005567 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
5568 MaybeObject* maybe_result =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005569 accessor->AddElementsToFixedArray(NULL, NULL, this, other);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00005570 FixedArray* result;
5571 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005572#ifdef DEBUG
5573 if (FLAG_enable_slow_asserts) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00005574 for (int i = 0; i < result->length(); i++) {
5575 Object* current = result->get(i);
5576 ASSERT(current->IsNumber() || current->IsString());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005577 }
5578 }
5579#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005580 return result;
5581}
5582
5583
lrn@chromium.org303ada72010-10-27 09:33:13 +00005584MaybeObject* FixedArray::CopySize(int new_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005585 Heap* heap = GetHeap();
5586 if (new_length == 0) return heap->empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00005587 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005588 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005589 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5590 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005591 FixedArray* result = FixedArray::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005592 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005593 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005594 int len = length();
5595 if (new_length < len) len = new_length;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005596 // We are taking the map from the old fixed array so the map is sure to
5597 // be an immortal immutable object.
5598 result->set_map_no_write_barrier(map());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005599 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005600 for (int i = 0; i < len; i++) {
5601 result->set(i, get(i), mode);
5602 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603 return result;
5604}
5605
5606
5607void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005608 AssertNoAllocation no_gc;
5609 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005610 for (int index = 0; index < len; index++) {
5611 dest->set(dest_pos+index, get(pos+index), mode);
5612 }
5613}
5614
5615
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005616#ifdef DEBUG
5617bool FixedArray::IsEqualTo(FixedArray* other) {
5618 if (length() != other->length()) return false;
5619 for (int i = 0 ; i < length(); ++i) {
5620 if (get(i) != other->get(i)) return false;
5621 }
5622 return true;
5623}
5624#endif
5625
5626
lrn@chromium.org303ada72010-10-27 09:33:13 +00005627MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005628 Heap* heap = Isolate::Current()->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005629 if (number_of_descriptors == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005630 return heap->empty_descriptor_array();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005631 }
5632 // Allocate the array of keys.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005633 Object* array;
5634 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
lrn@chromium.org303ada72010-10-27 09:33:13 +00005636 if (!maybe_array->ToObject(&array)) return maybe_array;
5637 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005638 // Do not use DescriptorArray::cast on incomplete object.
5639 FixedArray* result = FixedArray::cast(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005640
5641 // Allocate the content array and set it in the descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005642 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005643 heap->AllocateFixedArray(number_of_descriptors << 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005644 if (!maybe_array->ToObject(&array)) return maybe_array;
5645 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00005646 result->set(kBitField3StorageIndex, Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005647 result->set(kContentArrayIndex, array);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005648 result->set(kEnumerationIndexIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005649 Smi::FromInt(PropertyDetails::kInitialIndex));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005650 return result;
5651}
5652
5653
5654void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005655 FixedArray* new_cache,
5656 Object* new_index_cache) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005657 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005658 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005659 if (HasEnumCache()) {
5660 FixedArray::cast(get(kEnumerationIndexIndex))->
5661 set(kEnumCacheBridgeCacheIndex, new_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005662 FixedArray::cast(get(kEnumerationIndexIndex))->
5663 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005665 if (IsEmpty()) return; // Do nothing for empty descriptor array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005666 FixedArray::cast(bridge_storage)->
5667 set(kEnumCacheBridgeCacheIndex, new_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005668 FixedArray::cast(bridge_storage)->
5669 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005670 NoWriteBarrierSet(FixedArray::cast(bridge_storage),
5671 kEnumCacheBridgeEnumIndex,
5672 get(kEnumerationIndexIndex));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005673 set(kEnumerationIndexIndex, bridge_storage);
5674 }
5675}
5676
5677
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00005678static bool InsertionPointFound(String* key1, String* key2) {
5679 return key1->Hash() > key2->Hash() || key1 == key2;
5680}
5681
5682
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005683void DescriptorArray::CopyFrom(Handle<DescriptorArray> dst,
5684 int dst_index,
5685 Handle<DescriptorArray> src,
5686 int src_index,
5687 const WhitenessWitness& witness) {
5688 CALL_HEAP_FUNCTION_VOID(dst->GetIsolate(),
5689 dst->CopyFrom(dst_index, *src, src_index, witness));
5690}
5691
5692
5693MaybeObject* DescriptorArray::CopyFrom(int dst_index,
5694 DescriptorArray* src,
5695 int src_index,
5696 const WhitenessWitness& witness) {
5697 Object* value = src->GetValue(src_index);
5698 PropertyDetails details(src->GetDetails(src_index));
5699 if (details.type() == CALLBACKS && value->IsAccessorPair()) {
5700 MaybeObject* maybe_copy =
5701 AccessorPair::cast(value)->CopyWithoutTransitions();
5702 if (!maybe_copy->To(&value)) return maybe_copy;
5703 }
5704 Descriptor desc(src->GetKey(src_index), value, details);
5705 Set(dst_index, &desc, witness);
5706 return this;
5707}
5708
5709
lrn@chromium.org303ada72010-10-27 09:33:13 +00005710MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
5711 TransitionFlag transition_flag) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005712 // Transitions are only kept when inserting another transition.
5713 // This precondition is not required by this function's implementation, but
5714 // is currently required by the semantics of maps, so we check it.
5715 // Conversely, we filter after replacing, so replacing a transition and
5716 // removing all other transitions is not supported.
5717 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005718 ASSERT(remove_transitions == !descriptor->ContainsTransition());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005719 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005720
5721 // Ensure the key is a symbol.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005722 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005723 if (maybe_result->IsFailure()) return maybe_result;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005724 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005725
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005726 int new_size = 0;
5727 for (int i = 0; i < number_of_descriptors(); i++) {
5728 if (IsNullDescriptor(i)) continue;
5729 if (remove_transitions && IsTransitionOnly(i)) continue;
5730 new_size++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005732
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005733 // If key is in descriptor, we replace it in-place when filtering.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005734 // Count a null descriptor for key as inserted, not replaced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005735 int index = Search(descriptor->GetKey());
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005736 const bool replacing = (index != kNotFound);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005737 bool keep_enumeration_index = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005738 if (replacing) {
5739 // We are replacing an existing descriptor. We keep the enumeration
5740 // index of a visible property.
5741 PropertyType t = PropertyDetails(GetDetails(index)).type();
5742 if (t == CONSTANT_FUNCTION ||
5743 t == FIELD ||
5744 t == CALLBACKS ||
5745 t == INTERCEPTOR) {
5746 keep_enumeration_index = true;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005747 } else if (remove_transitions) {
5748 // Replaced descriptor has been counted as removed if it is
5749 // a transition that will be replaced. Adjust count in this case.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005750 ++new_size;
5751 }
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005752 } else {
5753 ++new_size;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005754 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005755
5756 DescriptorArray* new_descriptors;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005757 { MaybeObject* maybe_result = Allocate(new_size);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005758 if (!maybe_result->To(&new_descriptors)) return maybe_result;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005759 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005760
5761 DescriptorArray::WhitenessWitness witness(new_descriptors);
5762
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005763 // Set the enumeration index in the descriptors and set the enumeration index
5764 // in the result.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005765 int enumeration_index = NextEnumerationIndex();
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005766 if (!descriptor->ContainsTransition()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005767 if (keep_enumeration_index) {
5768 descriptor->SetEnumerationIndex(
5769 PropertyDetails(GetDetails(index)).index());
5770 } else {
5771 descriptor->SetEnumerationIndex(enumeration_index);
5772 ++enumeration_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005773 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005774 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005775 new_descriptors->SetNextEnumerationIndex(enumeration_index);
5776
5777 // Copy the descriptors, filtering out transitions and null descriptors,
5778 // and inserting or replacing a descriptor.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005779 int to_index = 0;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00005780 int insertion_index = -1;
5781 int from_index = 0;
5782 while (from_index < number_of_descriptors()) {
5783 if (insertion_index < 0 &&
5784 InsertionPointFound(GetKey(from_index), descriptor->GetKey())) {
5785 insertion_index = to_index++;
5786 if (replacing) from_index++;
5787 } else {
5788 if (!(IsNullDescriptor(from_index) ||
5789 (remove_transitions && IsTransitionOnly(from_index)))) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005790 MaybeObject* copy_result =
5791 new_descriptors->CopyFrom(to_index++, this, from_index, witness);
5792 if (copy_result->IsFailure()) return copy_result;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00005793 }
5794 from_index++;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005795 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005796 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00005797 if (insertion_index < 0) insertion_index = to_index++;
5798 new_descriptors->Set(insertion_index, descriptor, witness);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005799
5800 ASSERT(to_index == new_descriptors->number_of_descriptors());
5801 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005802
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005803 return new_descriptors;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005804}
5805
5806
lrn@chromium.org303ada72010-10-27 09:33:13 +00005807MaybeObject* DescriptorArray::RemoveTransitions() {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005808 // Allocate the new descriptor array.
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00005809 int new_number_of_descriptors = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005810 for (int i = 0; i < number_of_descriptors(); i++) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00005811 if (IsProperty(i)) new_number_of_descriptors++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005812 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005813 DescriptorArray* new_descriptors;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00005814 { MaybeObject* maybe_result = Allocate(new_number_of_descriptors);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005815 if (!maybe_result->To(&new_descriptors)) return maybe_result;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005816 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005817
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005818 // Copy the content.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005819 DescriptorArray::WhitenessWitness witness(new_descriptors);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005820 int next_descriptor = 0;
5821 for (int i = 0; i < number_of_descriptors(); i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005822 if (IsProperty(i)) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005823 MaybeObject* copy_result =
5824 new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
5825 if (copy_result->IsFailure()) return copy_result;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005826 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005827 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005828 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005829
5830 return new_descriptors;
5831}
5832
5833
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005834void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005835 // In-place heap sort.
5836 int len = number_of_descriptors();
5837
5838 // Bottom-up max-heap construction.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005839 // Index of the last node with children
5840 const int max_parent_index = (len / 2) - 1;
5841 for (int i = max_parent_index; i >= 0; --i) {
5842 int parent_index = i;
5843 const uint32_t parent_hash = GetKey(i)->Hash();
5844 while (parent_index <= max_parent_index) {
5845 int child_index = 2 * parent_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005846 uint32_t child_hash = GetKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005847 if (child_index + 1 < len) {
5848 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5849 if (right_child_hash > child_hash) {
5850 child_index++;
5851 child_hash = right_child_hash;
5852 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005853 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005854 if (child_hash <= parent_hash) break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005855 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005856 // Now element at child_index could be < its children.
5857 parent_index = child_index; // parent_hash remains correct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005858 }
5859 }
5860
5861 // Extract elements and create sorted array.
5862 for (int i = len - 1; i > 0; --i) {
5863 // Put max element at the back of the array.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005864 NoIncrementalWriteBarrierSwapDescriptors(0, i);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005865 // Shift down the new top element.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005866 int parent_index = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005867 const uint32_t parent_hash = GetKey(parent_index)->Hash();
5868 const int max_parent_index = (i / 2) - 1;
5869 while (parent_index <= max_parent_index) {
5870 int child_index = parent_index * 2 + 1;
5871 uint32_t child_hash = GetKey(child_index)->Hash();
5872 if (child_index + 1 < i) {
5873 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5874 if (right_child_hash > child_hash) {
5875 child_index++;
5876 child_hash = right_child_hash;
5877 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005878 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005879 if (child_hash <= parent_hash) break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005880 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005881 parent_index = child_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005882 }
5883 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00005884}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005885
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00005886
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005887void DescriptorArray::Sort(const WhitenessWitness& witness) {
5888 SortUnchecked(witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005889 SLOW_ASSERT(IsSortedNoDuplicates());
5890}
5891
5892
5893int DescriptorArray::BinarySearch(String* name, int low, int high) {
5894 uint32_t hash = name->Hash();
5895
5896 while (low <= high) {
5897 int mid = (low + high) / 2;
5898 String* mid_name = GetKey(mid);
5899 uint32_t mid_hash = mid_name->Hash();
5900
5901 if (mid_hash > hash) {
5902 high = mid - 1;
5903 continue;
5904 }
5905 if (mid_hash < hash) {
5906 low = mid + 1;
5907 continue;
5908 }
5909 // Found an element with the same hash-code.
5910 ASSERT(hash == mid_hash);
5911 // There might be more, so we find the first one and
5912 // check them all to see if we have a match.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005913 if (name == mid_name && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
5915 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005916 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005917 }
5918 break;
5919 }
5920 return kNotFound;
5921}
5922
5923
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005924int DescriptorArray::LinearSearch(String* name, int len) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005925 uint32_t hash = name->Hash();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005926 for (int number = 0; number < len; number++) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005927 String* entry = GetKey(number);
5928 if ((entry->Hash() == hash) &&
5929 name->Equals(entry) &&
5930 !is_null_descriptor(number)) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005931 return number;
5932 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005933 }
5934 return kNotFound;
5935}
5936
5937
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005938MaybeObject* AccessorPair::CopyWithoutTransitions() {
5939 Heap* heap = GetHeap();
5940 AccessorPair* copy;
5941 { MaybeObject* maybe_copy = heap->AllocateAccessorPair();
5942 if (!maybe_copy->To(&copy)) return maybe_copy;
5943 }
5944 copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter());
5945 copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter());
5946 return copy;
5947}
5948
5949
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005950Object* AccessorPair::SafeGet(AccessorComponent component) {
5951 Object* accessor = get(component);
5952 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
5953}
5954
5955
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005956MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5957 PretenureFlag pretenure) {
5958 ASSERT(deopt_entry_count > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005959 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005960 pretenure);
5961}
5962
5963
5964MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5965 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005966 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5967 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005968 pretenure);
5969}
5970
5971
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005972#ifdef DEBUG
5973bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5974 if (IsEmpty()) return other->IsEmpty();
5975 if (other->IsEmpty()) return false;
5976 if (length() != other->length()) return false;
5977 for (int i = 0; i < length(); ++i) {
5978 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5979 }
5980 return GetContentArray()->IsEqualTo(other->GetContentArray());
5981}
5982#endif
5983
5984
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005985bool String::LooksValid() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005986 if (!Isolate::Current()->heap()->Contains(this)) return false;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005987 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988}
5989
5990
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005991String::FlatContent String::GetFlatContent() {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005992 int length = this->length();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005993 StringShape shape(this);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005994 String* string = this;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00005995 int offset = 0;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005996 if (shape.representation_tag() == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005997 ConsString* cons = ConsString::cast(string);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005998 if (cons->second()->length() != 0) {
5999 return FlatContent();
6000 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006001 string = cons->first();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006002 shape = StringShape(string);
ager@chromium.org7c537e22008-10-16 08:43:32 +00006003 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006004 if (shape.representation_tag() == kSlicedStringTag) {
6005 SlicedString* slice = SlicedString::cast(string);
6006 offset = slice->offset();
6007 string = slice->parent();
6008 shape = StringShape(string);
6009 ASSERT(shape.representation_tag() != kConsStringTag &&
6010 shape.representation_tag() != kSlicedStringTag);
6011 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006012 if (shape.encoding_tag() == kAsciiStringTag) {
6013 const char* start;
6014 if (shape.representation_tag() == kSeqStringTag) {
6015 start = SeqAsciiString::cast(string)->GetChars();
6016 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00006017 start = ExternalAsciiString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006018 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006019 return FlatContent(Vector<const char>(start + offset, length));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006020 } else {
6021 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
6022 const uc16* start;
6023 if (shape.representation_tag() == kSeqStringTag) {
6024 start = SeqTwoByteString::cast(string)->GetChars();
6025 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00006026 start = ExternalTwoByteString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006027 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006028 return FlatContent(Vector<const uc16>(start + offset, length));
ager@chromium.org7c537e22008-10-16 08:43:32 +00006029 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006030}
6031
6032
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006033SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6034 RobustnessFlag robust_flag,
6035 int offset,
6036 int length,
6037 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006039 return SmartArrayPointer<char>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006041 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006042
6043 // Negative length means the to the end of the string.
6044 if (length < 0) length = kMaxInt - offset;
6045
6046 // Compute the size of the UTF-8 string. Start at the specified offset.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006047 Access<StringInputBuffer> buffer(
6048 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006049 buffer->Reset(offset, this);
6050 int character_position = offset;
6051 int utf8_bytes = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006052 while (buffer->has_more() && character_position++ < offset + length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053 uint16_t character = buffer->GetNext();
danno@chromium.orgc612e022011-11-10 11:38:15 +00006054 utf8_bytes += unibrow::Utf8::Length(character);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006055 }
6056
6057 if (length_return) {
6058 *length_return = utf8_bytes;
6059 }
6060
6061 char* result = NewArray<char>(utf8_bytes + 1);
6062
6063 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
6064 buffer->Rewind();
6065 buffer->Seek(offset);
6066 character_position = offset;
6067 int utf8_byte_position = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006068 while (buffer->has_more() && character_position++ < offset + length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006069 uint16_t character = buffer->GetNext();
danno@chromium.orgc612e022011-11-10 11:38:15 +00006070 if (allow_nulls == DISALLOW_NULLS && character == 0) {
6071 character = ' ';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006072 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00006073 utf8_byte_position +=
6074 unibrow::Utf8::Encode(result + utf8_byte_position, character);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006075 }
6076 result[utf8_byte_position] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006077 return SmartArrayPointer<char>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078}
6079
6080
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006081SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6082 RobustnessFlag robust_flag,
6083 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006084 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
6085}
6086
6087
6088const uc16* String::GetTwoByteData() {
6089 return GetTwoByteData(0);
6090}
6091
6092
6093const uc16* String::GetTwoByteData(unsigned start) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006094 ASSERT(!IsAsciiRepresentationUnderneath());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006095 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006096 case kSeqStringTag:
ager@chromium.org7c537e22008-10-16 08:43:32 +00006097 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006098 case kExternalStringTag:
6099 return ExternalTwoByteString::cast(this)->
6100 ExternalTwoByteStringGetData(start);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006101 case kSlicedStringTag: {
6102 SlicedString* slice = SlicedString::cast(this);
6103 return slice->parent()->GetTwoByteData(start + slice->offset());
6104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006105 case kConsStringTag:
6106 UNREACHABLE();
6107 return NULL;
6108 }
6109 UNREACHABLE();
6110 return NULL;
6111}
6112
6113
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006114SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006115 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006116 return SmartArrayPointer<uc16>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006117 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006118 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006119
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006120 Access<StringInputBuffer> buffer(
6121 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006122 buffer->Reset(this);
6123
6124 uc16* result = NewArray<uc16>(length() + 1);
6125
6126 int i = 0;
6127 while (buffer->has_more()) {
6128 uint16_t character = buffer->GetNext();
6129 result[i++] = character;
6130 }
6131 result[i] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006132 return SmartArrayPointer<uc16>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006133}
6134
6135
ager@chromium.org7c537e22008-10-16 08:43:32 +00006136const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006137 return reinterpret_cast<uc16*>(
6138 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
6139}
6140
6141
ager@chromium.org7c537e22008-10-16 08:43:32 +00006142void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00006143 unsigned* offset_ptr,
6144 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006145 unsigned chars_read = 0;
6146 unsigned offset = *offset_ptr;
6147 while (chars_read < max_chars) {
6148 uint16_t c = *reinterpret_cast<uint16_t*>(
6149 reinterpret_cast<char*>(this) -
6150 kHeapObjectTag + kHeaderSize + offset * kShortSize);
6151 if (c <= kMaxAsciiCharCode) {
6152 // Fast case for ASCII characters. Cursor is an input output argument.
6153 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6154 rbb->util_buffer,
6155 rbb->capacity,
6156 rbb->cursor)) {
6157 break;
6158 }
6159 } else {
6160 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6161 rbb->util_buffer,
6162 rbb->capacity,
6163 rbb->cursor)) {
6164 break;
6165 }
6166 }
6167 offset++;
6168 chars_read++;
6169 }
6170 *offset_ptr = offset;
6171 rbb->remaining += chars_read;
6172}
6173
6174
ager@chromium.org7c537e22008-10-16 08:43:32 +00006175const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
6176 unsigned* remaining,
6177 unsigned* offset_ptr,
6178 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006179 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
6180 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
6181 *remaining = max_chars;
6182 *offset_ptr += max_chars;
6183 return b;
6184}
6185
6186
6187// This will iterate unless the block of string data spans two 'halves' of
6188// a ConsString, in which case it will recurse. Since the block of string
6189// data to be read has a maximum size this limits the maximum recursion
6190// depth to something sane. Since C++ does not have tail call recursion
6191// elimination, the iteration must be explicit. Since this is not an
6192// -IntoBuffer method it can delegate to one of the efficient
6193// *AsciiStringReadBlock routines.
6194const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
6195 unsigned* offset_ptr,
6196 unsigned max_chars) {
6197 ConsString* current = this;
6198 unsigned offset = *offset_ptr;
6199 int offset_correction = 0;
6200
6201 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006202 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006203 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006204 if (left_length > offset &&
6205 (max_chars <= left_length - offset ||
6206 (rbb->capacity <= left_length - offset &&
6207 (max_chars = left_length - offset, true)))) { // comma operator!
6208 // Left hand side only - iterate unless we have reached the bottom of
6209 // the cons tree. The assignment on the left of the comma operator is
6210 // in order to make use of the fact that the -IntoBuffer routines can
6211 // produce at most 'capacity' characters. This enables us to postpone
6212 // the point where we switch to the -IntoBuffer routines (below) in order
6213 // to maximize the chances of delegating a big chunk of work to the
6214 // efficient *AsciiStringReadBlock routines.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006215 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006216 current = ConsString::cast(left);
6217 continue;
6218 } else {
6219 const unibrow::byte* answer =
6220 String::ReadBlock(left, rbb, &offset, max_chars);
6221 *offset_ptr = offset + offset_correction;
6222 return answer;
6223 }
6224 } else if (left_length <= offset) {
6225 // Right hand side only - iterate unless we have reached the bottom of
6226 // the cons tree.
ager@chromium.org870a0b62008-11-04 11:43:05 +00006227 String* right = current->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006228 offset -= left_length;
6229 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006230 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006231 current = ConsString::cast(right);
6232 continue;
6233 } else {
6234 const unibrow::byte* answer =
6235 String::ReadBlock(right, rbb, &offset, max_chars);
6236 *offset_ptr = offset + offset_correction;
6237 return answer;
6238 }
6239 } else {
6240 // The block to be read spans two sides of the ConsString, so we call the
6241 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
6242 // are able to assemble data from several part strings because they use
6243 // the util_buffer to store their data and never return direct pointers
6244 // to their storage. We don't try to read more than the buffer capacity
6245 // here or we can get too much recursion.
6246 ASSERT(rbb->remaining == 0);
6247 ASSERT(rbb->cursor == 0);
6248 current->ConsStringReadBlockIntoBuffer(
6249 rbb,
6250 &offset,
6251 max_chars > rbb->capacity ? rbb->capacity : max_chars);
6252 *offset_ptr = offset + offset_correction;
6253 return rbb->util_buffer;
6254 }
6255 }
6256}
6257
6258
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006259const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
6260 unsigned* remaining,
6261 unsigned* offset_ptr,
6262 unsigned max_chars) {
6263 // Cast const char* to unibrow::byte* (signedness difference).
6264 const unibrow::byte* b =
erikcorry0ad885c2011-11-21 13:51:57 +00006265 reinterpret_cast<const unibrow::byte*>(GetChars()) + *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266 *remaining = max_chars;
6267 *offset_ptr += max_chars;
6268 return b;
6269}
6270
6271
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006272void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
6273 ReadBlockBuffer* rbb,
6274 unsigned* offset_ptr,
6275 unsigned max_chars) {
6276 unsigned chars_read = 0;
6277 unsigned offset = *offset_ptr;
erikcorry0ad885c2011-11-21 13:51:57 +00006278 const uint16_t* data = GetChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006279 while (chars_read < max_chars) {
6280 uint16_t c = data[offset];
6281 if (c <= kMaxAsciiCharCode) {
ager@chromium.org80787b72009-04-17 10:24:24 +00006282 // Fast case for ASCII characters. Cursor is an input output argument.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006283 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6284 rbb->util_buffer,
6285 rbb->capacity,
6286 rbb->cursor))
6287 break;
6288 } else {
6289 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6290 rbb->util_buffer,
6291 rbb->capacity,
6292 rbb->cursor))
6293 break;
6294 }
6295 offset++;
6296 chars_read++;
6297 }
6298 *offset_ptr = offset;
6299 rbb->remaining += chars_read;
6300}
6301
6302
ager@chromium.org7c537e22008-10-16 08:43:32 +00006303void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006304 unsigned* offset_ptr,
6305 unsigned max_chars) {
6306 unsigned capacity = rbb->capacity - rbb->cursor;
6307 if (max_chars > capacity) max_chars = capacity;
6308 memcpy(rbb->util_buffer + rbb->cursor,
6309 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
6310 *offset_ptr * kCharSize,
6311 max_chars);
6312 rbb->remaining += max_chars;
6313 *offset_ptr += max_chars;
6314 rbb->cursor += max_chars;
6315}
6316
6317
6318void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
6319 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;
erikcorry0ad885c2011-11-21 13:51:57 +00006324 memcpy(rbb->util_buffer + rbb->cursor, GetChars() + *offset_ptr, max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006325 rbb->remaining += max_chars;
6326 *offset_ptr += max_chars;
6327 rbb->cursor += max_chars;
6328}
6329
6330
6331// This method determines the type of string involved and then copies
6332// a whole chunk of characters into a buffer, or returns a pointer to a buffer
6333// where they can be found. The pointer is not necessarily valid across a GC
6334// (see AsciiStringReadBlock).
6335const unibrow::byte* String::ReadBlock(String* input,
6336 ReadBlockBuffer* rbb,
6337 unsigned* offset_ptr,
6338 unsigned max_chars) {
6339 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
6340 if (max_chars == 0) {
6341 rbb->remaining = 0;
6342 return NULL;
6343 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006344 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006345 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006346 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006347 SeqAsciiString* str = SeqAsciiString::cast(input);
6348 return str->SeqAsciiStringReadBlock(&rbb->remaining,
6349 offset_ptr,
6350 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006351 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006352 SeqTwoByteString* str = SeqTwoByteString::cast(input);
6353 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6354 offset_ptr,
6355 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006356 return rbb->util_buffer;
6357 }
6358 case kConsStringTag:
6359 return ConsString::cast(input)->ConsStringReadBlock(rbb,
6360 offset_ptr,
6361 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006362 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006363 if (input->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006364 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
6365 &rbb->remaining,
6366 offset_ptr,
6367 max_chars);
6368 } else {
6369 ExternalTwoByteString::cast(input)->
6370 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6371 offset_ptr,
6372 max_chars);
6373 return rbb->util_buffer;
6374 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006375 case kSlicedStringTag:
6376 return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
6377 offset_ptr,
6378 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006379 default:
6380 break;
6381 }
6382
6383 UNREACHABLE();
6384 return 0;
6385}
6386
6387
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006388// This method determines the type of string involved and then gets the UTF8
6389// length of the string. It doesn't flatten the string and has log(n) recursion
6390// for a string of length n.
6391int String::Utf8Length(String* input, int from, int to) {
6392 if (from == to) return 0;
6393 int total = 0;
6394 while (true) {
6395 if (input->IsAsciiRepresentation()) return total + to - from;
6396 switch (StringShape(input).representation_tag()) {
6397 case kConsStringTag: {
6398 ConsString* str = ConsString::cast(input);
6399 String* first = str->first();
6400 String* second = str->second();
6401 int first_length = first->length();
6402 if (first_length - from < to - first_length) {
6403 if (first_length > from) {
6404 // Left hand side is shorter.
6405 total += Utf8Length(first, from, first_length);
6406 input = second;
6407 from = 0;
6408 to -= first_length;
6409 } else {
6410 // We only need the right hand side.
6411 input = second;
6412 from -= first_length;
6413 to -= first_length;
6414 }
6415 } else {
6416 if (first_length <= to) {
6417 // Right hand side is shorter.
6418 total += Utf8Length(second, 0, to - first_length);
6419 input = first;
6420 to = first_length;
6421 } else {
6422 // We only need the left hand side.
6423 input = first;
6424 }
6425 }
6426 continue;
6427 }
6428 case kExternalStringTag:
6429 case kSeqStringTag: {
6430 Vector<const uc16> vector = input->GetFlatContent().ToUC16Vector();
6431 const uc16* p = vector.start();
6432 for (int i = from; i < to; i++) {
6433 total += unibrow::Utf8::Length(p[i]);
6434 }
6435 return total;
6436 }
6437 case kSlicedStringTag: {
6438 SlicedString* str = SlicedString::cast(input);
6439 int offset = str->offset();
6440 input = str->parent();
6441 from += offset;
6442 to += offset;
6443 continue;
6444 }
6445 default:
6446 break;
6447 }
6448 UNREACHABLE();
6449 return 0;
6450 }
6451 return 0;
6452}
6453
6454
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006455void Relocatable::PostGarbageCollectionProcessing() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006456 Isolate* isolate = Isolate::Current();
6457 Relocatable* current = isolate->relocatable_top();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006458 while (current != NULL) {
6459 current->PostGarbageCollection();
6460 current = current->prev_;
6461 }
6462}
6463
6464
6465// Reserve space for statics needing saving and restoring.
6466int Relocatable::ArchiveSpacePerThread() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006467 return sizeof(Isolate::Current()->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006468}
6469
6470
6471// Archive statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00006472char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006473 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
6474 isolate->set_relocatable_top(NULL);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006475 return to + ArchiveSpacePerThread();
6476}
6477
6478
6479// Restore statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00006480char* Relocatable::RestoreState(Isolate* isolate, char* from) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006481 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006482 return from + ArchiveSpacePerThread();
6483}
6484
6485
6486char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
6487 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
6488 Iterate(v, top);
6489 return thread_storage + ArchiveSpacePerThread();
6490}
6491
6492
6493void Relocatable::Iterate(ObjectVisitor* v) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006494 Isolate* isolate = Isolate::Current();
6495 Iterate(v, isolate->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006496}
6497
6498
6499void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
6500 Relocatable* current = top;
6501 while (current != NULL) {
6502 current->IterateInstance(v);
6503 current = current->prev_;
6504 }
6505}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006506
6507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006508FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
6509 : Relocatable(isolate),
6510 str_(str.location()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006511 length_(str->length()) {
6512 PostGarbageCollection();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006513}
6514
6515
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006516FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
6517 : Relocatable(isolate),
6518 str_(0),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006519 is_ascii_(true),
6520 length_(input.length()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006521 start_(input.start()) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006522
6523
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006524void FlatStringReader::PostGarbageCollection() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006525 if (str_ == NULL) return;
6526 Handle<String> str(str_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006527 ASSERT(str->IsFlat());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006528 String::FlatContent content = str->GetFlatContent();
6529 ASSERT(content.IsFlat());
6530 is_ascii_ = content.IsAscii();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006531 if (is_ascii_) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006532 start_ = content.ToAsciiVector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006533 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006534 start_ = content.ToUC16Vector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006535 }
6536}
6537
6538
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006539void StringInputBuffer::Seek(unsigned pos) {
6540 Reset(pos, input_);
6541}
6542
6543
6544void SafeStringInputBuffer::Seek(unsigned pos) {
6545 Reset(pos, input_);
6546}
6547
6548
6549// This method determines the type of string involved and then copies
6550// a whole chunk of characters into a buffer. It can be used with strings
6551// that have been glued together to form a ConsString and which must cooperate
6552// to fill up a buffer.
6553void String::ReadBlockIntoBuffer(String* input,
6554 ReadBlockBuffer* rbb,
6555 unsigned* offset_ptr,
6556 unsigned max_chars) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006557 ASSERT(*offset_ptr <= (unsigned)input->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006558 if (max_chars == 0) return;
6559
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006560 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006561 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006562 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006563 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564 offset_ptr,
6565 max_chars);
6566 return;
6567 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006568 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569 offset_ptr,
6570 max_chars);
6571 return;
6572 }
6573 case kConsStringTag:
6574 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
6575 offset_ptr,
6576 max_chars);
6577 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006578 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006579 if (input->IsAsciiRepresentation()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006580 ExternalAsciiString::cast(input)->
6581 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
6582 } else {
6583 ExternalTwoByteString::cast(input)->
6584 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6585 offset_ptr,
6586 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587 }
6588 return;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006589 case kSlicedStringTag:
6590 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
6591 offset_ptr,
6592 max_chars);
6593 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594 default:
6595 break;
6596 }
6597
6598 UNREACHABLE();
6599 return;
6600}
6601
6602
6603const unibrow::byte* String::ReadBlock(String* input,
6604 unibrow::byte* util_buffer,
6605 unsigned capacity,
6606 unsigned* remaining,
6607 unsigned* offset_ptr) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006608 ASSERT(*offset_ptr <= (unsigned)input->length());
6609 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6611 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006612 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613 *remaining = rbb.remaining;
6614 return answer;
6615}
6616
6617
6618const unibrow::byte* String::ReadBlock(String** raw_input,
6619 unibrow::byte* util_buffer,
6620 unsigned capacity,
6621 unsigned* remaining,
6622 unsigned* offset_ptr) {
6623 Handle<String> input(raw_input);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006624 ASSERT(*offset_ptr <= (unsigned)input->length());
6625 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006626 if (chars > capacity) chars = capacity;
6627 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6628 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006629 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630 *remaining = rbb.remaining;
6631 return rbb.util_buffer;
6632}
6633
6634
6635// This will iterate unless the block of string data spans two 'halves' of
6636// a ConsString, in which case it will recurse. Since the block of string
6637// data to be read has a maximum size this limits the maximum recursion
6638// depth to something sane. Since C++ does not have tail call recursion
6639// elimination, the iteration must be explicit.
6640void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6641 unsigned* offset_ptr,
6642 unsigned max_chars) {
6643 ConsString* current = this;
6644 unsigned offset = *offset_ptr;
6645 int offset_correction = 0;
6646
6647 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006648 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006649 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006650 if (left_length > offset &&
6651 max_chars <= left_length - offset) {
6652 // Left hand side only - iterate unless we have reached the bottom of
6653 // the cons tree.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006654 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655 current = ConsString::cast(left);
6656 continue;
6657 } else {
6658 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
6659 *offset_ptr = offset + offset_correction;
6660 return;
6661 }
6662 } else if (left_length <= offset) {
6663 // Right hand side only - iterate unless we have reached the bottom of
6664 // the cons tree.
6665 offset -= left_length;
6666 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006667 String* right = current->second();
6668 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669 current = ConsString::cast(right);
6670 continue;
6671 } else {
6672 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6673 *offset_ptr = offset + offset_correction;
6674 return;
6675 }
6676 } else {
6677 // The block to be read spans two sides of the ConsString, so we recurse.
6678 // First recurse on the left.
6679 max_chars -= left_length - offset;
6680 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
6681 // We may have reached the max or there may not have been enough space
6682 // in the buffer for the characters in the left hand side.
6683 if (offset == left_length) {
6684 // Recurse on the right.
6685 String* right = String::cast(current->second());
6686 offset -= left_length;
6687 offset_correction += left_length;
6688 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6689 }
6690 *offset_ptr = offset + offset_correction;
6691 return;
6692 }
6693 }
6694}
6695
6696
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006697uint16_t ConsString::ConsStringGet(int index) {
6698 ASSERT(index >= 0 && index < this->length());
6699
6700 // Check for a flattened cons string
ager@chromium.org870a0b62008-11-04 11:43:05 +00006701 if (second()->length() == 0) {
6702 String* left = first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006703 return left->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006704 }
6705
6706 String* string = String::cast(this);
6707
6708 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006709 if (StringShape(string).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006710 ConsString* cons_string = ConsString::cast(string);
ager@chromium.org870a0b62008-11-04 11:43:05 +00006711 String* left = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006712 if (left->length() > index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006713 string = left;
6714 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006715 index -= left->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006716 string = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006717 }
6718 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006719 return string->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006720 }
6721 }
6722
6723 UNREACHABLE();
6724 return 0;
6725}
6726
6727
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006728uint16_t SlicedString::SlicedStringGet(int index) {
6729 return parent()->Get(offset() + index);
6730}
6731
6732
6733const unibrow::byte* SlicedString::SlicedStringReadBlock(
6734 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6735 unsigned offset = this->offset();
6736 *offset_ptr += offset;
6737 const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
6738 buffer, offset_ptr, chars);
6739 *offset_ptr -= offset;
6740 return answer;
6741}
6742
6743
6744void SlicedString::SlicedStringReadBlockIntoBuffer(
6745 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6746 unsigned offset = this->offset();
6747 *offset_ptr += offset;
6748 String::ReadBlockIntoBuffer(String::cast(parent()),
6749 buffer, offset_ptr, chars);
6750 *offset_ptr -= offset;
6751}
6752
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006753template <typename sinkchar>
6754void String::WriteToFlat(String* src,
6755 sinkchar* sink,
6756 int f,
6757 int t) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006758 String* source = src;
6759 int from = f;
6760 int to = t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006762 ASSERT(0 <= from && from <= to && to <= source->length());
6763 switch (StringShape(source).full_representation_tag()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006764 case kAsciiStringTag | kExternalStringTag: {
6765 CopyChars(sink,
erikcorry0ad885c2011-11-21 13:51:57 +00006766 ExternalAsciiString::cast(source)->GetChars() + from,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006767 to - from);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006768 return;
6769 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006770 case kTwoByteStringTag | kExternalStringTag: {
6771 const uc16* data =
erikcorry0ad885c2011-11-21 13:51:57 +00006772 ExternalTwoByteString::cast(source)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006773 CopyChars(sink,
6774 data + from,
6775 to - from);
6776 return;
6777 }
6778 case kAsciiStringTag | kSeqStringTag: {
6779 CopyChars(sink,
6780 SeqAsciiString::cast(source)->GetChars() + from,
6781 to - from);
6782 return;
6783 }
6784 case kTwoByteStringTag | kSeqStringTag: {
6785 CopyChars(sink,
6786 SeqTwoByteString::cast(source)->GetChars() + from,
6787 to - from);
6788 return;
6789 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006790 case kAsciiStringTag | kConsStringTag:
6791 case kTwoByteStringTag | kConsStringTag: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006792 ConsString* cons_string = ConsString::cast(source);
ager@chromium.org870a0b62008-11-04 11:43:05 +00006793 String* first = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006794 int boundary = first->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006795 if (to - boundary >= boundary - from) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 // Right hand side is longer. Recurse over left.
6797 if (from < boundary) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006798 WriteToFlat(first, sink, from, boundary);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006799 sink += boundary - from;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800 from = 0;
6801 } else {
6802 from -= boundary;
6803 }
6804 to -= boundary;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006805 source = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006806 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006807 // Left hand side is longer. Recurse over right.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808 if (to > boundary) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006809 String* second = cons_string->second();
ulan@chromium.org812308e2012-02-29 15:58:45 +00006810 // When repeatedly appending to a string, we get a cons string that
6811 // is unbalanced to the left, a list, essentially. We inline the
6812 // common case of sequential ascii right child.
6813 if (to - boundary == 1) {
6814 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
6815 } else if (second->IsSeqAsciiString()) {
6816 CopyChars(sink + boundary - from,
6817 SeqAsciiString::cast(second)->GetChars(),
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006818 to - boundary);
ulan@chromium.org812308e2012-02-29 15:58:45 +00006819 } else {
6820 WriteToFlat(second,
6821 sink + boundary - from,
6822 0,
6823 to - boundary);
6824 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006825 to = boundary;
6826 }
6827 source = first;
6828 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006829 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006830 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006831 case kAsciiStringTag | kSlicedStringTag:
6832 case kTwoByteStringTag | kSlicedStringTag: {
6833 SlicedString* slice = SlicedString::cast(source);
6834 unsigned offset = slice->offset();
6835 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
6836 return;
6837 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838 }
6839 }
6840}
6841
6842
ager@chromium.org7c537e22008-10-16 08:43:32 +00006843template <typename IteratorA, typename IteratorB>
6844static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
6845 // General slow case check. We know that the ia and ib iterators
6846 // have the same length.
6847 while (ia->has_more()) {
6848 uc32 ca = ia->GetNext();
6849 uc32 cb = ib->GetNext();
6850 if (ca != cb)
6851 return false;
6852 }
6853 return true;
6854}
6855
6856
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006857// Compares the contents of two strings by reading and comparing
6858// int-sized blocks of characters.
6859template <typename Char>
6860static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
6861 int length = a.length();
6862 ASSERT_EQ(length, b.length());
6863 const Char* pa = a.start();
6864 const Char* pb = b.start();
6865 int i = 0;
ager@chromium.org9085a012009-05-11 19:22:57 +00006866#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006867 // If this architecture isn't comfortable reading unaligned ints
6868 // then we have to check that the strings are aligned before
6869 // comparing them blockwise.
6870 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
6871 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
6872 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006873 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006874#endif
6875 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
6876 int endpoint = length - kStepSize;
6877 // Compare blocks until we reach near the end of the string.
6878 for (; i <= endpoint; i += kStepSize) {
6879 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
6880 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
6881 if (wa != wb) {
6882 return false;
6883 }
6884 }
ager@chromium.org9085a012009-05-11 19:22:57 +00006885#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006886 }
6887#endif
6888 // Compare the remaining characters that didn't fit into a block.
6889 for (; i < length; i++) {
6890 if (a[i] != b[i]) {
6891 return false;
6892 }
6893 }
6894 return true;
6895}
6896
6897
ager@chromium.org7c537e22008-10-16 08:43:32 +00006898template <typename IteratorA>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006899static inline bool CompareStringContentsPartial(Isolate* isolate,
6900 IteratorA* ia,
6901 String* b) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006902 String::FlatContent content = b->GetFlatContent();
6903 if (content.IsFlat()) {
6904 if (content.IsAscii()) {
6905 VectorIterator<char> ib(content.ToAsciiVector());
ager@chromium.org7c537e22008-10-16 08:43:32 +00006906 return CompareStringContents(ia, &ib);
6907 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006908 VectorIterator<uc16> ib(content.ToUC16Vector());
ager@chromium.org7c537e22008-10-16 08:43:32 +00006909 return CompareStringContents(ia, &ib);
6910 }
6911 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006912 isolate->objects_string_compare_buffer_b()->Reset(0, b);
6913 return CompareStringContents(ia,
6914 isolate->objects_string_compare_buffer_b());
ager@chromium.org7c537e22008-10-16 08:43:32 +00006915 }
6916}
6917
6918
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006919bool String::SlowEquals(String* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006920 // Fast check: negative check with lengths.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006921 int len = length();
6922 if (len != other->length()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006923 if (len == 0) return true;
6924
6925 // Fast check: if hash code is computed for both strings
6926 // a fast negative check can be performed.
6927 if (HasHashCode() && other->HasHashCode()) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006928#ifdef DEBUG
6929 if (FLAG_enable_slow_asserts) {
6930 if (Hash() != other->Hash()) {
6931 bool found_difference = false;
6932 for (int i = 0; i < len; i++) {
6933 if (Get(i) != other->Get(i)) {
6934 found_difference = true;
6935 break;
6936 }
6937 }
6938 ASSERT(found_difference);
6939 }
6940 }
6941#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006942 if (Hash() != other->Hash()) return false;
6943 }
6944
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006945 // We know the strings are both non-empty. Compare the first chars
6946 // before we try to flatten the strings.
6947 if (this->Get(0) != other->Get(0)) return false;
6948
6949 String* lhs = this->TryFlattenGetString();
6950 String* rhs = other->TryFlattenGetString();
6951
6952 if (StringShape(lhs).IsSequentialAscii() &&
6953 StringShape(rhs).IsSequentialAscii()) {
6954 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
6955 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006956 return CompareRawStringContents(Vector<const char>(str1, len),
6957 Vector<const char>(str2, len));
6958 }
6959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006960 Isolate* isolate = GetIsolate();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006961 String::FlatContent lhs_content = lhs->GetFlatContent();
6962 String::FlatContent rhs_content = rhs->GetFlatContent();
6963 if (lhs_content.IsFlat()) {
6964 if (lhs_content.IsAscii()) {
6965 Vector<const char> vec1 = lhs_content.ToAsciiVector();
6966 if (rhs_content.IsFlat()) {
6967 if (rhs_content.IsAscii()) {
6968 Vector<const char> vec2 = rhs_content.ToAsciiVector();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006969 return CompareRawStringContents(vec1, vec2);
6970 } else {
6971 VectorIterator<char> buf1(vec1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006972 VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006973 return CompareStringContents(&buf1, &ib);
6974 }
6975 } else {
6976 VectorIterator<char> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006977 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6978 return CompareStringContents(&buf1,
6979 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006980 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006981 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006982 Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
6983 if (rhs_content.IsFlat()) {
6984 if (rhs_content.IsAscii()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006985 VectorIterator<uc16> buf1(vec1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006986 VectorIterator<char> ib(rhs_content.ToAsciiVector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006987 return CompareStringContents(&buf1, &ib);
6988 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006989 Vector<const uc16> vec2(rhs_content.ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006990 return CompareRawStringContents(vec1, vec2);
6991 }
6992 } else {
6993 VectorIterator<uc16> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006994 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6995 return CompareStringContents(&buf1,
6996 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006998 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006999 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007000 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
7001 return CompareStringContentsPartial(isolate,
7002 isolate->objects_string_compare_buffer_a(), rhs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007003 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007004}
7005
7006
7007bool String::MarkAsUndetectable() {
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00007008 if (StringShape(this).IsSymbol()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009
7010 Map* map = this->map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007011 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007012 if (map == heap->string_map()) {
7013 this->set_map(heap->undetectable_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014 return true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007015 } else if (map == heap->ascii_string_map()) {
7016 this->set_map(heap->undetectable_ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007017 return true;
7018 }
7019 // Rest cannot be marked as undetectable
7020 return false;
7021}
7022
7023
7024bool String::IsEqualTo(Vector<const char> str) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007025 Isolate* isolate = GetIsolate();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007026 int slen = length();
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007027 Access<UnicodeCache::Utf8Decoder>
7028 decoder(isolate->unicode_cache()->utf8_decoder());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029 decoder->Reset(str.start(), str.length());
7030 int i;
7031 for (i = 0; i < slen && decoder->has_more(); i++) {
7032 uc32 r = decoder->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007033 if (Get(i) != r) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007034 }
7035 return i == slen && !decoder->has_more();
7036}
7037
7038
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00007039bool String::IsAsciiEqualTo(Vector<const char> str) {
7040 int slen = length();
7041 if (str.length() != slen) return false;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007042 FlatContent content = GetFlatContent();
7043 if (content.IsAscii()) {
7044 return CompareChars(content.ToAsciiVector().start(),
7045 str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007046 }
7047 for (int i = 0; i < slen; i++) {
7048 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00007049 }
7050 return true;
7051}
7052
7053
7054bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
7055 int slen = length();
7056 if (str.length() != slen) return false;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007057 FlatContent content = GetFlatContent();
7058 if (content.IsTwoByte()) {
7059 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007060 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00007061 for (int i = 0; i < slen; i++) {
7062 if (Get(i) != str[i]) return false;
7063 }
7064 return true;
7065}
7066
7067
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068uint32_t String::ComputeAndSetHash() {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00007069 // Should only be called if hash code has not yet been computed.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007070 ASSERT(!HasHashCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00007072 const int len = length();
7073
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074 // Compute the hash code.
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00007075 uint32_t field = 0;
7076 if (StringShape(this).IsSequentialAscii()) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00007077 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(),
7078 len,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00007079 GetHeap()->HashSeed());
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00007080 } else if (StringShape(this).IsSequentialTwoByte()) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00007081 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(),
7082 len,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00007083 GetHeap()->HashSeed());
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00007084 } else {
7085 StringInputBuffer buffer(this);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00007086 field = ComputeHashField(&buffer, len, GetHeap()->HashSeed());
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00007087 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007088
7089 // Store the hash code in the object.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007090 set_hash_field(field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091
7092 // Check the hash code is there.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007093 ASSERT(HasHashCode());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00007094 uint32_t result = field >> kHashShift;
7095 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
7096 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007097}
7098
7099
7100bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
7101 uint32_t* index,
7102 int length) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007103 if (length == 0 || length > kMaxArrayIndexSize) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007104 uc32 ch = buffer->GetNext();
7105
7106 // If the string begins with a '0' character, it must only consist
7107 // of it to be a legal array index.
7108 if (ch == '0') {
7109 *index = 0;
7110 return length == 1;
7111 }
7112
7113 // Convert string to uint32 array index; character by character.
7114 int d = ch - '0';
7115 if (d < 0 || d > 9) return false;
7116 uint32_t result = d;
7117 while (buffer->has_more()) {
7118 d = buffer->GetNext() - '0';
7119 if (d < 0 || d > 9) return false;
7120 // Check that the new result is below the 32 bit limit.
7121 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
7122 result = (result * 10) + d;
7123 }
7124
7125 *index = result;
7126 return true;
7127}
7128
7129
7130bool String::SlowAsArrayIndex(uint32_t* index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007131 if (length() <= kMaxCachedArrayIndexLength) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007132 Hash(); // force computation of hash code
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007133 uint32_t field = hash_field();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007134 if ((field & kIsNotArrayIndexMask) != 0) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007135 // Isolate the array index form the full hash field.
7136 *index = (kArrayIndexHashMask & field) >> kHashShift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007137 return true;
7138 } else {
7139 StringInputBuffer buffer(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007140 return ComputeArrayIndex(&buffer, index, length());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007141 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007142}
7143
7144
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007145uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007146 // For array indexes mix the length into the hash as an array index could
7147 // be zero.
7148 ASSERT(length > 0);
7149 ASSERT(length <= String::kMaxArrayIndexSize);
7150 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
7151 (1 << String::kArrayIndexValueBits));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007152
7153 value <<= String::kHashShift;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007154 value |= length << String::kArrayIndexHashLengthShift;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007155
7156 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
7157 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
7158 (value & String::kContainsCachedArrayIndexMask) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007159 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007160}
7161
7162
ager@chromium.org7c537e22008-10-16 08:43:32 +00007163uint32_t StringHasher::GetHashField() {
7164 ASSERT(is_valid());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007165 if (length_ <= String::kMaxHashCalcLength) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007166 if (is_array_index()) {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007167 return MakeArrayIndexHash(array_index(), length_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00007168 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007169 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
ager@chromium.org7c537e22008-10-16 08:43:32 +00007170 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007171 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007172 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007173}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007174
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007175
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007176uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00007177 int length,
7178 uint32_t seed) {
7179 StringHasher hasher(length, seed);
ager@chromium.org7c537e22008-10-16 08:43:32 +00007180
7181 // Very long strings have a trivial hash that doesn't inspect the
7182 // string contents.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007183 if (hasher.has_trivial_hash()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007184 return hasher.GetHashField();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007185 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007186
7187 // Do the iterative array index computation as long as there is a
7188 // chance this is an array index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007189 while (buffer->has_more() && hasher.is_array_index()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007190 hasher.AddCharacter(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007191 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007192
7193 // Process the remaining characters without updating the array
7194 // index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007195 while (buffer->has_more()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007196 hasher.AddCharacterNoIndex(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007197 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007198
7199 return hasher.GetHashField();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007200}
7201
7202
lrn@chromium.org303ada72010-10-27 09:33:13 +00007203MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007204 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007205 if (start == 0 && end == length()) return this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007206 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007207 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007208}
7209
7210
7211void String::PrintOn(FILE* file) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007212 int length = this->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007213 for (int i = 0; i < length; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007214 fprintf(file, "%c", Get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007215 }
7216}
7217
7218
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007219void Map::CreateOneBackPointer(Object* transition_target) {
7220 if (!transition_target->IsMap()) return;
7221 Map* target = Map::cast(transition_target);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007222#ifdef DEBUG
7223 // Verify target.
7224 Object* source_prototype = prototype();
7225 Object* target_prototype = target->prototype();
7226 ASSERT(source_prototype->IsJSReceiver() ||
7227 source_prototype->IsMap() ||
7228 source_prototype->IsNull());
7229 ASSERT(target_prototype->IsJSReceiver() ||
7230 target_prototype->IsNull());
7231 ASSERT(source_prototype->IsMap() ||
7232 source_prototype == target_prototype);
7233#endif
7234 // Point target back to source. set_prototype() will not let us set
7235 // the prototype to a map, as we do here.
7236 *RawField(target, kPrototypeOffset) = this;
7237}
7238
7239
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007240void Map::CreateBackPointers() {
7241 DescriptorArray* descriptors = instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00007242 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007243 switch (descriptors->GetType(i)) {
7244 case MAP_TRANSITION:
7245 case CONSTANT_TRANSITION:
7246 CreateOneBackPointer(descriptors->GetValue(i));
7247 break;
7248 case ELEMENTS_TRANSITION: {
7249 Object* object = descriptors->GetValue(i);
7250 if (object->IsMap()) {
7251 CreateOneBackPointer(object);
7252 } else {
7253 FixedArray* array = FixedArray::cast(object);
7254 for (int i = 0; i < array->length(); ++i) {
7255 CreateOneBackPointer(array->get(i));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007256 }
7257 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007258 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007259 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007260 case CALLBACKS: {
7261 Object* object = descriptors->GetValue(i);
7262 if (object->IsAccessorPair()) {
7263 AccessorPair* accessors = AccessorPair::cast(object);
7264 CreateOneBackPointer(accessors->getter());
7265 CreateOneBackPointer(accessors->setter());
7266 }
7267 break;
7268 }
7269 case NORMAL:
7270 case FIELD:
7271 case CONSTANT_FUNCTION:
7272 case HANDLER:
7273 case INTERCEPTOR:
7274 case NULL_DESCRIPTOR:
7275 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007276 }
7277 }
7278}
7279
7280
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007281bool Map::RestoreOneBackPointer(Object* object,
7282 Object* real_prototype,
7283 bool* keep_entry) {
7284 if (!object->IsMap()) return false;
7285 Map* map = Map::cast(object);
7286 if (Marking::MarkBitFrom(map).Get()) {
7287 *keep_entry = true;
7288 return false;
7289 }
7290 ASSERT(map->prototype() == this || map->prototype() == real_prototype);
7291 // Getter prototype() is read-only, set_prototype() has side effects.
7292 *RawField(map, Map::kPrototypeOffset) = real_prototype;
7293 return true;
7294}
7295
7296
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007297void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007298 DescriptorArray* d = DescriptorArray::cast(
danno@chromium.org40cb8782011-05-25 07:58:50 +00007299 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
7300 if (d->IsEmpty()) return;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007301 Smi* NullDescriptorDetails =
7302 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007303 FixedArray* contents = FixedArray::cast(
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007304 d->get(DescriptorArray::kContentArrayIndex));
7305 ASSERT(contents->length() >= 2);
7306 for (int i = 0; i < contents->length(); i += 2) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007307 // If the pair (value, details) is a map transition, check if the target is
7308 // live. If not, null the descriptor. Also drop the back pointer for that
7309 // map transition, so that this map is not reached again by following a back
7310 // pointer from a non-live object.
7311 bool keep_entry = false;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007312 PropertyDetails details(Smi::cast(contents->get(i + 1)));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007313 switch (details.type()) {
7314 case MAP_TRANSITION:
7315 case CONSTANT_TRANSITION:
7316 RestoreOneBackPointer(contents->get(i), real_prototype, &keep_entry);
7317 break;
7318 case ELEMENTS_TRANSITION: {
7319 Object* object = contents->get(i);
7320 if (object->IsMap()) {
7321 RestoreOneBackPointer(object, real_prototype, &keep_entry);
7322 } else {
7323 FixedArray* array = FixedArray::cast(object);
7324 for (int j = 0; j < array->length(); ++j) {
7325 if (RestoreOneBackPointer(array->get(j),
7326 real_prototype,
7327 &keep_entry)) {
7328 array->set_undefined(j);
7329 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007330 }
7331 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007332 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007333 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007334 case CALLBACKS: {
7335 Object* object = contents->get(i);
7336 if (object->IsAccessorPair()) {
7337 AccessorPair* accessors = AccessorPair::cast(object);
7338 if (RestoreOneBackPointer(accessors->getter(),
7339 real_prototype,
7340 &keep_entry)) {
7341 accessors->set_getter(heap->the_hole_value());
7342 }
7343 if (RestoreOneBackPointer(accessors->setter(),
7344 real_prototype,
7345 &keep_entry)) {
7346 accessors->set_setter(heap->the_hole_value());
7347 }
7348 } else {
7349 keep_entry = true;
7350 }
7351 break;
7352 }
7353 case NORMAL:
7354 case FIELD:
7355 case CONSTANT_FUNCTION:
7356 case HANDLER:
7357 case INTERCEPTOR:
7358 case NULL_DESCRIPTOR:
7359 keep_entry = true;
7360 break;
7361 }
7362 // Make sure that an entry containing only dead transitions gets collected.
7363 // What we *really* want to do here is removing this entry completely, but
7364 // for technical reasons we can't do this, so we zero it out instead.
7365 if (!keep_entry) {
7366 contents->set_unchecked(i + 1, NullDescriptorDetails);
7367 contents->set_null_unchecked(heap, i);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007368 }
7369 }
7370}
7371
7372
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007373int Map::Hash() {
7374 // For performance reasons we only hash the 3 most variable fields of a map:
7375 // constructor, prototype and bit_field2.
7376
7377 // Shift away the tag.
7378 int hash = (static_cast<uint32_t>(
7379 reinterpret_cast<uintptr_t>(constructor())) >> 2);
7380
7381 // XOR-ing the prototype and constructor directly yields too many zero bits
7382 // when the two pointers are close (which is fairly common).
7383 // To avoid this we shift the prototype 4 bits relatively to the constructor.
7384 hash ^= (static_cast<uint32_t>(
7385 reinterpret_cast<uintptr_t>(prototype())) << 2);
7386
7387 return hash ^ (hash >> 16) ^ bit_field2();
7388}
7389
7390
7391bool Map::EquivalentToForNormalization(Map* other,
7392 PropertyNormalizationMode mode) {
7393 return
7394 constructor() == other->constructor() &&
7395 prototype() == other->prototype() &&
7396 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
7397 0 :
7398 other->inobject_properties()) &&
7399 instance_type() == other->instance_type() &&
7400 bit_field() == other->bit_field() &&
7401 bit_field2() == other->bit_field2() &&
7402 (bit_field3() & ~(1<<Map::kIsShared)) ==
7403 (other->bit_field3() & ~(1<<Map::kIsShared));
7404}
7405
7406
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00007407void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
7408 // Iterate over all fields in the body but take care in dealing with
7409 // the code entry.
7410 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
7411 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
7412 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
7413}
7414
7415
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007416void JSFunction::MarkForLazyRecompilation() {
7417 ASSERT(is_compiled() && !IsOptimized());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007418 ASSERT(shared()->allows_lazy_compilation() ||
7419 code()->optimizable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007420 Builtins* builtins = GetIsolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007421 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007422}
7423
7424
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007425bool SharedFunctionInfo::EnsureCompiled(Handle<SharedFunctionInfo> shared,
7426 ClearExceptionFlag flag) {
7427 return shared->is_compiled() || CompileLazy(shared, flag);
7428}
7429
7430
7431static bool CompileLazyHelper(CompilationInfo* info,
7432 ClearExceptionFlag flag) {
7433 // Compile the source information to a code object.
7434 ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
7435 ASSERT(!info->isolate()->has_pending_exception());
7436 bool result = Compiler::CompileLazy(info);
7437 ASSERT(result != Isolate::Current()->has_pending_exception());
7438 if (!result && flag == CLEAR_EXCEPTION) {
7439 info->isolate()->clear_pending_exception();
7440 }
7441 return result;
7442}
7443
7444
7445bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
7446 ClearExceptionFlag flag) {
7447 CompilationInfo info(shared);
7448 return CompileLazyHelper(&info, flag);
7449}
7450
7451
7452bool JSFunction::CompileLazy(Handle<JSFunction> function,
7453 ClearExceptionFlag flag) {
7454 bool result = true;
7455 if (function->shared()->is_compiled()) {
7456 function->ReplaceCode(function->shared()->code());
7457 function->shared()->set_code_age(0);
7458 } else {
7459 CompilationInfo info(function);
7460 result = CompileLazyHelper(&info, flag);
7461 ASSERT(!result || function->is_compiled());
7462 }
7463 return result;
7464}
7465
7466
7467bool JSFunction::CompileOptimized(Handle<JSFunction> function,
7468 int osr_ast_id,
7469 ClearExceptionFlag flag) {
7470 CompilationInfo info(function);
7471 info.SetOptimizing(osr_ast_id);
7472 return CompileLazyHelper(&info, flag);
7473}
7474
7475
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007476bool JSFunction::IsInlineable() {
7477 if (IsBuiltin()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007478 SharedFunctionInfo* shared_info = shared();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007479 // Check that the function has a script associated with it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007480 if (!shared_info->script()->IsScript()) return false;
7481 if (shared_info->optimization_disabled()) return false;
7482 Code* code = shared_info->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007483 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
7484 // If we never ran this (unlikely) then lets try to optimize it.
7485 if (code->kind() != Code::FUNCTION) return true;
7486 return code->optimizable();
7487}
7488
7489
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007490MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007491 ASSERT(value->IsJSObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007492 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007493 if (has_initial_map()) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007494 // If the function has allocated the initial map
7495 // replace it with a copy containing the new prototype.
7496 Map* new_map;
7497 MaybeObject* maybe_new_map = initial_map()->CopyDropTransitions();
7498 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
7499 new_map->set_prototype(value);
7500 MaybeObject* maybe_object =
7501 set_initial_map_and_cache_transitions(new_map);
7502 if (maybe_object->IsFailure()) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007503 } else {
7504 // Put the value in the initial map field until an initial map is
7505 // needed. At that point, a new initial map is created and the
7506 // prototype is put into the initial map where it belongs.
7507 set_prototype_or_initial_map(value);
7508 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007509 heap->ClearInstanceofCache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007510 return value;
7511}
7512
7513
lrn@chromium.org303ada72010-10-27 09:33:13 +00007514MaybeObject* JSFunction::SetPrototype(Object* value) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007515 ASSERT(should_have_prototype());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007516 Object* construct_prototype = value;
7517
7518 // If the value is not a JSObject, store the value in the map's
7519 // constructor field so it can be accessed. Also, set the prototype
7520 // used for constructing objects to the original object prototype.
7521 // See ECMA-262 13.2.2.
7522 if (!value->IsJSObject()) {
7523 // Copy the map so this does not affect unrelated functions.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007524 // Remove map transitions because they point to maps with a
7525 // different prototype.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007526 Map* new_map;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007527 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007528 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007529 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007530 Heap* heap = new_map->GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007531 set_map(new_map);
7532 new_map->set_constructor(value);
7533 new_map->set_non_instance_prototype(true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007534 construct_prototype =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007535 heap->isolate()->context()->global_context()->
7536 initial_object_prototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007537 } else {
7538 map()->set_non_instance_prototype(false);
7539 }
7540
7541 return SetInstancePrototype(construct_prototype);
7542}
7543
7544
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007545Object* JSFunction::RemovePrototype() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007546 Context* global_context = context()->global_context();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007547 Map* no_prototype_map = shared()->is_classic_mode()
7548 ? global_context->function_without_prototype_map()
7549 : global_context->strict_mode_function_without_prototype_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007550
7551 if (map() == no_prototype_map) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007552 // Be idempotent.
7553 return this;
7554 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007555
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007556 ASSERT(map() == (shared()->is_classic_mode()
7557 ? global_context->function_map()
7558 : global_context->strict_mode_function_map()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007559
7560 set_map(no_prototype_map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007561 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007562 return this;
7563}
7564
7565
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007566Object* JSFunction::SetInstanceClassName(String* name) {
7567 shared()->set_instance_class_name(name);
7568 return this;
7569}
7570
7571
whesse@chromium.org023421e2010-12-21 12:19:12 +00007572void JSFunction::PrintName(FILE* out) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007573 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
whesse@chromium.org023421e2010-12-21 12:19:12 +00007574 PrintF(out, "%s", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007575}
7576
7577
ager@chromium.org236ad962008-09-25 09:45:57 +00007578Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
7579 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
7580}
7581
7582
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007583MaybeObject* Oddball::Initialize(const char* to_string,
7584 Object* to_number,
7585 byte kind) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007586 String* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007587 { MaybeObject* maybe_symbol =
7588 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007589 if (!maybe_symbol->To(&symbol)) return maybe_symbol;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007590 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007591 set_to_string(symbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007592 set_to_number(to_number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007593 set_kind(kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007594 return this;
7595}
7596
7597
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00007598String* SharedFunctionInfo::DebugName() {
7599 Object* n = name();
7600 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
7601 return String::cast(n);
7602}
7603
7604
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007605bool SharedFunctionInfo::HasSourceCode() {
7606 return !script()->IsUndefined() &&
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007607 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007608}
7609
7610
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00007611Handle<Object> SharedFunctionInfo::GetSourceCode() {
7612 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
7613 Handle<String> source(String::cast(Script::cast(script())->source()));
7614 return SubString(source, start_position(), end_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007615}
7616
7617
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007618int SharedFunctionInfo::SourceSize() {
7619 return end_position() - start_position();
7620}
7621
7622
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007623int SharedFunctionInfo::CalculateInstanceSize() {
7624 int instance_size =
7625 JSObject::kHeaderSize +
7626 expected_nof_properties() * kPointerSize;
7627 if (instance_size > JSObject::kMaxInstanceSize) {
7628 instance_size = JSObject::kMaxInstanceSize;
7629 }
7630 return instance_size;
7631}
7632
7633
7634int SharedFunctionInfo::CalculateInObjectProperties() {
7635 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
7636}
7637
7638
ager@chromium.org5c838252010-02-19 08:53:10 +00007639bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
7640 // Check the basic conditions for generating inline constructor code.
7641 if (!FLAG_inline_new
7642 || !has_only_simple_this_property_assignments()
7643 || this_property_assignments_count() == 0) {
7644 return false;
7645 }
7646
7647 // If the prototype is null inline constructors cause no problems.
7648 if (!prototype->IsJSObject()) {
7649 ASSERT(prototype->IsNull());
7650 return true;
7651 }
7652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007653 Heap* heap = GetHeap();
7654
ager@chromium.org5c838252010-02-19 08:53:10 +00007655 // Traverse the proposed prototype chain looking for setters for properties of
7656 // the same names as are set by the inline constructor.
7657 for (Object* obj = prototype;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007658 obj != heap->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007659 obj = obj->GetPrototype()) {
7660 JSObject* js_object = JSObject::cast(obj);
7661 for (int i = 0; i < this_property_assignments_count(); i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007662 LookupResult result(heap->isolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00007663 String* name = GetThisPropertyAssignmentName(i);
7664 js_object->LocalLookupRealNamedProperty(name, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007665 if (result.IsFound() && result.type() == CALLBACKS) {
ager@chromium.org5c838252010-02-19 08:53:10 +00007666 return false;
7667 }
7668 }
7669 }
7670
7671 return true;
7672}
7673
7674
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00007675void SharedFunctionInfo::ForbidInlineConstructor() {
7676 set_compiler_hints(BooleanBit::set(compiler_hints(),
7677 kHasOnlySimpleThisPropertyAssignments,
7678 false));
7679}
7680
7681
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007682void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007683 bool only_simple_this_property_assignments,
7684 FixedArray* assignments) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007685 set_compiler_hints(BooleanBit::set(compiler_hints(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007686 kHasOnlySimpleThisPropertyAssignments,
7687 only_simple_this_property_assignments));
7688 set_this_property_assignments(assignments);
7689 set_this_property_assignments_count(assignments->length() / 3);
7690}
7691
7692
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007693void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007694 Heap* heap = GetHeap();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007695 set_compiler_hints(BooleanBit::set(compiler_hints(),
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007696 kHasOnlySimpleThisPropertyAssignments,
7697 false));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007698 set_this_property_assignments(heap->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007699 set_this_property_assignments_count(0);
7700}
7701
7702
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007703String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
7704 Object* obj = this_property_assignments();
7705 ASSERT(obj->IsFixedArray());
7706 ASSERT(index < this_property_assignments_count());
7707 obj = FixedArray::cast(obj)->get(index * 3);
7708 ASSERT(obj->IsString());
7709 return String::cast(obj);
7710}
7711
7712
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007713bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
7714 Object* obj = this_property_assignments();
7715 ASSERT(obj->IsFixedArray());
7716 ASSERT(index < this_property_assignments_count());
7717 obj = FixedArray::cast(obj)->get(index * 3 + 1);
7718 return Smi::cast(obj)->value() != -1;
7719}
7720
7721
7722int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
7723 ASSERT(IsThisPropertyAssignmentArgument(index));
7724 Object* obj =
7725 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
7726 return Smi::cast(obj)->value();
7727}
7728
7729
7730Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
7731 ASSERT(!IsThisPropertyAssignmentArgument(index));
7732 Object* obj =
7733 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
7734 return obj;
7735}
7736
7737
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007738// Support function for printing the source code to a StringStream
7739// without any allocation in the heap.
7740void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
7741 int max_length) {
7742 // For some native functions there is no source.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007743 if (!HasSourceCode()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007744 accumulator->Add("<No Source>");
7745 return;
7746 }
7747
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007748 // Get the source for the script which this function came from.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007749 // Don't use String::cast because we don't want more assertion errors while
7750 // we are already creating a stack dump.
7751 String* script_source =
7752 reinterpret_cast<String*>(Script::cast(script())->source());
7753
7754 if (!script_source->LooksValid()) {
7755 accumulator->Add("<Invalid Source>");
7756 return;
7757 }
7758
7759 if (!is_toplevel()) {
7760 accumulator->Add("function ");
7761 Object* name = this->name();
7762 if (name->IsString() && String::cast(name)->length() > 0) {
7763 accumulator->PrintName(name);
7764 }
7765 }
7766
7767 int len = end_position() - start_position();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007768 if (len <= max_length || max_length < 0) {
7769 accumulator->Put(script_source, start_position(), end_position());
7770 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007771 accumulator->Put(script_source,
7772 start_position(),
7773 start_position() + max_length);
7774 accumulator->Add("...\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007775 }
7776}
7777
7778
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007779static bool IsCodeEquivalent(Code* code, Code* recompiled) {
7780 if (code->instruction_size() != recompiled->instruction_size()) return false;
7781 ByteArray* code_relocation = code->relocation_info();
7782 ByteArray* recompiled_relocation = recompiled->relocation_info();
7783 int length = code_relocation->length();
7784 if (length != recompiled_relocation->length()) return false;
7785 int compare = memcmp(code_relocation->GetDataStartAddress(),
7786 recompiled_relocation->GetDataStartAddress(),
7787 length);
7788 return compare == 0;
7789}
7790
7791
7792void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
7793 ASSERT(!has_deoptimization_support());
7794 AssertNoAllocation no_allocation;
7795 Code* code = this->code();
7796 if (IsCodeEquivalent(code, recompiled)) {
7797 // Copy the deoptimization data from the recompiled code.
7798 code->set_deoptimization_data(recompiled->deoptimization_data());
7799 code->set_has_deoptimization_support(true);
7800 } else {
7801 // TODO(3025757): In case the recompiled isn't equivalent to the
7802 // old code, we have to replace it. We should try to avoid this
7803 // altogether because it flushes valuable type feedback by
7804 // effectively resetting all IC state.
7805 set_code(recompiled);
7806 }
7807 ASSERT(has_deoptimization_support());
7808}
7809
7810
yangguo@chromium.org56454712012-02-16 15:33:53 +00007811void SharedFunctionInfo::DisableOptimization() {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00007812 // Disable optimization for the shared function info and mark the
7813 // code as non-optimizable. The marker on the shared function info
7814 // is there because we flush non-optimized code thereby loosing the
7815 // non-optimizable information for the code. When the code is
7816 // regenerated and set on the shared function info it is marked as
7817 // non-optimizable if optimization is disabled for the shared
7818 // function info.
7819 set_optimization_disabled(true);
7820 // Code should be the lazy compilation stub or else unoptimized. If the
7821 // latter, disable optimization for the code too.
7822 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
7823 if (code()->kind() == Code::FUNCTION) {
7824 code()->set_optimizable(false);
7825 }
7826 if (FLAG_trace_opt) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007827 PrintF("[disabled optimization for %s]\n", *DebugName()->ToCString());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00007828 }
7829}
7830
7831
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007832bool SharedFunctionInfo::VerifyBailoutId(int id) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007833 ASSERT(id != AstNode::kNoNumber);
7834 Code* unoptimized = code();
7835 DeoptimizationOutputData* data =
7836 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
7837 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
7838 USE(ignore);
7839 return true; // Return true if there was no ASSERT.
7840}
7841
7842
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007843void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
7844 ASSERT(!IsInobjectSlackTrackingInProgress());
7845
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00007846 if (!FLAG_clever_optimizations) return;
7847
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007848 // Only initiate the tracking the first time.
7849 if (live_objects_may_exist()) return;
7850 set_live_objects_may_exist(true);
7851
7852 // No tracking during the snapshot construction phase.
7853 if (Serializer::enabled()) return;
7854
7855 if (map->unused_property_fields() == 0) return;
7856
7857 // Nonzero counter is a leftover from the previous attempt interrupted
7858 // by GC, keep it.
7859 if (construction_count() == 0) {
7860 set_construction_count(kGenerousAllocationCount);
7861 }
7862 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007863 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007864 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007865 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007866 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007867}
7868
7869
7870// Called from GC, hence reinterpret_cast and unchecked accessors.
7871void SharedFunctionInfo::DetachInitialMap() {
7872 Map* map = reinterpret_cast<Map*>(initial_map());
7873
7874 // Make the map remember to restore the link if it survives the GC.
7875 map->set_bit_field2(
7876 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
7877
7878 // Undo state changes made by StartInobjectTracking (except the
7879 // construction_count). This way if the initial map does not survive the GC
7880 // then StartInobjectTracking will be called again the next time the
7881 // constructor is called. The countdown will continue and (possibly after
7882 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007883 Heap* heap = map->GetHeap();
7884 set_initial_map(heap->raw_unchecked_undefined_value());
7885 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007886 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007887 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007888 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007889 // It is safe to clear the flag: it will be set again if the map is live.
7890 set_live_objects_may_exist(false);
7891}
7892
7893
7894// Called from GC, hence reinterpret_cast and unchecked accessors.
7895void SharedFunctionInfo::AttachInitialMap(Map* map) {
7896 map->set_bit_field2(
7897 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
7898
7899 // Resume inobject slack tracking.
7900 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007901 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007902 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007903 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007904 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007905 // The map survived the gc, so there may be objects referencing it.
7906 set_live_objects_may_exist(true);
7907}
7908
7909
7910static void GetMinInobjectSlack(Map* map, void* data) {
7911 int slack = map->unused_property_fields();
7912 if (*reinterpret_cast<int*>(data) > slack) {
7913 *reinterpret_cast<int*>(data) = slack;
7914 }
7915}
7916
7917
7918static void ShrinkInstanceSize(Map* map, void* data) {
7919 int slack = *reinterpret_cast<int*>(data);
7920 map->set_inobject_properties(map->inobject_properties() - slack);
7921 map->set_unused_property_fields(map->unused_property_fields() - slack);
7922 map->set_instance_size(map->instance_size() - slack * kPointerSize);
7923
7924 // Visitor id might depend on the instance size, recalculate it.
7925 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
7926}
7927
7928
7929void SharedFunctionInfo::CompleteInobjectSlackTracking() {
7930 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
7931 Map* map = Map::cast(initial_map());
7932
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007933 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007934 set_initial_map(heap->undefined_value());
7935 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007936 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007937 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007938 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007939
7940 int slack = map->unused_property_fields();
7941 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
7942 if (slack != 0) {
7943 // Resize the initial map and all maps in its transition tree.
7944 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007945
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007946 // Give the correct expected_nof_properties to initial maps created later.
7947 ASSERT(expected_nof_properties() >= slack);
7948 set_expected_nof_properties(expected_nof_properties() - slack);
7949 }
7950}
7951
7952
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007953#define DECLARE_TAG(ignore1, name, ignore2) name,
7954const char* const VisitorSynchronization::kTags[
7955 VisitorSynchronization::kNumberOfSyncTags] = {
7956 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7957};
7958#undef DECLARE_TAG
7959
7960
7961#define DECLARE_TAG(ignore1, ignore2, name) name,
7962const char* const VisitorSynchronization::kTagNames[
7963 VisitorSynchronization::kNumberOfSyncTags] = {
7964 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7965};
7966#undef DECLARE_TAG
7967
7968
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007969void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ager@chromium.org236ad962008-09-25 09:45:57 +00007970 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007971 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
7972 Object* old_target = target;
7973 VisitPointer(&target);
7974 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007975}
7976
7977
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00007978void ObjectVisitor::VisitCodeEntry(Address entry_address) {
7979 Object* code = Code::GetObjectFromEntryAddress(entry_address);
7980 Object* old_code = code;
7981 VisitPointer(&code);
7982 if (code != old_code) {
7983 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
7984 }
7985}
7986
7987
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007988void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
7989 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
7990 Object* cell = rinfo->target_cell();
7991 Object* old_cell = cell;
7992 VisitPointer(&cell);
7993 if (cell != old_cell) {
7994 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
7995 }
7996}
7997
7998
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007999void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00008000 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
8001 rinfo->IsPatchedReturnSequence()) ||
8002 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
8003 rinfo->IsPatchedDebugBreakSlotSequence()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008004 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
8005 Object* old_target = target;
8006 VisitPointer(&target);
8007 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008008}
8009
8010
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008011void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
8012 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
8013 VisitPointer(rinfo->target_object_address());
8014}
8015
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00008016void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
8017 Address* p = rinfo->target_reference_address();
8018 VisitExternalReferences(p, p + 1);
8019}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008020
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008021void Code::InvalidateRelocation() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008022 set_relocation_info(GetHeap()->empty_byte_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008023}
8024
8025
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008026void Code::Relocate(intptr_t delta) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008027 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
8028 it.rinfo()->apply(delta);
8029 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008030 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008031}
8032
8033
8034void Code::CopyFrom(const CodeDesc& desc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008035 ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
8036
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008037 // copy code
8038 memmove(instruction_start(), desc.buffer, desc.instr_size);
8039
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008040 // copy reloc info
8041 memmove(relocation_start(),
8042 desc.buffer + desc.buffer_size - desc.reloc_size,
8043 desc.reloc_size);
8044
8045 // unbox handles and relocate
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00008046 intptr_t delta = instruction_start() - desc.buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008047 int mode_mask = RelocInfo::kCodeTargetMask |
ager@chromium.org236ad962008-09-25 09:45:57 +00008048 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008049 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008050 RelocInfo::kApplyMask;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008051 Assembler* origin = desc.origin; // Needed to find target_object on X64.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008052 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00008053 RelocInfo::Mode mode = it.rinfo()->rmode();
8054 if (mode == RelocInfo::EMBEDDED_OBJECT) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008055 Handle<Object> p = it.rinfo()->target_object_handle(origin);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008056 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008057 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008058 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008059 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
ager@chromium.org236ad962008-09-25 09:45:57 +00008060 } else if (RelocInfo::IsCodeTarget(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008061 // rewrite code handles in inline cache targets to direct
8062 // pointers to the first instruction in the code object
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008063 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008064 Code* code = Code::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008065 it.rinfo()->set_target_address(code->instruction_start(),
8066 SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008067 } else {
8068 it.rinfo()->apply(delta);
8069 }
8070 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008071 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072}
8073
8074
8075// Locate the source position which is closest to the address in the code. This
8076// is using the source position information embedded in the relocation info.
8077// The position returned is relative to the beginning of the script where the
8078// source for this function is found.
8079int Code::SourcePosition(Address pc) {
8080 int distance = kMaxInt;
ager@chromium.org236ad962008-09-25 09:45:57 +00008081 int position = RelocInfo::kNoPosition; // Initially no position found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008082 // Run through all the relocation info to find the best matching source
8083 // position. All the code needs to be considered as the sequence of the
8084 // instructions in the code does not necessarily follow the same order as the
8085 // source.
8086 RelocIterator it(this, RelocInfo::kPositionMask);
8087 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00008088 // Only look at positions after the current pc.
8089 if (it.rinfo()->pc() < pc) {
8090 // Get position and distance.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008091
8092 int dist = static_cast<int>(pc - it.rinfo()->pc());
8093 int pos = static_cast<int>(it.rinfo()->data());
ager@chromium.org236ad962008-09-25 09:45:57 +00008094 // If this position is closer than the current candidate or if it has the
8095 // same distance as the current candidate and the position is higher then
8096 // this position is the new candidate.
8097 if ((dist < distance) ||
8098 (dist == distance && pos > position)) {
8099 position = pos;
8100 distance = dist;
8101 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008102 }
8103 it.next();
8104 }
8105 return position;
8106}
8107
8108
8109// Same as Code::SourcePosition above except it only looks for statement
8110// positions.
8111int Code::SourceStatementPosition(Address pc) {
8112 // First find the position as close as possible using all position
8113 // information.
8114 int position = SourcePosition(pc);
8115 // Now find the closest statement position before the position.
8116 int statement_position = 0;
8117 RelocIterator it(this, RelocInfo::kPositionMask);
8118 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00008119 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008120 int p = static_cast<int>(it.rinfo()->data());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008121 if (statement_position < p && p <= position) {
8122 statement_position = p;
8123 }
8124 }
8125 it.next();
8126 }
8127 return statement_position;
8128}
8129
8130
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008131SafepointEntry Code::GetSafepointEntry(Address pc) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008132 SafepointTable table(this);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008133 return table.FindEntry(pc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008134}
8135
8136
8137void Code::SetNoStackCheckTable() {
8138 // Indicate the absence of a stack-check table by a table start after the
8139 // end of the instructions. Table start must be aligned, so round up.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008140 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008141}
8142
8143
8144Map* Code::FindFirstMap() {
8145 ASSERT(is_inline_cache_stub());
8146 AssertNoAllocation no_allocation;
8147 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
8148 for (RelocIterator it(this, mask); !it.done(); it.next()) {
8149 RelocInfo* info = it.rinfo();
8150 Object* object = info->target_object();
8151 if (object->IsMap()) return Map::cast(object);
8152 }
8153 return NULL;
8154}
8155
8156
ricow@chromium.org4f693d62011-07-04 14:01:31 +00008157#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008158
whesse@chromium.org023421e2010-12-21 12:19:12 +00008159void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008160 disasm::NameConverter converter;
8161 int deopt_count = DeoptCount();
whesse@chromium.org023421e2010-12-21 12:19:12 +00008162 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008163 if (0 == deopt_count) return;
8164
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008165 PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc",
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008166 FLAG_print_code_verbose ? "commands" : "");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008167 for (int i = 0; i < deopt_count; i++) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008168 PrintF(out, "%6d %6d %6d %6d",
8169 i,
8170 AstId(i)->value(),
8171 ArgumentsStackHeight(i)->value(),
8172 Pc(i)->value());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008173
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008174 if (!FLAG_print_code_verbose) {
8175 PrintF(out, "\n");
8176 continue;
8177 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008178 // Print details of the frame translation.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008179 int translation_index = TranslationIndex(i)->value();
8180 TranslationIterator iterator(TranslationByteArray(), translation_index);
8181 Translation::Opcode opcode =
8182 static_cast<Translation::Opcode>(iterator.Next());
8183 ASSERT(Translation::BEGIN == opcode);
8184 int frame_count = iterator.Next();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008185 int jsframe_count = iterator.Next();
8186 PrintF(out, " %s {frame count=%d, js frame count=%d}\n",
8187 Translation::StringFor(opcode),
8188 frame_count,
8189 jsframe_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008190
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008191 while (iterator.HasNext() &&
8192 Translation::BEGIN !=
8193 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
8194 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
8195
8196 switch (opcode) {
8197 case Translation::BEGIN:
8198 UNREACHABLE();
8199 break;
8200
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008201 case Translation::JS_FRAME: {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008202 int ast_id = iterator.Next();
8203 int function_id = iterator.Next();
8204 JSFunction* function =
8205 JSFunction::cast(LiteralArray()->get(function_id));
8206 unsigned height = iterator.Next();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008207 PrintF(out, "{ast_id=%d, function=", ast_id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008208 function->PrintName(out);
8209 PrintF(out, ", height=%u}", height);
8210 break;
8211 }
8212
ulan@chromium.org967e2702012-02-28 09:49:15 +00008213 case Translation::ARGUMENTS_ADAPTOR_FRAME:
8214 case Translation::CONSTRUCT_STUB_FRAME: {
8215 int function_id = iterator.Next();
8216 JSFunction* function =
8217 JSFunction::cast(LiteralArray()->get(function_id));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008218 unsigned height = iterator.Next();
ulan@chromium.org967e2702012-02-28 09:49:15 +00008219 PrintF(out, "{function=");
8220 function->PrintName(out);
8221 PrintF(out, ", height=%u}", height);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008222 break;
8223 }
8224
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008225 case Translation::DUPLICATE:
8226 break;
8227
8228 case Translation::REGISTER: {
8229 int reg_code = iterator.Next();
8230 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8231 break;
8232 }
8233
8234 case Translation::INT32_REGISTER: {
8235 int reg_code = iterator.Next();
8236 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8237 break;
8238 }
8239
8240 case Translation::DOUBLE_REGISTER: {
8241 int reg_code = iterator.Next();
8242 PrintF(out, "{input=%s}",
8243 DoubleRegister::AllocationIndexToString(reg_code));
8244 break;
8245 }
8246
8247 case Translation::STACK_SLOT: {
8248 int input_slot_index = iterator.Next();
8249 PrintF(out, "{input=%d}", input_slot_index);
8250 break;
8251 }
8252
8253 case Translation::INT32_STACK_SLOT: {
8254 int input_slot_index = iterator.Next();
8255 PrintF(out, "{input=%d}", input_slot_index);
8256 break;
8257 }
8258
8259 case Translation::DOUBLE_STACK_SLOT: {
8260 int input_slot_index = iterator.Next();
8261 PrintF(out, "{input=%d}", input_slot_index);
8262 break;
8263 }
8264
8265 case Translation::LITERAL: {
8266 unsigned literal_index = iterator.Next();
8267 PrintF(out, "{literal_id=%u}", literal_index);
8268 break;
8269 }
8270
8271 case Translation::ARGUMENTS_OBJECT:
8272 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008273 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008274 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008275 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008276 }
8277}
8278
8279
whesse@chromium.org023421e2010-12-21 12:19:12 +00008280void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
8281 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008282 this->DeoptPoints());
8283 if (this->DeoptPoints() == 0) return;
8284
8285 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
8286 for (int i = 0; i < this->DeoptPoints(); i++) {
8287 int pc_and_state = this->PcAndState(i)->value();
8288 PrintF("%6d %8d %s\n",
8289 this->AstId(i)->value(),
8290 FullCodeGenerator::PcField::decode(pc_and_state),
8291 FullCodeGenerator::State2String(
8292 FullCodeGenerator::StateField::decode(pc_and_state)));
8293 }
8294}
8295
whesse@chromium.org7b260152011-06-20 15:33:18 +00008296
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008297// Identify kind of code.
8298const char* Code::Kind2String(Kind kind) {
8299 switch (kind) {
8300 case FUNCTION: return "FUNCTION";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008301 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008302 case STUB: return "STUB";
8303 case BUILTIN: return "BUILTIN";
8304 case LOAD_IC: return "LOAD_IC";
8305 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
8306 case STORE_IC: return "STORE_IC";
8307 case KEYED_STORE_IC: return "KEYED_STORE_IC";
8308 case CALL_IC: return "CALL_IC";
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008309 case KEYED_CALL_IC: return "KEYED_CALL_IC";
danno@chromium.org40cb8782011-05-25 07:58:50 +00008310 case UNARY_OP_IC: return "UNARY_OP_IC";
8311 case BINARY_OP_IC: return "BINARY_OP_IC";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008312 case COMPARE_IC: return "COMPARE_IC";
ricow@chromium.org9fa09672011-07-25 11:05:35 +00008313 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008314 }
8315 UNREACHABLE();
8316 return NULL;
8317}
mads.s.ager31e71382008-08-13 09:32:07 +00008318
8319
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008320const char* Code::ICState2String(InlineCacheState state) {
8321 switch (state) {
8322 case UNINITIALIZED: return "UNINITIALIZED";
8323 case PREMONOMORPHIC: return "PREMONOMORPHIC";
8324 case MONOMORPHIC: return "MONOMORPHIC";
8325 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
8326 case MEGAMORPHIC: return "MEGAMORPHIC";
8327 case DEBUG_BREAK: return "DEBUG_BREAK";
8328 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
8329 }
8330 UNREACHABLE();
8331 return NULL;
8332}
8333
8334
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008335const char* Code::PropertyType2String(PropertyType type) {
8336 switch (type) {
8337 case NORMAL: return "NORMAL";
8338 case FIELD: return "FIELD";
8339 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
8340 case CALLBACKS: return "CALLBACKS";
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00008341 case HANDLER: return "HANDLER";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008342 case INTERCEPTOR: return "INTERCEPTOR";
8343 case MAP_TRANSITION: return "MAP_TRANSITION";
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008344 case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008345 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
8346 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
8347 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00008348 UNREACHABLE(); // keep the compiler happy
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008349 return NULL;
8350}
8351
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008352
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008353void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
8354 const char* name = NULL;
8355 switch (kind) {
8356 case CALL_IC:
8357 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
8358 name = "STRING_INDEX_OUT_OF_BOUNDS";
8359 }
8360 break;
8361 case STORE_IC:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008362 case KEYED_STORE_IC:
8363 if (extra == kStrictMode) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008364 name = "STRICT";
8365 }
8366 break;
8367 default:
8368 break;
8369 }
8370 if (name != NULL) {
8371 PrintF(out, "extra_ic_state = %s\n", name);
8372 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008373 PrintF(out, "extra_ic_state = %d\n", extra);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008374 }
8375}
8376
8377
whesse@chromium.org023421e2010-12-21 12:19:12 +00008378void Code::Disassemble(const char* name, FILE* out) {
8379 PrintF(out, "kind = %s\n", Kind2String(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008380 if (is_inline_cache_stub()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008381 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008382 PrintExtraICState(out, kind(), extra_ic_state());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008383 if (ic_state() == MONOMORPHIC) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008384 PrintF(out, "type = %s\n", PropertyType2String(type()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008385 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00008386 if (is_call_stub() || is_keyed_call_stub()) {
8387 PrintF(out, "argc = %d\n", arguments_count());
8388 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008389 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008390 if ((name != NULL) && (name[0] != '\0')) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008391 PrintF(out, "name = %s\n", name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008392 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008393 if (kind() == OPTIMIZED_FUNCTION) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008394 PrintF(out, "stack_slots = %d\n", stack_slots());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008395 }
mads.s.ager31e71382008-08-13 09:32:07 +00008396
whesse@chromium.org023421e2010-12-21 12:19:12 +00008397 PrintF(out, "Instructions (size = %d)\n", instruction_size());
8398 Disassembler::Decode(out, this);
8399 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00008400
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008401 if (kind() == FUNCTION) {
8402 DeoptimizationOutputData* data =
8403 DeoptimizationOutputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00008404 data->DeoptimizationOutputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008405 } else if (kind() == OPTIMIZED_FUNCTION) {
8406 DeoptimizationInputData* data =
8407 DeoptimizationInputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00008408 data->DeoptimizationInputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008409 }
8410 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008411
8412 if (kind() == OPTIMIZED_FUNCTION) {
8413 SafepointTable table(this);
whesse@chromium.org023421e2010-12-21 12:19:12 +00008414 PrintF(out, "Safepoints (size = %u)\n", table.size());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008415 for (unsigned i = 0; i < table.length(); i++) {
8416 unsigned pc_offset = table.GetPcOffset(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00008417 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008418 table.PrintEntry(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00008419 PrintF(out, " (sp -> fp)");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008420 SafepointEntry entry = table.GetEntry(i);
8421 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
8422 PrintF(out, " %6d", entry.deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008423 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008424 PrintF(out, " <none>");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008425 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008426 if (entry.argument_count() > 0) {
8427 PrintF(out, " argc: %d", entry.argument_count());
8428 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008429 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008430 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008431 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008432 } else if (kind() == FUNCTION) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008433 unsigned offset = stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008434 // If there is no stack check table, the "table start" will at or after
8435 // (due to alignment) the end of the instruction stream.
8436 if (static_cast<int>(offset) < instruction_size()) {
8437 unsigned* address =
8438 reinterpret_cast<unsigned*>(instruction_start() + offset);
8439 unsigned length = address[0];
whesse@chromium.org023421e2010-12-21 12:19:12 +00008440 PrintF(out, "Stack checks (size = %u)\n", length);
8441 PrintF(out, "ast_id pc_offset\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008442 for (unsigned i = 0; i < length; ++i) {
8443 unsigned index = (2 * i) + 1;
whesse@chromium.org023421e2010-12-21 12:19:12 +00008444 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008445 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008446 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008447 }
8448 }
8449
mads.s.ager31e71382008-08-13 09:32:07 +00008450 PrintF("RelocInfo (size = %d)\n", relocation_size());
whesse@chromium.org023421e2010-12-21 12:19:12 +00008451 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
8452 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00008453}
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008454#endif // ENABLE_DISASSEMBLER
8455
8456
whesse@chromium.org7b260152011-06-20 15:33:18 +00008457static void CopyFastElementsToFast(FixedArray* source,
8458 FixedArray* destination,
8459 WriteBarrierMode mode) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008460 int count = source->length();
8461 int copy_size = Min(count, destination->length());
8462 if (mode == SKIP_WRITE_BARRIER ||
8463 !Page::FromAddress(destination->address())->IsFlagSet(
8464 MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING)) {
8465 Address to = destination->address() + FixedArray::kHeaderSize;
8466 Address from = source->address() + FixedArray::kHeaderSize;
8467 memcpy(reinterpret_cast<void*>(to),
8468 reinterpret_cast<void*>(from),
8469 kPointerSize * copy_size);
8470 } else {
8471 for (int i = 0; i < copy_size; ++i) {
8472 destination->set(i, source->get(i), mode);
8473 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008474 }
8475}
8476
8477
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008478static void CopySlowElementsToFast(SeededNumberDictionary* source,
whesse@chromium.org7b260152011-06-20 15:33:18 +00008479 FixedArray* destination,
8480 WriteBarrierMode mode) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008481 int destination_length = destination->length();
whesse@chromium.org7b260152011-06-20 15:33:18 +00008482 for (int i = 0; i < source->Capacity(); ++i) {
8483 Object* key = source->KeyAt(i);
8484 if (key->IsNumber()) {
8485 uint32_t entry = static_cast<uint32_t>(key->Number());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008486 if (entry < static_cast<uint32_t>(destination_length)) {
8487 destination->set(entry, source->ValueAt(i), mode);
8488 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008489 }
8490 }
8491}
8492
8493
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008494MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8495 int capacity,
8496 int length,
8497 SetFastElementsCapacityMode set_capacity_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008498 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +00008499 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008500 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008501
whesse@chromium.org7b260152011-06-20 15:33:18 +00008502 // Allocate a new fast elements backing store.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008503 FixedArray* new_elements;
8504 { MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
8505 if (!maybe->To(&new_elements)) return maybe;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008506 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008507
whesse@chromium.org7b260152011-06-20 15:33:18 +00008508 // Find the new map to use for this object if there is a map change.
8509 Map* new_map = NULL;
8510 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00008511 // The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces
8512 // it, or if it's allowed and the old elements array contained only SMIs.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008513 bool has_fast_smi_only_elements =
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00008514 (set_capacity_mode == kForceSmiOnlyElements) ||
8515 ((set_capacity_mode == kAllowSmiOnlyElements) &&
8516 (elements()->map()->has_fast_smi_only_elements() ||
8517 elements() == heap->empty_fixed_array()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008518 ElementsKind elements_kind = has_fast_smi_only_elements
8519 ? FAST_SMI_ONLY_ELEMENTS
8520 : FAST_ELEMENTS;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00008521 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), elements_kind);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008522 if (!maybe->To(&new_map)) return maybe;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008523 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008524
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008525 FixedArrayBase* old_elements_raw = elements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008526 ElementsKind elements_kind = GetElementsKind();
8527 switch (elements_kind) {
8528 case FAST_SMI_ONLY_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008529 case FAST_ELEMENTS: {
8530 AssertNoAllocation no_gc;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008531 WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008532 CopyFastElementsToFast(FixedArray::cast(old_elements_raw),
8533 new_elements, mode);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00008534 set_map_and_elements(new_map, new_elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008535 break;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008536 }
8537 case DICTIONARY_ELEMENTS: {
8538 AssertNoAllocation no_gc;
8539 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008540 CopySlowElementsToFast(SeededNumberDictionary::cast(old_elements_raw),
whesse@chromium.org7b260152011-06-20 15:33:18 +00008541 new_elements,
8542 mode);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00008543 set_map_and_elements(new_map, new_elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008544 break;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008545 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008546 case NON_STRICT_ARGUMENTS_ELEMENTS: {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008547 AssertNoAllocation no_gc;
8548 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008549 // The object's map and the parameter map are unchanged, the unaliased
8550 // arguments are copied to the new backing store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008551 FixedArray* parameter_map = FixedArray::cast(old_elements_raw);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008552 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8553 if (arguments->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008554 CopySlowElementsToFast(SeededNumberDictionary::cast(arguments),
whesse@chromium.org7b260152011-06-20 15:33:18 +00008555 new_elements,
8556 mode);
8557 } else {
8558 CopyFastElementsToFast(arguments, new_elements, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008559 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008560 parameter_map->set(1, new_elements);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008561 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008562 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008563 case FAST_DOUBLE_ELEMENTS: {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008564 FixedDoubleArray* old_elements = FixedDoubleArray::cast(old_elements_raw);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008565 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
8566 // Fill out the new array with this content and array holes.
8567 for (uint32_t i = 0; i < old_length; i++) {
8568 if (!old_elements->is_the_hole(i)) {
8569 Object* obj;
8570 // Objects must be allocated in the old object space, since the
8571 // overall number of HeapNumbers needed for the conversion might
8572 // exceed the capacity of new space, and we would fail repeatedly
8573 // trying to convert the FixedDoubleArray.
8574 MaybeObject* maybe_value_object =
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008575 GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
8576 TENURED);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008577 if (!maybe_value_object->To(&obj)) return maybe_value_object;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008578 // Force write barrier. It's not worth trying to exploit
8579 // elems->GetWriteBarrierMode(), since it requires an
8580 // AssertNoAllocation stack object that would have to be positioned
8581 // after the HeapNumber allocation anyway.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008582 new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008583 }
8584 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008585 set_map(new_map);
8586 set_elements(new_elements);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008587 break;
8588 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008589 case EXTERNAL_BYTE_ELEMENTS:
8590 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8591 case EXTERNAL_SHORT_ELEMENTS:
8592 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8593 case EXTERNAL_INT_ELEMENTS:
8594 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8595 case EXTERNAL_FLOAT_ELEMENTS:
8596 case EXTERNAL_DOUBLE_ELEMENTS:
8597 case EXTERNAL_PIXEL_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008598 UNREACHABLE();
8599 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008600 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008601
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008602 if (FLAG_trace_elements_transitions) {
8603 PrintElementsTransition(stdout, elements_kind, old_elements_raw,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00008604 GetElementsKind(), new_elements);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008605 }
8606
whesse@chromium.org7b260152011-06-20 15:33:18 +00008607 // Update the length if necessary.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008608 if (IsJSArray()) {
8609 JSArray::cast(this)->set_length(Smi::FromInt(length));
8610 }
8611
whesse@chromium.org7b260152011-06-20 15:33:18 +00008612 return new_elements;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008613}
8614
8615
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008616MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
8617 int capacity,
8618 int length) {
8619 Heap* heap = GetHeap();
8620 // We should never end in here with a pixel or external array.
8621 ASSERT(!HasExternalArrayElements());
8622
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008623 FixedDoubleArray* elems;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008624 { MaybeObject* maybe_obj =
8625 heap->AllocateUninitializedFixedDoubleArray(capacity);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008626 if (!maybe_obj->To(&elems)) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008627 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008628
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008629 Map* new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008630 { MaybeObject* maybe_obj =
danno@chromium.orgfa458e42012-02-01 10:48:36 +00008631 GetElementsTransitionMap(heap->isolate(), FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008632 if (!maybe_obj->To(&new_map)) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008633 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008634
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008635 FixedArrayBase* old_elements = elements();
8636 ElementsKind elements_kind(GetElementsKind());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008637 AssertNoAllocation no_gc;
yangguo@chromium.org56454712012-02-16 15:33:53 +00008638 if (old_elements->length() != 0) {
8639 switch (elements_kind) {
8640 case FAST_SMI_ONLY_ELEMENTS:
8641 case FAST_ELEMENTS: {
8642 elems->Initialize(FixedArray::cast(old_elements));
8643 break;
8644 }
8645 case FAST_DOUBLE_ELEMENTS: {
8646 elems->Initialize(FixedDoubleArray::cast(old_elements));
8647 break;
8648 }
8649 case DICTIONARY_ELEMENTS: {
8650 elems->Initialize(SeededNumberDictionary::cast(old_elements));
8651 break;
8652 }
8653 default:
8654 UNREACHABLE();
8655 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008656 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008657 }
8658
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008659 if (FLAG_trace_elements_transitions) {
8660 PrintElementsTransition(stdout, elements_kind, old_elements,
8661 FAST_DOUBLE_ELEMENTS, elems);
8662 }
8663
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008664 ASSERT(new_map->has_fast_double_elements());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008665 set_map(new_map);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008666 ASSERT(elems->IsFixedDoubleArray());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008667 set_elements(elems);
8668
8669 if (IsJSArray()) {
8670 JSArray::cast(this)->set_length(Smi::FromInt(length));
8671 }
8672
8673 return this;
8674}
8675
8676
lrn@chromium.org303ada72010-10-27 09:33:13 +00008677MaybeObject* JSArray::Initialize(int capacity) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008678 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008679 ASSERT(capacity >= 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008680 set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008681 FixedArray* new_elements;
8682 if (capacity == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008683 new_elements = heap->empty_fixed_array();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008684 } else {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008685 MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
8686 if (!maybe_obj->To(&new_elements)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687 }
8688 set_elements(new_elements);
8689 return this;
8690}
8691
8692
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008693void JSArray::Expand(int required_size) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008694 GetIsolate()->factory()->SetElementsCapacityAndLength(
8695 Handle<JSArray>(this), required_size, required_size);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008696}
8697
8698
ricow@chromium.org7ad65222011-12-19 12:13:11 +00008699MaybeObject* JSArray::SetElementsLength(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +00008700 // We should never end in here with a pixel or external array.
ager@chromium.org5c838252010-02-19 08:53:10 +00008701 ASSERT(AllowsSetElementsLength());
danno@chromium.orgc612e022011-11-10 11:38:15 +00008702 return GetElementsAccessor()->SetLength(this, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008703}
8704
8705
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008706Object* Map::GetPrototypeTransition(Object* prototype) {
8707 FixedArray* cache = prototype_transitions();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008708 int number_of_transitions = NumberOfProtoTransitions();
8709 const int proto_offset =
8710 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
8711 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
8712 const int step = kProtoTransitionElementsPerEntry;
8713 for (int i = 0; i < number_of_transitions; i++) {
8714 if (cache->get(proto_offset + i * step) == prototype) {
8715 Object* map = cache->get(map_offset + i * step);
8716 ASSERT(map->IsMap());
8717 return map;
8718 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008719 }
8720 return NULL;
8721}
8722
8723
8724MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008725 ASSERT(map->IsMap());
8726 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008727 // Don't cache prototype transition if this map is shared.
8728 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
8729
8730 FixedArray* cache = prototype_transitions();
8731
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008732 const int step = kProtoTransitionElementsPerEntry;
8733 const int header = kProtoTransitionHeaderSize;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008734
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008735 int capacity = (cache->length() - header) / step;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008736
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008737 int transitions = NumberOfProtoTransitions() + 1;
8738
8739 if (transitions > capacity) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008740 if (capacity > kMaxCachedPrototypeTransitions) return this;
8741
8742 FixedArray* new_cache;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008743 // Grow array by factor 2 over and above what we need.
8744 { MaybeObject* maybe_cache =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008745 GetHeap()->AllocateFixedArray(transitions * 2 * step + header);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008746 if (!maybe_cache->To(&new_cache)) return maybe_cache;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008747 }
8748
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008749 for (int i = 0; i < capacity * step; i++) {
8750 new_cache->set(i + header, cache->get(i + header));
8751 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008752 cache = new_cache;
8753 set_prototype_transitions(cache);
8754 }
8755
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008756 int last = transitions - 1;
8757
8758 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
8759 cache->set(header + last * step + kProtoTransitionMapOffset, map);
8760 SetNumberOfProtoTransitions(transitions);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008761
8762 return cache;
8763}
8764
8765
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008766MaybeObject* JSReceiver::SetPrototype(Object* value,
8767 bool skip_hidden_prototypes) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008768#ifdef DEBUG
8769 int size = Size();
8770#endif
8771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008772 Heap* heap = GetHeap();
ager@chromium.org5c838252010-02-19 08:53:10 +00008773 // Silently ignore the change if value is not a JSObject or null.
8774 // SpiderMonkey behaves this way.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008775 if (!value->IsJSReceiver() && !value->IsNull()) return value;
ager@chromium.org5c838252010-02-19 08:53:10 +00008776
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008777 // From 8.6.2 Object Internal Methods
8778 // ...
8779 // In addition, if [[Extensible]] is false the value of the [[Class]] and
8780 // [[Prototype]] internal properties of the object may not be modified.
8781 // ...
8782 // Implementation specific extensions that modify [[Class]], [[Prototype]]
8783 // or [[Extensible]] must not violate the invariants defined in the preceding
8784 // paragraph.
8785 if (!this->map()->is_extensible()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008786 HandleScope scope(heap->isolate());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008787 Handle<Object> handle(this, heap->isolate());
8788 return heap->isolate()->Throw(
8789 *FACTORY->NewTypeError("non_extensible_proto",
8790 HandleVector<Object>(&handle, 1)));
8791 }
8792
ager@chromium.org5c838252010-02-19 08:53:10 +00008793 // Before we can set the prototype we need to be sure
8794 // prototype cycles are prevented.
8795 // It is sufficient to validate that the receiver is not in the new prototype
8796 // chain.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008797 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008798 if (JSReceiver::cast(pt) == this) {
ager@chromium.org5c838252010-02-19 08:53:10 +00008799 // Cycle detected.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008800 HandleScope scope(heap->isolate());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008801 return heap->isolate()->Throw(
8802 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
ager@chromium.org5c838252010-02-19 08:53:10 +00008803 }
8804 }
8805
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008806 JSReceiver* real_receiver = this;
ager@chromium.org5c838252010-02-19 08:53:10 +00008807
8808 if (skip_hidden_prototypes) {
8809 // Find the first object in the chain whose prototype object is not
8810 // hidden and set the new prototype on that object.
8811 Object* current_proto = real_receiver->GetPrototype();
8812 while (current_proto->IsJSObject() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008813 JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) {
8814 real_receiver = JSReceiver::cast(current_proto);
ager@chromium.org5c838252010-02-19 08:53:10 +00008815 current_proto = current_proto->GetPrototype();
8816 }
8817 }
8818
8819 // Set the new prototype of the object.
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008820 Map* map = real_receiver->map();
8821
8822 // Nothing to do if prototype is already set.
8823 if (map->prototype() == value) return value;
8824
8825 Object* new_map = map->GetPrototypeTransition(value);
8826 if (new_map == NULL) {
8827 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
8828 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
8829 }
8830
8831 { MaybeObject* maybe_new_cache =
8832 map->PutPrototypeTransition(value, Map::cast(new_map));
8833 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
8834 }
8835
8836 Map::cast(new_map)->set_prototype(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008837 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008838 ASSERT(Map::cast(new_map)->prototype() == value);
ager@chromium.org5c838252010-02-19 08:53:10 +00008839 real_receiver->set_map(Map::cast(new_map));
8840
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008841 heap->ClearInstanceofCache();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008842 ASSERT(size == Size());
ager@chromium.org5c838252010-02-19 08:53:10 +00008843 return value;
8844}
8845
8846
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008847MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
8848 uint32_t first_arg,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008849 uint32_t arg_count,
8850 EnsureElementsMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008851 // Elements in |Arguments| are ordered backwards (because they're on the
8852 // stack), but the method that's called here iterates over them in forward
8853 // direction.
8854 return EnsureCanContainElements(
8855 args->arguments() - first_arg - (arg_count - 1),
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008856 arg_count, mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008857}
8858
8859
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008860bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008861 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008862 // Make sure that the top context does not change when doing
8863 // callbacks or interceptor calls.
8864 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008865 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008866 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008867 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008868 Handle<JSObject> holder_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008869 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008870 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871 if (!interceptor->query()->IsUndefined()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00008872 v8::IndexedPropertyQuery query =
8873 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008874 LOG(isolate,
8875 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00008876 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008877 {
8878 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008879 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880 result = query(index, info);
8881 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008882 if (!result.IsEmpty()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00008883 ASSERT(result->IsInt32());
8884 return true; // absence of property is signaled by empty handle.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008885 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008886 } else if (!interceptor->getter()->IsUndefined()) {
8887 v8::IndexedPropertyGetter getter =
8888 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 LOG(isolate,
8890 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008891 v8::Handle<v8::Value> result;
8892 {
8893 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008894 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008895 result = getter(index, info);
8896 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008897 if (!result.IsEmpty()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008898 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00008899
8900 if (holder_handle->GetElementsAccessor()->HasElement(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008901 *receiver_handle, *holder_handle, index)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00008902 return true;
8903 }
8904
8905 if (holder_handle->IsStringObjectWithCharacterAt(index)) return true;
8906 Object* pt = holder_handle->GetPrototype();
8907 if (pt->IsJSProxy()) {
8908 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8909 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8910 receiver, index) != ABSENT;
8911 }
8912 if (pt->IsNull()) return false;
8913 return JSObject::cast(pt)->HasElementWithReceiver(*receiver_handle, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008914}
8915
8916
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008917JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008918 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008919 if (IsAccessCheckNeeded()) {
8920 Heap* heap = GetHeap();
8921 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8922 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8923 return UNDEFINED_ELEMENT;
8924 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008925 }
8926
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008927 if (IsJSGlobalProxy()) {
8928 Object* proto = GetPrototype();
8929 if (proto->IsNull()) return UNDEFINED_ELEMENT;
8930 ASSERT(proto->IsJSGlobalObject());
8931 return JSObject::cast(proto)->HasLocalElement(index);
8932 }
8933
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008934 // Check for lookup interceptor
8935 if (HasIndexedInterceptor()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008936 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
8937 : UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008938 }
8939
8940 // Handle [] on String objects.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008941 if (this->IsStringObjectWithCharacterAt(index)) {
8942 return STRING_CHARACTER_ELEMENT;
8943 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008944
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008945 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008946 case FAST_SMI_ONLY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008947 case FAST_ELEMENTS: {
8948 uint32_t length = IsJSArray() ?
8949 static_cast<uint32_t>
8950 (Smi::cast(JSArray::cast(this)->length())->value()) :
8951 static_cast<uint32_t>(FixedArray::cast(elements())->length());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008952 if ((index < length) &&
8953 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8954 return FAST_ELEMENT;
8955 }
8956 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008957 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00008958 case FAST_DOUBLE_ELEMENTS: {
8959 uint32_t length = IsJSArray() ?
8960 static_cast<uint32_t>
8961 (Smi::cast(JSArray::cast(this)->length())->value()) :
8962 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8963 if ((index < length) &&
8964 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
8965 return FAST_ELEMENT;
8966 }
8967 break;
8968 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008969 case EXTERNAL_PIXEL_ELEMENTS: {
8970 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008971 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
8972 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008973 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008974 case EXTERNAL_BYTE_ELEMENTS:
8975 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8976 case EXTERNAL_SHORT_ELEMENTS:
8977 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8978 case EXTERNAL_INT_ELEMENTS:
8979 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008980 case EXTERNAL_FLOAT_ELEMENTS:
8981 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00008982 ExternalArray* array = ExternalArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008983 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
8984 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00008985 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008986 case DICTIONARY_ELEMENTS: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008987 if (element_dictionary()->FindEntry(index) !=
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008988 SeededNumberDictionary::kNotFound) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008989 return DICTIONARY_ELEMENT;
8990 }
8991 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008992 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008993 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8994 // Aliased parameters and non-aliased elements in a fast backing store
8995 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
8996 // backing store behave as DICTIONARY_ELEMENT.
8997 FixedArray* parameter_map = FixedArray::cast(elements());
8998 uint32_t length = parameter_map->length();
8999 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00009000 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009001 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
9002 // If not aliased, check the arguments.
9003 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9004 if (arguments->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009005 SeededNumberDictionary* dictionary =
9006 SeededNumberDictionary::cast(arguments);
9007 if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009008 return DICTIONARY_ELEMENT;
9009 }
9010 } else {
9011 length = arguments->length();
9012 probe = (index < length) ? arguments->get(index) : NULL;
9013 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
9014 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009015 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009016 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009017 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009018
9019 return UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009020}
9021
9022
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00009023bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009024 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009025 if (IsAccessCheckNeeded()) {
9026 Heap* heap = GetHeap();
9027 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
9028 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9029 return false;
9030 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031 }
9032
9033 // Check for lookup interceptor
9034 if (HasIndexedInterceptor()) {
9035 return HasElementWithInterceptor(receiver, index);
9036 }
9037
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00009038 ElementsAccessor* accessor = GetElementsAccessor();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009039 if (accessor->HasElement(receiver, this, index)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00009040 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009041 }
9042
9043 // Handle [] on String objects.
9044 if (this->IsStringObjectWithCharacterAt(index)) return true;
9045
9046 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009047 if (pt->IsNull()) return false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009048 if (pt->IsJSProxy()) {
9049 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
9050 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
9051 receiver, index) != ABSENT;
9052 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
9054}
9055
9056
lrn@chromium.org303ada72010-10-27 09:33:13 +00009057MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009058 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009059 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009060 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009061 bool check_prototype,
9062 SetPropertyMode set_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009063 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009064 // Make sure that the top context does not change when doing
9065 // callbacks or interceptor calls.
9066 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009067 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
9069 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009070 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071 if (!interceptor->setter()->IsUndefined()) {
9072 v8::IndexedPropertySetter setter =
9073 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009074 LOG(isolate,
9075 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
9076 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009077 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009078 v8::Handle<v8::Value> result;
9079 {
9080 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009081 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009082 result = setter(index, v8::Utils::ToLocal(value_handle), info);
9083 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009084 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085 if (!result.IsEmpty()) return *value_handle;
9086 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009087 MaybeObject* raw_result =
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009088 this_handle->SetElementWithoutInterceptor(index,
9089 *value_handle,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009090 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009091 strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009092 check_prototype,
9093 set_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009094 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009095 return raw_result;
9096}
9097
9098
lrn@chromium.org303ada72010-10-27 09:33:13 +00009099MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
9100 Object* structure,
9101 uint32_t index,
9102 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009103 Isolate* isolate = GetIsolate();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009104 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009105
9106 // api style callbacks.
9107 if (structure->IsAccessorInfo()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009108 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009109 Object* fun_obj = data->getter();
9110 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009111 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009112 Handle<JSObject> self(JSObject::cast(receiver));
9113 Handle<JSObject> holder_handle(JSObject::cast(holder));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009114 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009115 Handle<String> key = isolate->factory()->NumberToString(number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009116 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
9117 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009118 v8::AccessorInfo info(args.end());
9119 v8::Handle<v8::Value> result;
9120 {
9121 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009122 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009123 result = call_fun(v8::Utils::ToLocal(key), info);
9124 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009125 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9126 if (result.IsEmpty()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009127 return *v8::Utils::OpenHandle(*result);
9128 }
9129
9130 // __defineGetter__ callback
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009131 if (structure->IsAccessorPair()) {
9132 Object* getter = AccessorPair::cast(structure)->getter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009133 if (getter->IsSpecFunction()) {
9134 // TODO(rossberg): nicer would be to cast to some JSCallable here...
9135 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009136 }
9137 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009138 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009139 }
9140
9141 UNREACHABLE();
9142 return NULL;
9143}
9144
9145
lrn@chromium.org303ada72010-10-27 09:33:13 +00009146MaybeObject* JSObject::SetElementWithCallback(Object* structure,
9147 uint32_t index,
9148 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009149 JSObject* holder,
9150 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009151 Isolate* isolate = GetIsolate();
9152 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009153
9154 // We should never get here to initialize a const with the hole
9155 // value since a const declaration would conflict with the setter.
9156 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009157 Handle<Object> value_handle(value, isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009158
9159 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009160 // data structure used to store the callbacks. Eventually foreign
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009161 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009162 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009163
9164 if (structure->IsAccessorInfo()) {
9165 // api style callbacks
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009166 Handle<JSObject> self(this);
9167 Handle<JSObject> holder_handle(JSObject::cast(holder));
9168 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009169 Object* call_obj = data->setter();
9170 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
9171 if (call_fun == NULL) return value;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009172 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9173 Handle<String> key(isolate->factory()->NumberToString(number));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009174 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
9175 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009176 v8::AccessorInfo info(args.end());
9177 {
9178 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009179 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009180 call_fun(v8::Utils::ToLocal(key),
9181 v8::Utils::ToLocal(value_handle),
9182 info);
9183 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009184 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009185 return *value_handle;
9186 }
9187
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009188 if (structure->IsAccessorPair()) {
9189 Handle<Object> setter(AccessorPair::cast(structure)->setter());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009190 if (setter->IsSpecFunction()) {
9191 // TODO(rossberg): nicer would be to cast to some JSCallable here...
9192 return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009193 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009194 if (strict_mode == kNonStrictMode) {
9195 return value;
9196 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009197 Handle<Object> holder_handle(holder, isolate);
9198 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009199 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009200 return isolate->Throw(
9201 *isolate->factory()->NewTypeError("no_setter_in_callback",
9202 HandleVector(args, 2)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009203 }
9204 }
9205
9206 UNREACHABLE();
9207 return NULL;
9208}
9209
9210
whesse@chromium.org7b260152011-06-20 15:33:18 +00009211bool JSObject::HasFastArgumentsElements() {
9212 Heap* heap = GetHeap();
9213 if (!elements()->IsFixedArray()) return false;
9214 FixedArray* elements = FixedArray::cast(this->elements());
9215 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9216 return false;
9217 }
9218 FixedArray* arguments = FixedArray::cast(elements->get(1));
9219 return !arguments->IsDictionary();
9220}
9221
9222
9223bool JSObject::HasDictionaryArgumentsElements() {
9224 Heap* heap = GetHeap();
9225 if (!elements()->IsFixedArray()) return false;
9226 FixedArray* elements = FixedArray::cast(this->elements());
9227 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9228 return false;
9229 }
9230 FixedArray* arguments = FixedArray::cast(elements->get(1));
9231 return arguments->IsDictionary();
9232}
9233
9234
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009235// Adding n elements in fast case is O(n*n).
9236// Note: revisit design to have dual undefined values to capture absent
9237// elements.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009238MaybeObject* JSObject::SetFastElement(uint32_t index,
9239 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009240 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009241 bool check_prototype) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009242 ASSERT(HasFastTypeElements() ||
9243 HasFastArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244
whesse@chromium.org7b260152011-06-20 15:33:18 +00009245 FixedArray* backing_store = FixedArray::cast(elements());
9246 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
9247 backing_store = FixedArray::cast(backing_store->get(1));
9248 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009249 MaybeObject* maybe = EnsureWritableFastElements();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009250 if (!maybe->To(&backing_store)) return maybe;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009251 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009252 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009253
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009254 if (check_prototype &&
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009255 (index >= capacity || backing_store->get(index)->IsTheHole())) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00009256 bool found;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009257 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9258 value,
9259 &found,
9260 strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00009261 if (found) return result;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009262 }
9263
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009264 uint32_t new_capacity = capacity;
9265 // Check if the length property of this object needs to be updated.
9266 uint32_t array_length = 0;
9267 bool must_update_array_length = false;
9268 if (IsJSArray()) {
9269 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9270 if (index >= array_length) {
9271 must_update_array_length = true;
9272 array_length = index + 1;
9273 }
9274 }
9275 // Check if the capacity of the backing store needs to be increased, or if
9276 // a transition to slow elements is necessary.
9277 if (index >= capacity) {
9278 bool convert_to_slow = true;
9279 if ((index - capacity) < kMaxGap) {
9280 new_capacity = NewElementsCapacity(index + 1);
9281 ASSERT(new_capacity > index);
9282 if (!ShouldConvertToSlowElements(new_capacity)) {
9283 convert_to_slow = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009284 }
9285 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009286 if (convert_to_slow) {
9287 MaybeObject* result = NormalizeElements();
9288 if (result->IsFailure()) return result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009289 return SetDictionaryElement(index, value, NONE, strict_mode,
9290 check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009291 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009292 }
9293 // Convert to fast double elements if appropriate.
9294 if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) {
9295 MaybeObject* maybe =
9296 SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
9297 if (maybe->IsFailure()) return maybe;
9298 FixedDoubleArray::cast(elements())->set(index, value->Number());
ager@chromium.orgbdf2f942008-10-17 07:23:00 +00009299 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009300 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009301 // Change elements kind from SMI_ONLY to generic FAST if necessary.
9302 if (HasFastSmiOnlyElements() && !value->IsSmi()) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009303 Map* new_map;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009304 { MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
9305 FAST_ELEMENTS);
9306 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9307 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009308 set_map(new_map);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009309 if (FLAG_trace_elements_transitions) {
9310 PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
9311 FAST_ELEMENTS, elements());
9312 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009313 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009314 // Increase backing store capacity if that's been decided previously.
9315 if (new_capacity != capacity) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009316 FixedArray* new_elements;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009317 SetFastElementsCapacityMode set_capacity_mode =
9318 value->IsSmi() && HasFastSmiOnlyElements()
9319 ? kAllowSmiOnlyElements
9320 : kDontAllowSmiOnlyElements;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009321 { MaybeObject* maybe =
9322 SetFastElementsCapacityAndLength(new_capacity,
9323 array_length,
9324 set_capacity_mode);
9325 if (!maybe->To(&new_elements)) return maybe;
9326 }
9327 new_elements->set(index, value);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009328 return value;
9329 }
9330 // Finally, set the new element and length.
9331 ASSERT(elements()->IsFixedArray());
9332 backing_store->set(index, value);
9333 if (must_update_array_length) {
9334 JSArray::cast(this)->set_length(Smi::FromInt(array_length));
9335 }
9336 return value;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009337}
9338
9339
9340MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
9341 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009342 PropertyAttributes attributes,
whesse@chromium.org7b260152011-06-20 15:33:18 +00009343 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009344 bool check_prototype,
9345 SetPropertyMode set_mode) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009346 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9347 Isolate* isolate = GetIsolate();
9348 Heap* heap = isolate->heap();
9349
9350 // Insert element in the dictionary.
9351 FixedArray* elements = FixedArray::cast(this->elements());
9352 bool is_arguments =
9353 (elements->map() == heap->non_strict_arguments_elements_map());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009354 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009355 if (is_arguments) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009356 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00009357 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009358 dictionary = SeededNumberDictionary::cast(elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009359 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009360
9361 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009362 if (entry != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009363 Object* element = dictionary->ValueAt(entry);
9364 PropertyDetails details = dictionary->DetailsAt(entry);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009365 if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009366 return SetElementWithCallback(element, index, value, this, strict_mode);
9367 } else {
9368 dictionary->UpdateMaxNumberKey(index);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009369 // If a value has not been initialized we allow writing to it even if it
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009370 // is read-only (a declared const that has not been initialized). If a
9371 // value is being defined we skip attribute checks completely.
9372 if (set_mode == DEFINE_PROPERTY) {
9373 details = PropertyDetails(attributes, NORMAL, details.index());
9374 dictionary->DetailsAtPut(entry, details);
9375 } else if (details.IsReadOnly() && !element->IsTheHole()) {
9376 if (strict_mode == kNonStrictMode) {
9377 return isolate->heap()->undefined_value();
9378 } else {
9379 Handle<Object> holder(this);
9380 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9381 Handle<Object> args[2] = { number, holder };
9382 Handle<Object> error =
9383 isolate->factory()->NewTypeError("strict_read_only_property",
9384 HandleVector(args, 2));
9385 return isolate->Throw(*error);
9386 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009387 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009388 // Elements of the arguments object in slow mode might be slow aliases.
9389 if (is_arguments && element->IsAliasedArgumentsEntry()) {
9390 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(element);
9391 Context* context = Context::cast(elements->get(0));
9392 int context_index = entry->aliased_context_slot();
9393 ASSERT(!context->get(context_index)->IsTheHole());
9394 context->set(context_index, value);
9395 // For elements that are still writable we keep slow aliasing.
9396 if (!details.IsReadOnly()) value = element;
9397 }
9398 dictionary->ValueAtPut(entry, value);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009399 }
9400 } else {
9401 // Index not already used. Look for an accessor in the prototype chain.
9402 if (check_prototype) {
9403 bool found;
9404 MaybeObject* result =
9405 SetElementWithCallbackSetterInPrototypes(
9406 index, value, &found, strict_mode);
9407 if (found) return result;
9408 }
9409 // When we set the is_extensible flag to false we always force the
9410 // element into dictionary mode (and force them to stay there).
9411 if (!map()->is_extensible()) {
9412 if (strict_mode == kNonStrictMode) {
9413 return isolate->heap()->undefined_value();
9414 } else {
9415 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9416 Handle<String> name = isolate->factory()->NumberToString(number);
9417 Handle<Object> args[1] = { name };
9418 Handle<Object> error =
9419 isolate->factory()->NewTypeError("object_not_extensible",
9420 HandleVector(args, 1));
9421 return isolate->Throw(*error);
9422 }
9423 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009424 FixedArrayBase* new_dictionary;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009425 PropertyDetails details = PropertyDetails(attributes, NORMAL);
9426 MaybeObject* maybe = dictionary->AddNumberEntry(index, value, details);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009427 if (!maybe->To(&new_dictionary)) return maybe;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009428 if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009429 if (is_arguments) {
9430 elements->set(1, new_dictionary);
9431 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009432 set_elements(new_dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009433 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009434 dictionary = SeededNumberDictionary::cast(new_dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009435 }
9436 }
9437
9438 // Update the array length if this JSObject is an array.
9439 if (IsJSArray()) {
9440 MaybeObject* result =
9441 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
9442 if (result->IsFailure()) return result;
9443 }
9444
9445 // Attempt to put this object back in fast case.
9446 if (ShouldConvertToFastElements()) {
9447 uint32_t new_length = 0;
9448 if (IsJSArray()) {
9449 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
9450 } else {
9451 new_length = dictionary->max_number_key() + 1;
9452 }
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00009453 SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays
9454 ? kAllowSmiOnlyElements
9455 : kDontAllowSmiOnlyElements;
9456 bool has_smi_only_elements = false;
9457 bool should_convert_to_fast_double_elements =
9458 ShouldConvertToFastDoubleElements(&has_smi_only_elements);
9459 if (has_smi_only_elements) {
9460 set_capacity_mode = kForceSmiOnlyElements;
9461 }
9462 MaybeObject* result = should_convert_to_fast_double_elements
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009463 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009464 : SetFastElementsCapacityAndLength(new_length,
9465 new_length,
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00009466 set_capacity_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009467 if (result->IsFailure()) return result;
9468#ifdef DEBUG
9469 if (FLAG_trace_normalization) {
9470 PrintF("Object elements are fast case again:\n");
9471 Print();
9472 }
9473#endif
9474 }
9475 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009476}
9477
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00009478
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009479MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
9480 uint32_t index,
9481 Object* value,
9482 StrictModeFlag strict_mode,
9483 bool check_prototype) {
9484 ASSERT(HasFastDoubleElements());
9485
yangguo@chromium.org56454712012-02-16 15:33:53 +00009486 FixedArrayBase* base_elms = FixedArrayBase::cast(elements());
9487 uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009488
9489 // If storing to an element that isn't in the array, pass the store request
9490 // up the prototype chain before storing in the receiver's elements.
9491 if (check_prototype &&
yangguo@chromium.org56454712012-02-16 15:33:53 +00009492 (index >= elms_length ||
9493 FixedDoubleArray::cast(base_elms)->is_the_hole(index))) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009494 bool found;
9495 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9496 value,
9497 &found,
9498 strict_mode);
9499 if (found) return result;
9500 }
9501
9502 // If the value object is not a heap number, switch to fast elements and try
9503 // again.
9504 bool value_is_smi = value->IsSmi();
9505 if (!value->IsNumber()) {
9506 Object* obj;
9507 uint32_t length = elms_length;
9508 if (IsJSArray()) {
9509 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9510 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009511 MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
9512 elms_length,
9513 length,
9514 kDontAllowSmiOnlyElements);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009515 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009516 return SetFastElement(index,
9517 value,
9518 strict_mode,
9519 check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009520 }
9521
9522 double double_value = value_is_smi
9523 ? static_cast<double>(Smi::cast(value)->value())
9524 : HeapNumber::cast(value)->value();
9525
9526 // Check whether there is extra space in the fixed array.
9527 if (index < elms_length) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00009528 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009529 elms->set(index, double_value);
9530 if (IsJSArray()) {
9531 // Update the length of the array if needed.
9532 uint32_t array_length = 0;
9533 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9534 if (index >= array_length) {
9535 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
9536 }
9537 }
9538 return value;
9539 }
9540
9541 // Allow gap in fast case.
9542 if ((index - elms_length) < kMaxGap) {
9543 // Try allocating extra space.
9544 int new_capacity = NewElementsCapacity(index+1);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00009545 if (!ShouldConvertToSlowElements(new_capacity)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009546 ASSERT(static_cast<uint32_t>(new_capacity) > index);
9547 Object* obj;
9548 { MaybeObject* maybe_obj =
9549 SetFastDoubleElementsCapacityAndLength(new_capacity,
9550 index + 1);
9551 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9552 }
9553 FixedDoubleArray::cast(elements())->set(index, double_value);
9554 return value;
9555 }
9556 }
9557
9558 // Otherwise default to slow case.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009559 ASSERT(HasFastDoubleElements());
9560 ASSERT(map()->has_fast_double_elements());
9561 ASSERT(elements()->IsFixedDoubleArray());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009562 Object* obj;
9563 { MaybeObject* maybe_obj = NormalizeElements();
9564 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9565 }
9566 ASSERT(HasDictionaryElements());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009567 return SetElement(index, value, NONE, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009568}
9569
9570
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009571MaybeObject* JSReceiver::SetElement(uint32_t index,
9572 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009573 PropertyAttributes attributes,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009574 StrictModeFlag strict_mode,
9575 bool check_proto) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009576 if (IsJSProxy()) {
9577 return JSProxy::cast(this)->SetElementWithHandler(
9578 index, value, strict_mode);
9579 } else {
9580 return JSObject::cast(this)->SetElement(
9581 index, value, attributes, strict_mode, check_proto);
9582 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009583}
9584
9585
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009586Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
9587 uint32_t index,
9588 Handle<Object> value,
9589 StrictModeFlag strict_mode) {
9590 ASSERT(!object->HasExternalArrayElements());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009591 CALL_HEAP_FUNCTION(
9592 object->GetIsolate(),
9593 object->SetElement(index, *value, NONE, strict_mode, false),
9594 Object);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009595}
9596
9597
9598Handle<Object> JSObject::SetElement(Handle<JSObject> object,
9599 uint32_t index,
9600 Handle<Object> value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009601 PropertyAttributes attr,
9602 StrictModeFlag strict_mode,
9603 SetPropertyMode set_mode) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009604 if (object->HasExternalArrayElements()) {
9605 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
9606 bool has_exception;
9607 Handle<Object> number = Execution::ToNumber(value, &has_exception);
9608 if (has_exception) return Handle<Object>();
9609 value = number;
9610 }
9611 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009612 CALL_HEAP_FUNCTION(
9613 object->GetIsolate(),
9614 object->SetElement(index, *value, attr, strict_mode, true, set_mode),
9615 Object);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009616}
9617
9618
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009619MaybeObject* JSObject::SetElement(uint32_t index,
9620 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009621 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009622 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009623 bool check_prototype,
9624 SetPropertyMode set_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009625 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009626 if (IsAccessCheckNeeded()) {
9627 Heap* heap = GetHeap();
9628 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009629 HandleScope scope(heap->isolate());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009630 Handle<Object> value_handle(value);
9631 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
9632 return *value_handle;
9633 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009634 }
9635
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009636 if (IsJSGlobalProxy()) {
9637 Object* proto = GetPrototype();
9638 if (proto->IsNull()) return value;
9639 ASSERT(proto->IsJSGlobalObject());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009640 return JSObject::cast(proto)->SetElement(index,
9641 value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009642 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009643 strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009644 check_prototype,
9645 set_mode);
9646 }
9647
9648 // Don't allow element properties to be redefined for external arrays.
9649 if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) {
9650 Isolate* isolate = GetHeap()->isolate();
9651 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9652 Handle<Object> args[] = { Handle<Object>(this), number };
9653 Handle<Object> error = isolate->factory()->NewTypeError(
9654 "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args)));
9655 return isolate->Throw(*error);
9656 }
9657
9658 // Normalize the elements to enable attributes on the property.
9659 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
9660 SeededNumberDictionary* dictionary;
9661 MaybeObject* maybe_object = NormalizeElements();
9662 if (!maybe_object->To(&dictionary)) return maybe_object;
9663 // Make sure that we never go back to fast case.
9664 dictionary->set_requires_slow_elements();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009665 }
9666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009667 // Check for lookup interceptor
9668 if (HasIndexedInterceptor()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009669 return SetElementWithInterceptor(index,
9670 value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009671 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009672 strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009673 check_prototype,
9674 set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009675 }
9676
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009677 return SetElementWithoutInterceptor(index,
9678 value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009679 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009680 strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009681 check_prototype,
9682 set_mode);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009683}
9684
9685
lrn@chromium.org303ada72010-10-27 09:33:13 +00009686MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009687 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009688 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009689 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009690 bool check_prototype,
9691 SetPropertyMode set_mode) {
9692 ASSERT(HasDictionaryElements() ||
9693 HasDictionaryArgumentsElements() ||
9694 (attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009695 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009696 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009697 case FAST_SMI_ONLY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009698 case FAST_ELEMENTS:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009699 return SetFastElement(index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009700 case FAST_DOUBLE_ELEMENTS:
9701 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009702 case EXTERNAL_PIXEL_ELEMENTS: {
9703 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009704 return pixels->SetValue(index, value);
9705 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009706 case EXTERNAL_BYTE_ELEMENTS: {
9707 ExternalByteArray* array = ExternalByteArray::cast(elements());
9708 return array->SetValue(index, value);
9709 }
9710 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9711 ExternalUnsignedByteArray* array =
9712 ExternalUnsignedByteArray::cast(elements());
9713 return array->SetValue(index, value);
9714 }
9715 case EXTERNAL_SHORT_ELEMENTS: {
9716 ExternalShortArray* array = ExternalShortArray::cast(elements());
9717 return array->SetValue(index, value);
9718 }
9719 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9720 ExternalUnsignedShortArray* array =
9721 ExternalUnsignedShortArray::cast(elements());
9722 return array->SetValue(index, value);
9723 }
9724 case EXTERNAL_INT_ELEMENTS: {
9725 ExternalIntArray* array = ExternalIntArray::cast(elements());
9726 return array->SetValue(index, value);
9727 }
9728 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9729 ExternalUnsignedIntArray* array =
9730 ExternalUnsignedIntArray::cast(elements());
9731 return array->SetValue(index, value);
9732 }
9733 case EXTERNAL_FLOAT_ELEMENTS: {
9734 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
9735 return array->SetValue(index, value);
9736 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009737 case EXTERNAL_DOUBLE_ELEMENTS: {
9738 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
9739 return array->SetValue(index, value);
9740 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009741 case DICTIONARY_ELEMENTS:
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009742 return SetDictionaryElement(index, value, attr, strict_mode,
9743 check_prototype, set_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009744 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9745 FixedArray* parameter_map = FixedArray::cast(elements());
9746 uint32_t length = parameter_map->length();
9747 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00009748 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009749 if (probe != NULL && !probe->IsTheHole()) {
9750 Context* context = Context::cast(parameter_map->get(0));
9751 int context_index = Smi::cast(probe)->value();
9752 ASSERT(!context->get(context_index)->IsTheHole());
9753 context->set(context_index, value);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009754 // Redefining attributes of an aliased element destroys fast aliasing.
9755 if (set_mode == SET_PROPERTY || attr == NONE) return value;
9756 parameter_map->set_the_hole(index + 2);
9757 // For elements that are still writable we re-establish slow aliasing.
9758 if ((attr & READ_ONLY) == 0) {
9759 MaybeObject* maybe_entry =
9760 isolate->heap()->AllocateAliasedArgumentsEntry(context_index);
9761 if (!maybe_entry->ToObject(&value)) return maybe_entry;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009762 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009763 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009764 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9765 if (arguments->IsDictionary()) {
9766 return SetDictionaryElement(index, value, attr, strict_mode,
9767 check_prototype, set_mode);
9768 } else {
9769 return SetFastElement(index, value, strict_mode, check_prototype);
9770 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009771 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009772 }
9773 // All possible cases have been handled above. Add a return to avoid the
9774 // complaints from the compiler.
9775 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009776 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009777}
9778
9779
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009780Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
9781 ElementsKind to_kind) {
9782 CALL_HEAP_FUNCTION(object->GetIsolate(),
9783 object->TransitionElementsKind(to_kind),
9784 Object);
9785}
9786
9787
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009788MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009789 ElementsKind from_kind = map()->elements_kind();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009790
9791 Isolate* isolate = GetIsolate();
9792 if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9793 (to_kind == FAST_ELEMENTS ||
9794 elements() == isolate->heap()->empty_fixed_array())) {
9795 MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
9796 Map* new_map;
9797 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9798 set_map(new_map);
9799 if (FLAG_trace_elements_transitions) {
9800 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9801 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
9802 }
9803 return this;
9804 }
9805
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009806 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9807 uint32_t capacity = static_cast<uint32_t>(elms->length());
9808 uint32_t length = capacity;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009809
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009810 if (IsJSArray()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009811 Object* raw_length = JSArray::cast(this)->length();
9812 if (raw_length->IsUndefined()) {
9813 // If length is undefined, then JSArray is being initialized and has no
9814 // elements, assume a length of zero.
9815 length = 0;
9816 } else {
9817 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009818 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009819 }
9820
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009821 if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9822 to_kind == FAST_DOUBLE_ELEMENTS) {
9823 MaybeObject* maybe_result =
9824 SetFastDoubleElementsCapacityAndLength(capacity, length);
9825 if (maybe_result->IsFailure()) return maybe_result;
9826 return this;
9827 }
9828
9829 if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009830 MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
9831 capacity, length, kDontAllowSmiOnlyElements);
9832 if (maybe_result->IsFailure()) return maybe_result;
9833 return this;
9834 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009835
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009836 // This method should never be called for any other case than the ones
9837 // handled above.
9838 UNREACHABLE();
9839 return GetIsolate()->heap()->null_value();
9840}
9841
9842
9843// static
9844bool Map::IsValidElementsTransition(ElementsKind from_kind,
9845 ElementsKind to_kind) {
9846 return
9847 (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9848 (to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) ||
9849 (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS);
9850}
9851
9852
lrn@chromium.org303ada72010-10-27 09:33:13 +00009853MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
9854 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009855 uint32_t old_len = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009856 CHECK(length()->ToArrayIndex(&old_len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009857 // Check to see if we need to update the length. For now, we make
9858 // sure that the length stays within 32-bits (unsigned).
9859 if (index >= old_len && index != 0xffffffff) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009860 Object* len;
9861 { MaybeObject* maybe_len =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009862 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009863 if (!maybe_len->ToObject(&len)) return maybe_len;
9864 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009865 set_length(len);
9866 }
9867 return value;
9868}
9869
9870
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00009871MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009872 uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009873 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009874 // Make sure that the top context does not change when doing
9875 // callbacks or interceptor calls.
9876 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009877 HandleScope scope(isolate);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009878 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
9879 Handle<Object> this_handle(receiver, isolate);
9880 Handle<JSObject> holder_handle(this, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009881 if (!interceptor->getter()->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009882 v8::IndexedPropertyGetter getter =
9883 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009884 LOG(isolate,
9885 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
9886 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009887 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009888 v8::Handle<v8::Value> result;
9889 {
9890 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009891 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009892 result = getter(index, info);
9893 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009894 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009895 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
9896 }
9897
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009898 Heap* heap = holder_handle->GetHeap();
9899 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009900 MaybeObject* raw_result = handler->Get(*this_handle,
rossberg@chromium.org28a37082011-08-22 11:03:23 +00009901 *holder_handle,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009902 index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009903 if (raw_result != heap->the_hole_value()) return raw_result;
9904
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009905 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009906
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009907 Object* pt = holder_handle->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009908 if (pt == heap->null_value()) return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009909 return pt->GetElementWithReceiver(*this_handle, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009910}
9911
9912
9913bool JSObject::HasDenseElements() {
9914 int capacity = 0;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009915 int used = 0;
9916 GetElementsCapacityAndUsage(&capacity, &used);
9917 return (capacity == 0) || (used > (capacity / 2));
9918}
9919
9920
9921void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
9922 *capacity = 0;
9923 *used = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009924
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009925 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
9926 FixedArray* backing_store = NULL;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009927 switch (GetElementsKind()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009928 case NON_STRICT_ARGUMENTS_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009929 backing_store_base =
9930 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
9931 backing_store = FixedArray::cast(backing_store_base);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009932 if (backing_store->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009933 SeededNumberDictionary* dictionary =
9934 SeededNumberDictionary::cast(backing_store);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009935 *capacity = dictionary->Capacity();
9936 *used = dictionary->NumberOfElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +00009937 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009938 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009939 // Fall through.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009940 case FAST_SMI_ONLY_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +00009941 case FAST_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009942 backing_store = FixedArray::cast(backing_store_base);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009943 *capacity = backing_store->length();
9944 for (int i = 0; i < *capacity; ++i) {
9945 if (!backing_store->get(i)->IsTheHole()) ++(*used);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009946 }
9947 break;
9948 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009949 SeededNumberDictionary* dictionary =
9950 SeededNumberDictionary::cast(FixedArray::cast(elements()));
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009951 *capacity = dictionary->Capacity();
9952 *used = dictionary->NumberOfElements();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009953 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009954 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009955 case FAST_DOUBLE_ELEMENTS: {
9956 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009957 *capacity = elms->length();
9958 for (int i = 0; i < *capacity; i++) {
9959 if (!elms->is_the_hole(i)) ++(*used);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009960 }
9961 break;
9962 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009963 case EXTERNAL_BYTE_ELEMENTS:
9964 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9965 case EXTERNAL_SHORT_ELEMENTS:
9966 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9967 case EXTERNAL_INT_ELEMENTS:
9968 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009969 case EXTERNAL_FLOAT_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009970 case EXTERNAL_DOUBLE_ELEMENTS:
9971 case EXTERNAL_PIXEL_ELEMENTS:
9972 // External arrays are considered 100% used.
9973 ExternalArray* external_array = ExternalArray::cast(elements());
9974 *capacity = external_array->length();
9975 *used = external_array->length();
9976 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009977 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009978}
9979
9980
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009981bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009982 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
9983 kMaxUncheckedFastElementsLength);
9984 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
9985 (new_capacity <= kMaxUncheckedFastElementsLength &&
9986 GetHeap()->InNewSpace(this))) {
9987 return false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009988 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009989 // If the fast-case backing storage takes up roughly three times as
9990 // much space (in machine words) as a dictionary backing storage
9991 // would, the object should have slow elements.
9992 int old_capacity = 0;
9993 int used_elements = 0;
9994 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009995 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
9996 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009997 return 3 * dictionary_size <= new_capacity;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009998}
9999
10000
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010001bool JSObject::ShouldConvertToFastElements() {
whesse@chromium.org7b260152011-06-20 15:33:18 +000010002 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010003 // If the elements are sparse, we should not go back to fast case.
10004 if (!HasDenseElements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010005 // An object requiring access checks is never allowed to have fast
10006 // elements. If it had fast elements we would skip security checks.
10007 if (IsAccessCheckNeeded()) return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010008
10009 FixedArray* elements = FixedArray::cast(this->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010010 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010011 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010012 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +000010013 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010014 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +000010015 }
10016 // If an element has been added at a very high index in the elements
10017 // dictionary, we cannot go back to fast case.
10018 if (dictionary->requires_slow_elements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010019 // If the dictionary backing storage takes up roughly half as much
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010020 // space (in machine words) as a fast-case backing storage would,
10021 // the object should have fast elements.
10022 uint32_t array_size = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010023 if (IsJSArray()) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010024 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010025 } else {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010026 array_size = dictionary->max_number_key();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010027 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010028 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010029 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010030 return 2 * dictionary_size >= array_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010031}
10032
10033
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010034bool JSObject::ShouldConvertToFastDoubleElements(
10035 bool* has_smi_only_elements) {
10036 *has_smi_only_elements = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010037 if (FLAG_unbox_double_arrays) {
10038 ASSERT(HasDictionaryElements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010039 SeededNumberDictionary* dictionary =
10040 SeededNumberDictionary::cast(elements());
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010041 bool found_double = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010042 for (int i = 0; i < dictionary->Capacity(); i++) {
10043 Object* key = dictionary->KeyAt(i);
10044 if (key->IsNumber()) {
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010045 Object* value = dictionary->ValueAt(i);
10046 if (!value->IsNumber()) return false;
10047 if (!value->IsSmi()) {
10048 found_double = true;
10049 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010050 }
10051 }
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010052 *has_smi_only_elements = !found_double;
10053 return found_double;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010054 } else {
10055 return false;
10056 }
10057}
10058
10059
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010060// Certain compilers request function template instantiation when they
10061// see the definition of the other template functions in the
10062// class. This requires us to have the template functions put
10063// together, so even though this function belongs in objects-debug.cc,
10064// we keep it here instead to satisfy certain compilers.
whesse@chromium.org023421e2010-12-21 12:19:12 +000010065#ifdef OBJECT_PRINT
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010066template<typename Shape, typename Key>
whesse@chromium.org023421e2010-12-21 12:19:12 +000010067void Dictionary<Shape, Key>::Print(FILE* out) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010068 int capacity = HashTable<Shape, Key>::Capacity();
10069 for (int i = 0; i < capacity; i++) {
10070 Object* k = HashTable<Shape, Key>::KeyAt(i);
10071 if (HashTable<Shape, Key>::IsKey(k)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010072 PrintF(out, " ");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010073 if (k->IsString()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010074 String::cast(k)->StringPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010075 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010076 k->ShortPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010077 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000010078 PrintF(out, ": ");
10079 ValueAt(i)->ShortPrint(out);
10080 PrintF(out, "\n");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010081 }
10082 }
10083}
10084#endif
10085
10086
10087template<typename Shape, typename Key>
10088void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010089 int pos = 0;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010090 int capacity = HashTable<Shape, Key>::Capacity();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010091 AssertNoAllocation no_gc;
10092 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010093 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010094 Object* k = Dictionary<Shape, Key>::KeyAt(i);
10095 if (Dictionary<Shape, Key>::IsKey(k)) {
10096 elements->set(pos++, ValueAt(i), mode);
10097 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010098 }
10099 ASSERT(pos == elements->length());
10100}
10101
10102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103InterceptorInfo* JSObject::GetNamedInterceptor() {
10104 ASSERT(map()->has_named_interceptor());
10105 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010106 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010107 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010108 constructor->shared()->get_api_func_data()->named_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010109 return InterceptorInfo::cast(result);
10110}
10111
10112
10113InterceptorInfo* JSObject::GetIndexedInterceptor() {
10114 ASSERT(map()->has_indexed_interceptor());
10115 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010116 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010117 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010118 constructor->shared()->get_api_func_data()->indexed_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010119 return InterceptorInfo::cast(result);
10120}
10121
10122
lrn@chromium.org303ada72010-10-27 09:33:13 +000010123MaybeObject* JSObject::GetPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010124 JSReceiver* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010125 String* name,
10126 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010127 // Check local property in holder, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010128 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010129 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +000010130 if (result.IsProperty()) {
10131 return GetProperty(receiver, &result, name, attributes);
10132 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010133 // Continue searching via the prototype chain.
10134 Object* pt = GetPrototype();
10135 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010136 if (pt->IsNull()) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010137 return pt->GetPropertyWithReceiver(receiver, name, attributes);
10138}
10139
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010140
lrn@chromium.org303ada72010-10-27 09:33:13 +000010141MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010142 JSReceiver* receiver,
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010143 String* name,
10144 PropertyAttributes* attributes) {
10145 // Check local property in holder, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010146 LookupResult result(GetIsolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010147 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +000010148 if (result.IsProperty()) {
10149 return GetProperty(receiver, &result, name, attributes);
10150 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010151 return GetHeap()->undefined_value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010152}
10153
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010154
lrn@chromium.org303ada72010-10-27 09:33:13 +000010155MaybeObject* JSObject::GetPropertyWithInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010156 JSReceiver* receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +000010157 String* name,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010158 PropertyAttributes* attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010159 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010160 InterceptorInfo* interceptor = GetNamedInterceptor();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010161 HandleScope scope(isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010162 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010163 Handle<JSObject> holder_handle(this);
10164 Handle<String> name_handle(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010165
10166 if (!interceptor->getter()->IsUndefined()) {
10167 v8::NamedPropertyGetter getter =
10168 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010169 LOG(isolate,
10170 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
10171 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010172 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010173 v8::Handle<v8::Value> result;
10174 {
10175 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010176 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010177 result = getter(v8::Utils::ToLocal(name_handle), info);
10178 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010179 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010180 if (!result.IsEmpty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010181 *attributes = NONE;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010182 return *v8::Utils::OpenHandle(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010183 }
10184 }
10185
lrn@chromium.org303ada72010-10-27 09:33:13 +000010186 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010187 *receiver_handle,
10188 *name_handle,
10189 attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010190 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +000010191 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010192}
10193
10194
10195bool JSObject::HasRealNamedProperty(String* key) {
10196 // Check access rights if needed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010197 Isolate* isolate = GetIsolate();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010198 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010199 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10200 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010201 return false;
10202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010203 }
10204
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010205 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010206 LocalLookupRealNamedProperty(key, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +000010207 return result.IsProperty() && (result.type() != INTERCEPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010208}
10209
10210
10211bool JSObject::HasRealElementProperty(uint32_t index) {
10212 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010213 if (IsAccessCheckNeeded()) {
10214 Heap* heap = GetHeap();
10215 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
10216 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10217 return false;
10218 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010219 }
10220
10221 // Handle [] on String objects.
10222 if (this->IsStringObjectWithCharacterAt(index)) return true;
10223
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010224 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010225 case FAST_SMI_ONLY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010226 case FAST_ELEMENTS: {
10227 uint32_t length = IsJSArray() ?
10228 static_cast<uint32_t>(
10229 Smi::cast(JSArray::cast(this)->length())->value()) :
10230 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10231 return (index < length) &&
10232 !FixedArray::cast(elements())->get(index)->IsTheHole();
10233 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +000010234 case FAST_DOUBLE_ELEMENTS: {
10235 uint32_t length = IsJSArray() ?
10236 static_cast<uint32_t>(
10237 Smi::cast(JSArray::cast(this)->length())->value()) :
10238 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
10239 return (index < length) &&
10240 !FixedDoubleArray::cast(elements())->is_the_hole(index);
10241 break;
10242 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010243 case EXTERNAL_PIXEL_ELEMENTS: {
10244 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010245 return index < static_cast<uint32_t>(pixels->length());
10246 }
ager@chromium.org3811b432009-10-28 14:53:37 +000010247 case EXTERNAL_BYTE_ELEMENTS:
10248 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10249 case EXTERNAL_SHORT_ELEMENTS:
10250 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10251 case EXTERNAL_INT_ELEMENTS:
10252 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010253 case EXTERNAL_FLOAT_ELEMENTS:
10254 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +000010255 ExternalArray* array = ExternalArray::cast(elements());
10256 return index < static_cast<uint32_t>(array->length());
10257 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010258 case DICTIONARY_ELEMENTS: {
10259 return element_dictionary()->FindEntry(index)
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010260 != SeededNumberDictionary::kNotFound;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010261 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010262 case NON_STRICT_ARGUMENTS_ELEMENTS:
10263 UNIMPLEMENTED();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010264 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010266 // All possibilities have been handled above already.
10267 UNREACHABLE();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010268 return GetHeap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269}
10270
10271
10272bool JSObject::HasRealNamedCallbackProperty(String* key) {
10273 // Check access rights if needed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010274 Isolate* isolate = GetIsolate();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010275 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010276 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10277 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010278 return false;
10279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010280 }
10281
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010282 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010283 LocalLookupRealNamedProperty(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +000010284 return result.IsFound() && (result.type() == CALLBACKS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010285}
10286
10287
10288int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000010289 return HasFastProperties() ?
10290 map()->NumberOfDescribedProperties(filter) :
10291 property_dictionary()->NumberOfElementsFilterAttributes(filter);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010292}
10293
10294
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010295void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296 Object* temp = get(i);
10297 set(i, get(j));
10298 set(j, temp);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010299 if (this != numbers) {
10300 temp = numbers->get(i);
erikcorry0ad885c2011-11-21 13:51:57 +000010301 numbers->set(i, Smi::cast(numbers->get(j)));
10302 numbers->set(j, Smi::cast(temp));
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010303 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010304}
10305
10306
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010307static void InsertionSortPairs(FixedArray* content,
10308 FixedArray* numbers,
10309 int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010310 for (int i = 1; i < len; i++) {
10311 int j = i;
10312 while (j > 0 &&
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010313 (NumberToUint32(numbers->get(j - 1)) >
10314 NumberToUint32(numbers->get(j)))) {
10315 content->SwapPairs(numbers, j - 1, j);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010316 j--;
10317 }
10318 }
10319}
10320
10321
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010322void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323 // In-place heap sort.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010324 ASSERT(content->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325
10326 // Bottom-up max-heap construction.
10327 for (int i = 1; i < len; ++i) {
10328 int child_index = i;
10329 while (child_index > 0) {
10330 int parent_index = ((child_index + 1) >> 1) - 1;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010331 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10332 uint32_t child_value = NumberToUint32(numbers->get(child_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333 if (parent_value < child_value) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010334 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335 } else {
10336 break;
10337 }
10338 child_index = parent_index;
10339 }
10340 }
10341
10342 // Extract elements and create sorted array.
10343 for (int i = len - 1; i > 0; --i) {
10344 // Put max element at the back of the array.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010345 content->SwapPairs(numbers, 0, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010346 // Sift down the new top element.
10347 int parent_index = 0;
10348 while (true) {
10349 int child_index = ((parent_index + 1) << 1) - 1;
10350 if (child_index >= i) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010351 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
10352 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
10353 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010354 if (child_index + 1 >= i || child1_value > child2_value) {
10355 if (parent_value > child1_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010356 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010357 parent_index = child_index;
10358 } else {
10359 if (parent_value > child2_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010360 content->SwapPairs(numbers, parent_index, child_index + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010361 parent_index = child_index + 1;
10362 }
10363 }
10364 }
10365}
10366
10367
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010368// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
10369void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
10370 ASSERT(this->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010371 // For small arrays, simply use insertion sort.
10372 if (len <= 10) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010373 InsertionSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010374 return;
10375 }
10376 // Check the range of indices.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010377 uint32_t min_index = NumberToUint32(numbers->get(0));
10378 uint32_t max_index = min_index;
10379 uint32_t i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010380 for (i = 1; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010381 if (NumberToUint32(numbers->get(i)) < min_index) {
10382 min_index = NumberToUint32(numbers->get(i));
10383 } else if (NumberToUint32(numbers->get(i)) > max_index) {
10384 max_index = NumberToUint32(numbers->get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010385 }
10386 }
10387 if (max_index - min_index + 1 == len) {
10388 // Indices form a contiguous range, unless there are duplicates.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010389 // Do an in-place linear time sort assuming distinct numbers, but
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010390 // avoid hanging in case they are not.
10391 for (i = 0; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010392 uint32_t p;
10393 uint32_t j = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010394 // While the current element at i is not at its correct position p,
10395 // swap the elements at these two positions.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010396 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010397 j++ < len) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010398 SwapPairs(numbers, i, p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010399 }
10400 }
10401 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010402 HeapSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010403 return;
10404 }
10405}
10406
10407
10408// Fill in the names of local properties into the supplied storage. The main
10409// purpose of this function is to provide reflection information for the object
10410// mirrors.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010411void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000010412 ASSERT(storage->length() >= (NumberOfLocalProperties() - index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010413 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010414 DescriptorArray* descs = map()->instance_descriptors();
10415 for (int i = 0; i < descs->number_of_descriptors(); i++) {
10416 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010417 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010418 ASSERT(storage->length() >= index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010420 property_dictionary()->CopyKeysTo(storage,
10421 index,
10422 StringDictionary::UNSORTED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010423 }
10424}
10425
10426
10427int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
10428 return GetLocalElementKeys(NULL, filter);
10429}
10430
10431
10432int JSObject::NumberOfEnumElements() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010433 // Fast case for objects with no elements.
10434 if (!IsJSValue() && HasFastElements()) {
10435 uint32_t length = IsJSArray() ?
10436 static_cast<uint32_t>(
10437 Smi::cast(JSArray::cast(this)->length())->value()) :
10438 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10439 if (length == 0) return 0;
10440 }
10441 // Compute the number of enumerable elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010442 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
10443}
10444
10445
10446int JSObject::GetLocalElementKeys(FixedArray* storage,
10447 PropertyAttributes filter) {
10448 int counter = 0;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010449 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010450 case FAST_SMI_ONLY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010451 case FAST_ELEMENTS: {
10452 int length = IsJSArray() ?
10453 Smi::cast(JSArray::cast(this)->length())->value() :
10454 FixedArray::cast(elements())->length();
10455 for (int i = 0; i < length; i++) {
10456 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
10457 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010458 storage->set(counter, Smi::FromInt(i));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010459 }
10460 counter++;
10461 }
10462 }
10463 ASSERT(!storage || storage->length() >= counter);
10464 break;
10465 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010466 case FAST_DOUBLE_ELEMENTS: {
10467 int length = IsJSArray() ?
10468 Smi::cast(JSArray::cast(this)->length())->value() :
10469 FixedDoubleArray::cast(elements())->length();
10470 for (int i = 0; i < length; i++) {
10471 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
10472 if (storage != NULL) {
10473 storage->set(counter, Smi::FromInt(i));
10474 }
10475 counter++;
10476 }
10477 }
10478 ASSERT(!storage || storage->length() >= counter);
10479 break;
10480 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010481 case EXTERNAL_PIXEL_ELEMENTS: {
10482 int length = ExternalPixelArray::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010483 while (counter < length) {
10484 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010485 storage->set(counter, Smi::FromInt(counter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010486 }
10487 counter++;
10488 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010489 ASSERT(!storage || storage->length() >= counter);
10490 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491 }
ager@chromium.org3811b432009-10-28 14:53:37 +000010492 case EXTERNAL_BYTE_ELEMENTS:
10493 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10494 case EXTERNAL_SHORT_ELEMENTS:
10495 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10496 case EXTERNAL_INT_ELEMENTS:
10497 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010498 case EXTERNAL_FLOAT_ELEMENTS:
10499 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +000010500 int length = ExternalArray::cast(elements())->length();
10501 while (counter < length) {
10502 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010503 storage->set(counter, Smi::FromInt(counter));
ager@chromium.org3811b432009-10-28 14:53:37 +000010504 }
10505 counter++;
10506 }
10507 ASSERT(!storage || storage->length() >= counter);
10508 break;
10509 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010510 case DICTIONARY_ELEMENTS: {
10511 if (storage != NULL) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010512 element_dictionary()->CopyKeysTo(storage,
10513 filter,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010514 SeededNumberDictionary::SORTED);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010515 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010516 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010517 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010518 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010519 case NON_STRICT_ARGUMENTS_ELEMENTS: {
10520 FixedArray* parameter_map = FixedArray::cast(elements());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010521 int mapped_length = parameter_map->length() - 2;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010522 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
10523 if (arguments->IsDictionary()) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010524 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
10525 // will insert in storage starting at index 0.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010526 SeededNumberDictionary* dictionary =
10527 SeededNumberDictionary::cast(arguments);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010528 if (storage != NULL) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010529 dictionary->CopyKeysTo(
10530 storage, filter, SeededNumberDictionary::UNSORTED);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010531 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010532 counter += dictionary->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010533 for (int i = 0; i < mapped_length; ++i) {
10534 if (!parameter_map->get(i + 2)->IsTheHole()) {
10535 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
whesse@chromium.org7b260152011-06-20 15:33:18 +000010536 ++counter;
10537 }
10538 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010539 if (storage != NULL) storage->SortPairs(storage, counter);
10540
10541 } else {
10542 int backing_length = arguments->length();
10543 int i = 0;
10544 for (; i < mapped_length; ++i) {
10545 if (!parameter_map->get(i + 2)->IsTheHole()) {
10546 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10547 ++counter;
10548 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
10549 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10550 ++counter;
10551 }
10552 }
10553 for (; i < backing_length; ++i) {
10554 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10555 ++counter;
10556 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010557 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010558 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010559 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010560 }
10561
10562 if (this->IsJSValue()) {
10563 Object* val = JSValue::cast(this)->value();
10564 if (val->IsString()) {
10565 String* str = String::cast(val);
10566 if (storage) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010567 for (int i = 0; i < str->length(); i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010568 storage->set(counter + i, Smi::FromInt(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010569 }
10570 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010571 counter += str->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010572 }
10573 }
10574 ASSERT(!storage || storage->length() == counter);
10575 return counter;
10576}
10577
10578
10579int JSObject::GetEnumElementKeys(FixedArray* storage) {
10580 return GetLocalElementKeys(storage,
10581 static_cast<PropertyAttributes>(DONT_ENUM));
10582}
10583
10584
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010585// StringKey simply carries a string object as key.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010586class StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587 public:
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010588 explicit StringKey(String* string) :
10589 string_(string),
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010590 hash_(HashForObject(string)) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010591
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010592 bool IsMatch(Object* string) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010593 // We know that all entries in a hash table had their hash keys created.
10594 // Use that knowledge to have fast failure.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010595 if (hash_ != HashForObject(string)) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010596 return false;
10597 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010598 return string_->Equals(String::cast(string));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599 }
10600
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010601 uint32_t Hash() { return hash_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010602
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010603 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010605 Object* AsObject() { return string_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010606
10607 String* string_;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010608 uint32_t hash_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609};
10610
ager@chromium.org381abbb2009-02-25 13:23:22 +000010611
10612// StringSharedKeys are used as keys in the eval cache.
10613class StringSharedKey : public HashTableKey {
10614 public:
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010615 StringSharedKey(String* source,
10616 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010617 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010618 int scope_position)
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010619 : source_(source),
10620 shared_(shared),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010621 language_mode_(language_mode),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010622 scope_position_(scope_position) { }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010623
10624 bool IsMatch(Object* other) {
10625 if (!other->IsFixedArray()) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010626 FixedArray* other_array = FixedArray::cast(other);
10627 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
ager@chromium.org381abbb2009-02-25 13:23:22 +000010628 if (shared != shared_) return false;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010629 int language_unchecked = Smi::cast(other_array->get(2))->value();
10630 ASSERT(language_unchecked == CLASSIC_MODE ||
10631 language_unchecked == STRICT_MODE ||
10632 language_unchecked == EXTENDED_MODE);
10633 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10634 if (language_mode != language_mode_) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010635 int scope_position = Smi::cast(other_array->get(3))->value();
10636 if (scope_position != scope_position_) return false;
10637 String* source = String::cast(other_array->get(1));
ager@chromium.org381abbb2009-02-25 13:23:22 +000010638 return source->Equals(source_);
10639 }
10640
ager@chromium.org381abbb2009-02-25 13:23:22 +000010641 static uint32_t StringSharedHashHelper(String* source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010642 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010643 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010644 int scope_position) {
ager@chromium.org381abbb2009-02-25 13:23:22 +000010645 uint32_t hash = source->Hash();
10646 if (shared->HasSourceCode()) {
10647 // Instead of using the SharedFunctionInfo pointer in the hash
10648 // code computation, we use a combination of the hash of the
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010649 // script source code and the start position of the calling scope.
10650 // We do this to ensure that the cache entries can survive garbage
ager@chromium.org381abbb2009-02-25 13:23:22 +000010651 // collection.
10652 Script* script = Script::cast(shared->script());
10653 hash ^= String::cast(script->source())->Hash();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010654 if (language_mode == STRICT_MODE) hash ^= 0x8000;
10655 if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010656 hash += scope_position;
ager@chromium.org381abbb2009-02-25 13:23:22 +000010657 }
10658 return hash;
10659 }
10660
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010661 uint32_t Hash() {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010662 return StringSharedHashHelper(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010663 source_, shared_, language_mode_, scope_position_);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010664 }
10665
10666 uint32_t HashForObject(Object* obj) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010667 FixedArray* other_array = FixedArray::cast(obj);
10668 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10669 String* source = String::cast(other_array->get(1));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010670 int language_unchecked = Smi::cast(other_array->get(2))->value();
10671 ASSERT(language_unchecked == CLASSIC_MODE ||
10672 language_unchecked == STRICT_MODE ||
10673 language_unchecked == EXTENDED_MODE);
10674 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010675 int scope_position = Smi::cast(other_array->get(3))->value();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010676 return StringSharedHashHelper(
10677 source, shared, language_mode, scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010678 }
10679
lrn@chromium.org303ada72010-10-27 09:33:13 +000010680 MUST_USE_RESULT MaybeObject* AsObject() {
10681 Object* obj;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010682 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010683 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10684 }
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010685 FixedArray* other_array = FixedArray::cast(obj);
10686 other_array->set(0, shared_);
10687 other_array->set(1, source_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010688 other_array->set(2, Smi::FromInt(language_mode_));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010689 other_array->set(3, Smi::FromInt(scope_position_));
10690 return other_array;
ager@chromium.org381abbb2009-02-25 13:23:22 +000010691 }
10692
ager@chromium.org381abbb2009-02-25 13:23:22 +000010693 private:
10694 String* source_;
10695 SharedFunctionInfo* shared_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010696 LanguageMode language_mode_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010697 int scope_position_;
ager@chromium.org381abbb2009-02-25 13:23:22 +000010698};
10699
10700
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010701// RegExpKey carries the source and flags of a regular expression as key.
10702class RegExpKey : public HashTableKey {
10703 public:
10704 RegExpKey(String* string, JSRegExp::Flags flags)
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010705 : string_(string),
10706 flags_(Smi::FromInt(flags.value())) { }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010707
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000010708 // Rather than storing the key in the hash table, a pointer to the
10709 // stored value is stored where the key should be. IsMatch then
10710 // compares the search key to the found object, rather than comparing
10711 // a key to a key.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010712 bool IsMatch(Object* obj) {
10713 FixedArray* val = FixedArray::cast(obj);
10714 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
10715 && (flags_ == val->get(JSRegExp::kFlagsIndex));
10716 }
10717
10718 uint32_t Hash() { return RegExpHash(string_, flags_); }
10719
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010720 Object* AsObject() {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010721 // Plain hash maps, which is where regexp keys are used, don't
10722 // use this function.
10723 UNREACHABLE();
10724 return NULL;
10725 }
10726
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010727 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010728 FixedArray* val = FixedArray::cast(obj);
10729 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
10730 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
10731 }
10732
10733 static uint32_t RegExpHash(String* string, Smi* flags) {
10734 return string->Hash() + flags->value();
10735 }
10736
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010737 String* string_;
10738 Smi* flags_;
10739};
10740
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010741// Utf8SymbolKey carries a vector of chars as key.
10742class Utf8SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010743 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010744 explicit Utf8SymbolKey(Vector<const char> string, uint32_t seed)
10745 : string_(string), hash_field_(0), seed_(seed) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010747 bool IsMatch(Object* string) {
10748 return String::cast(string)->IsEqualTo(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010749 }
10750
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010751 uint32_t Hash() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010752 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010753 unibrow::Utf8InputBuffer<> buffer(string_.start(),
10754 static_cast<unsigned>(string_.length()));
10755 chars_ = buffer.Length();
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010756 hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010757 uint32_t result = hash_field_ >> String::kHashShift;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010758 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10759 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010760 }
10761
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010762 uint32_t HashForObject(Object* other) {
10763 return String::cast(other)->Hash();
10764 }
10765
lrn@chromium.org303ada72010-10-27 09:33:13 +000010766 MaybeObject* AsObject() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010767 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010768 return Isolate::Current()->heap()->AllocateSymbol(
10769 string_, chars_, hash_field_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010770 }
10771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010772 Vector<const char> string_;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010773 uint32_t hash_field_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010774 int chars_; // Caches the number of characters when computing the hash code.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010775 uint32_t seed_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776};
10777
10778
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010779template <typename Char>
10780class SequentialSymbolKey : public HashTableKey {
10781 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010782 explicit SequentialSymbolKey(Vector<const Char> string, uint32_t seed)
10783 : string_(string), hash_field_(0), seed_(seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010784
10785 uint32_t Hash() {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010786 StringHasher hasher(string_.length(), seed_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010787
10788 // Very long strings have a trivial hash that doesn't inspect the
10789 // string contents.
10790 if (hasher.has_trivial_hash()) {
10791 hash_field_ = hasher.GetHashField();
10792 } else {
10793 int i = 0;
10794 // Do the iterative array index computation as long as there is a
10795 // chance this is an array index.
10796 while (i < string_.length() && hasher.is_array_index()) {
10797 hasher.AddCharacter(static_cast<uc32>(string_[i]));
10798 i++;
10799 }
10800
10801 // Process the remaining characters without updating the array
10802 // index.
10803 while (i < string_.length()) {
10804 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
10805 i++;
10806 }
10807 hash_field_ = hasher.GetHashField();
10808 }
10809
10810 uint32_t result = hash_field_ >> String::kHashShift;
10811 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10812 return result;
10813 }
10814
10815
10816 uint32_t HashForObject(Object* other) {
10817 return String::cast(other)->Hash();
10818 }
10819
10820 Vector<const Char> string_;
10821 uint32_t hash_field_;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010822 uint32_t seed_;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010823};
10824
10825
10826
10827class AsciiSymbolKey : public SequentialSymbolKey<char> {
10828 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010829 AsciiSymbolKey(Vector<const char> str, uint32_t seed)
10830 : SequentialSymbolKey<char>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010831
10832 bool IsMatch(Object* string) {
10833 return String::cast(string)->IsAsciiEqualTo(string_);
10834 }
10835
10836 MaybeObject* AsObject() {
10837 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010838 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010839 }
10840};
10841
10842
danno@chromium.org40cb8782011-05-25 07:58:50 +000010843class SubStringAsciiSymbolKey : public HashTableKey {
10844 public:
10845 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
10846 int from,
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010847 int length,
10848 uint32_t seed)
10849 : string_(string), from_(from), length_(length), seed_(seed) { }
danno@chromium.org40cb8782011-05-25 07:58:50 +000010850
10851 uint32_t Hash() {
10852 ASSERT(length_ >= 0);
10853 ASSERT(from_ + length_ <= string_->length());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010854 StringHasher hasher(length_, string_->GetHeap()->HashSeed());
danno@chromium.org40cb8782011-05-25 07:58:50 +000010855
10856 // Very long strings have a trivial hash that doesn't inspect the
10857 // string contents.
10858 if (hasher.has_trivial_hash()) {
10859 hash_field_ = hasher.GetHashField();
10860 } else {
10861 int i = 0;
10862 // Do the iterative array index computation as long as there is a
10863 // chance this is an array index.
10864 while (i < length_ && hasher.is_array_index()) {
10865 hasher.AddCharacter(static_cast<uc32>(
10866 string_->SeqAsciiStringGet(i + from_)));
10867 i++;
10868 }
10869
10870 // Process the remaining characters without updating the array
10871 // index.
10872 while (i < length_) {
10873 hasher.AddCharacterNoIndex(static_cast<uc32>(
10874 string_->SeqAsciiStringGet(i + from_)));
10875 i++;
10876 }
10877 hash_field_ = hasher.GetHashField();
10878 }
10879
10880 uint32_t result = hash_field_ >> String::kHashShift;
10881 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10882 return result;
10883 }
10884
10885
10886 uint32_t HashForObject(Object* other) {
10887 return String::cast(other)->Hash();
10888 }
10889
10890 bool IsMatch(Object* string) {
10891 Vector<const char> chars(string_->GetChars() + from_, length_);
10892 return String::cast(string)->IsAsciiEqualTo(chars);
10893 }
10894
10895 MaybeObject* AsObject() {
10896 if (hash_field_ == 0) Hash();
10897 Vector<const char> chars(string_->GetChars() + from_, length_);
10898 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
10899 }
10900
10901 private:
10902 Handle<SeqAsciiString> string_;
10903 int from_;
10904 int length_;
10905 uint32_t hash_field_;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010906 uint32_t seed_;
danno@chromium.org40cb8782011-05-25 07:58:50 +000010907};
10908
10909
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010910class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
10911 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010912 explicit TwoByteSymbolKey(Vector<const uc16> str, uint32_t seed)
10913 : SequentialSymbolKey<uc16>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010914
10915 bool IsMatch(Object* string) {
10916 return String::cast(string)->IsTwoByteEqualTo(string_);
10917 }
10918
10919 MaybeObject* AsObject() {
10920 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010921 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010922 }
10923};
10924
10925
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010926// SymbolKey carries a string/symbol object as key.
10927class SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010928 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010929 explicit SymbolKey(String* string)
10930 : string_(string) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010931
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010932 bool IsMatch(Object* string) {
10933 return String::cast(string)->Equals(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010934 }
10935
10936 uint32_t Hash() { return string_->Hash(); }
10937
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010938 uint32_t HashForObject(Object* other) {
10939 return String::cast(other)->Hash();
10940 }
10941
lrn@chromium.org303ada72010-10-27 09:33:13 +000010942 MaybeObject* AsObject() {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000010943 // Attempt to flatten the string, so that symbols will most often
10944 // be flat strings.
10945 string_ = string_->TryFlattenGetString();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010946 Heap* heap = string_->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947 // Transform string to symbol if possible.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010948 Map* map = heap->SymbolMapForString(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010949 if (map != NULL) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000010950 string_->set_map_no_write_barrier(map);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010951 ASSERT(string_->IsSymbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010952 return string_;
10953 }
10954 // Otherwise allocate a new symbol.
10955 StringInputBuffer buffer(string_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010956 return heap->AllocateInternalSymbol(&buffer,
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010957 string_->length(),
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010958 string_->hash_field());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959 }
10960
10961 static uint32_t StringHash(Object* obj) {
10962 return String::cast(obj)->Hash();
10963 }
10964
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010965 String* string_;
10966};
10967
10968
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010969template<typename Shape, typename Key>
10970void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010971 IteratePointers(v, 0, kElementsStartOffset);
10972}
10973
10974
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010975template<typename Shape, typename Key>
10976void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010977 IteratePointers(v,
10978 kElementsStartOffset,
10979 kHeaderSize + length() * kPointerSize);
10980}
10981
10982
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010983template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010984MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
10985 PretenureFlag pretenure) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010986 int capacity = ComputeCapacity(at_least_space_for);
10987 if (capacity > HashTable::kMaxCapacity) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010988 return Failure::OutOfMemoryException();
10989 }
10990
lrn@chromium.org303ada72010-10-27 09:33:13 +000010991 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010992 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
10993 AllocateHashTable(EntryToIndex(capacity), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010994 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010995 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010996 HashTable::cast(obj)->SetNumberOfElements(0);
10997 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
10998 HashTable::cast(obj)->SetCapacity(capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010999 return obj;
11000}
11001
11002
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011003// Find entry for key otherwise return kNotFound.
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011004int StringDictionary::FindEntry(String* key) {
11005 if (!key->IsSymbol()) {
11006 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
11007 }
11008
11009 // Optimized for symbol key. Knowledge of the key type allows:
11010 // 1. Move the check if the key is a symbol out of the loop.
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011011 // 2. Avoid comparing hash codes in symbol to symbol comparison.
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011012 // 3. Detect a case when a dictionary key is not a symbol but the key is.
11013 // In case of positive result the dictionary key may be replaced by
11014 // the symbol with minimal performance penalty. It gives a chance to
11015 // perform further lookups in code stubs (and significant performance boost
11016 // a certain style of code).
11017
11018 // EnsureCapacity will guarantee the hash table is never full.
11019 uint32_t capacity = Capacity();
11020 uint32_t entry = FirstProbe(key->Hash(), capacity);
11021 uint32_t count = 1;
11022
11023 while (true) {
11024 int index = EntryToIndex(entry);
11025 Object* element = get(index);
11026 if (element->IsUndefined()) break; // Empty entry.
11027 if (key == element) return entry;
11028 if (!element->IsSymbol() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011029 !element->IsTheHole() &&
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011030 String::cast(element)->Equals(key)) {
11031 // Replace a non-symbol key by the equivalent symbol for faster further
11032 // lookups.
11033 set(index, key);
11034 return entry;
11035 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011036 ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key));
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011037 entry = NextProbe(entry, count++, capacity);
11038 }
11039 return kNotFound;
11040}
11041
11042
rossberg@chromium.org994edf62012-02-06 10:12:55 +000011043bool StringDictionary::ContainsTransition(int entry) {
11044 switch (DetailsAt(entry).type()) {
11045 case MAP_TRANSITION:
11046 case CONSTANT_TRANSITION:
11047 case ELEMENTS_TRANSITION:
11048 return true;
11049 case CALLBACKS: {
11050 Object* value = ValueAt(entry);
11051 if (!value->IsAccessorPair()) return false;
11052 AccessorPair* accessors = AccessorPair::cast(value);
11053 return accessors->getter()->IsMap() || accessors->setter()->IsMap();
11054 }
11055 case NORMAL:
11056 case FIELD:
11057 case CONSTANT_FUNCTION:
11058 case HANDLER:
11059 case INTERCEPTOR:
11060 case NULL_DESCRIPTOR:
11061 return false;
11062 }
11063 UNREACHABLE(); // Keep the compiler happy.
11064 return false;
11065}
11066
11067
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011068template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000011069MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
11070 ASSERT(NumberOfElements() < new_table->Capacity());
11071
11072 AssertNoAllocation no_gc;
11073 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
11074
11075 // Copy prefix to new array.
11076 for (int i = kPrefixStartIndex;
11077 i < kPrefixStartIndex + Shape::kPrefixSize;
11078 i++) {
11079 new_table->set(i, get(i), mode);
11080 }
11081
11082 // Rehash the elements.
11083 int capacity = Capacity();
11084 for (int i = 0; i < capacity; i++) {
11085 uint32_t from_index = EntryToIndex(i);
11086 Object* k = get(from_index);
11087 if (IsKey(k)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011088 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
ager@chromium.org04921a82011-06-27 13:21:41 +000011089 uint32_t insertion_index =
11090 EntryToIndex(new_table->FindInsertionEntry(hash));
11091 for (int j = 0; j < Shape::kEntrySize; j++) {
11092 new_table->set(insertion_index + j, get(from_index + j), mode);
11093 }
11094 }
11095 }
11096 new_table->SetNumberOfElements(NumberOfElements());
11097 new_table->SetNumberOfDeletedElements(0);
11098 return new_table;
11099}
11100
11101
11102template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000011103MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011104 int capacity = Capacity();
11105 int nof = NumberOfElements() + n;
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +000011106 int nod = NumberOfDeletedElements();
11107 // Return if:
11108 // 50% is still free after adding n elements and
11109 // at most 50% of the free elements are deleted elements.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011110 if (nod <= (capacity - nof) >> 1) {
11111 int needed_free = nof >> 1;
11112 if (nof + needed_free <= capacity) return this;
11113 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011114
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011115 const int kMinCapacityForPretenure = 256;
11116 bool pretenure =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011117 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011118 Object* obj;
11119 { MaybeObject* maybe_obj =
11120 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
11121 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11122 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011123
ager@chromium.org04921a82011-06-27 13:21:41 +000011124 return Rehash(HashTable::cast(obj), key);
11125}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011126
ager@chromium.org04921a82011-06-27 13:21:41 +000011127
11128template<typename Shape, typename Key>
11129MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
11130 int capacity = Capacity();
11131 int nof = NumberOfElements();
11132
11133 // Shrink to fit the number of elements if only a quarter of the
11134 // capacity is filled with elements.
11135 if (nof > (capacity >> 2)) return this;
11136 // Allocate a new dictionary with room for at least the current
11137 // number of elements. The allocation method will make sure that
11138 // there is extra room in the dictionary for additions. Don't go
11139 // lower than room for 16 elements.
11140 int at_least_room_for = nof;
11141 if (at_least_room_for < 16) return this;
11142
11143 const int kMinCapacityForPretenure = 256;
11144 bool pretenure =
11145 (at_least_room_for > kMinCapacityForPretenure) &&
11146 !GetHeap()->InNewSpace(this);
11147 Object* obj;
11148 { MaybeObject* maybe_obj =
11149 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
11150 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011151 }
ager@chromium.org04921a82011-06-27 13:21:41 +000011152
11153 return Rehash(HashTable::cast(obj), key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011154}
11155
11156
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011157template<typename Shape, typename Key>
11158uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011159 uint32_t capacity = Capacity();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011160 uint32_t entry = FirstProbe(hash, capacity);
11161 uint32_t count = 1;
11162 // EnsureCapacity will guarantee the hash table is never full.
11163 while (true) {
11164 Object* element = KeyAt(entry);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011165 if (element->IsUndefined() || element->IsTheHole()) break;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011166 entry = NextProbe(entry, count++, capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011167 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011168 return entry;
11169}
11170
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011171// Force instantiation of template instances class.
11172// Please note this list is compiler dependent.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011173
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011174template class HashTable<SymbolTableShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011175
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011176template class HashTable<CompilationCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011177
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011178template class HashTable<MapCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011179
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011180template class HashTable<ObjectHashTableShape<1>, Object*>;
11181
11182template class HashTable<ObjectHashTableShape<2>, Object*>;
vegorov@chromium.org7943d462011-08-01 11:41:52 +000011183
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011184template class Dictionary<StringDictionaryShape, String*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011185
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011186template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011187
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011188template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
11189
11190template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11191 Allocate(int at_least_space_for);
11192
11193template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11194 Allocate(int at_least_space_for);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011195
lrn@chromium.org303ada72010-10-27 09:33:13 +000011196template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011197 int);
11198
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011199template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011200 uint32_t, Object*);
11201
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011202template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11203 AtPut(uint32_t, Object*);
11204
ulan@chromium.org65a89c22012-02-14 11:46:07 +000011205template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11206 SlowReverseLookup(Object* value);
11207
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011208template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11209 SlowReverseLookup(Object* value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011210
11211template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
11212 Object*);
11213
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011214template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011215 FixedArray*,
11216 PropertyAttributes,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011217 Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011218
11219template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
11220 int, JSObject::DeleteMode);
11221
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011222template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11223 DeleteProperty(int, JSObject::DeleteMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011224
ager@chromium.org04921a82011-06-27 13:21:41 +000011225template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
11226 String*);
11227
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011228template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
ager@chromium.org04921a82011-06-27 13:21:41 +000011229 uint32_t);
11230
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011231template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011232 FixedArray*,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011233 int,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011234 Dictionary<StringDictionaryShape, String*>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011235
11236template int
11237Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
11238 PropertyAttributes);
11239
lrn@chromium.org303ada72010-10-27 09:33:13 +000011240template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011241 String*, Object*, PropertyDetails);
11242
lrn@chromium.org303ada72010-10-27 09:33:13 +000011243template MaybeObject*
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011244Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
11245
11246template int
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011247Dictionary<SeededNumberDictionaryShape, uint32_t>::
11248 NumberOfElementsFilterAttributes(PropertyAttributes);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011249
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011250template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011251 uint32_t, Object*, PropertyDetails);
11252
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011253template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
11254 uint32_t, Object*, PropertyDetails);
11255
11256template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11257 EnsureCapacity(int, uint32_t);
11258
11259template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
lrn@chromium.org303ada72010-10-27 09:33:13 +000011260 EnsureCapacity(int, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011261
lrn@chromium.org303ada72010-10-27 09:33:13 +000011262template MaybeObject* Dictionary<StringDictionaryShape, String*>::
11263 EnsureCapacity(int, String*);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011264
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011265template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11266 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
11267
11268template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11269 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011270
lrn@chromium.org303ada72010-10-27 09:33:13 +000011271template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011272 String*, Object*, PropertyDetails, uint32_t);
11273
11274template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011275int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011276
11277template
11278int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011279
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011280template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011281int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011282
11283
ager@chromium.org5ec48922009-05-05 07:25:34 +000011284// Collates undefined and unexisting elements below limit from position
11285// zero of the elements. The object stays in Dictionary mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011286MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011287 ASSERT(HasDictionaryElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011288 // Must stay in dictionary mode, either because of requires_slow_elements,
11289 // or because we are not going to sort (and therefore compact) all of the
11290 // elements.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011291 SeededNumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011292 HeapNumber* result_double = NULL;
11293 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11294 // Allocate space for result before we start mutating the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011295 Object* new_double;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011296 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011297 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11298 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011299 result_double = HeapNumber::cast(new_double);
11300 }
11301
lrn@chromium.org303ada72010-10-27 09:33:13 +000011302 Object* obj;
11303 { MaybeObject* maybe_obj =
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011304 SeededNumberDictionary::Allocate(dict->NumberOfElements());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011305 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11306 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011307 SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011308
11309 AssertNoAllocation no_alloc;
11310
ager@chromium.org5ec48922009-05-05 07:25:34 +000011311 uint32_t pos = 0;
11312 uint32_t undefs = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011313 int capacity = dict->Capacity();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011314 for (int i = 0; i < capacity; i++) {
11315 Object* k = dict->KeyAt(i);
11316 if (dict->IsKey(k)) {
11317 ASSERT(k->IsNumber());
11318 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
11319 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
11320 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
11321 Object* value = dict->ValueAt(i);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011322 PropertyDetails details = dict->DetailsAt(i);
11323 if (details.type() == CALLBACKS) {
11324 // Bail out and do the sorting of undefineds and array holes in JS.
11325 return Smi::FromInt(-1);
11326 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011327 uint32_t key = NumberToUint32(k);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011328 // In the following we assert that adding the entry to the new dictionary
11329 // does not cause GC. This is the case because we made sure to allocate
11330 // the dictionary big enough above, so it need not grow.
ager@chromium.org5ec48922009-05-05 07:25:34 +000011331 if (key < limit) {
11332 if (value->IsUndefined()) {
11333 undefs++;
11334 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011335 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11336 // Adding an entry with the key beyond smi-range requires
11337 // allocation. Bailout.
11338 return Smi::FromInt(-1);
11339 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000011340 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011341 pos++;
11342 }
11343 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011344 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
11345 // Adding an entry with the key beyond smi-range requires
11346 // allocation. Bailout.
11347 return Smi::FromInt(-1);
11348 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000011349 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011350 }
11351 }
11352 }
11353
11354 uint32_t result = pos;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011355 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011356 Heap* heap = GetHeap();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011357 while (undefs > 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011358 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11359 // Adding an entry with the key beyond smi-range requires
11360 // allocation. Bailout.
11361 return Smi::FromInt(-1);
11362 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011363 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
lrn@chromium.org303ada72010-10-27 09:33:13 +000011364 ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011365 pos++;
11366 undefs--;
11367 }
11368
11369 set_elements(new_dict);
11370
11371 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11372 return Smi::FromInt(static_cast<int>(result));
11373 }
11374
11375 ASSERT_NE(NULL, result_double);
11376 result_double->set_value(static_cast<double>(result));
11377 return result_double;
11378}
11379
11380
11381// Collects all defined (non-hole) and non-undefined (array) elements at
11382// the start of the elements array.
11383// If the object is in dictionary mode, it is converted to fast elements
11384// mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011385MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011386 Heap* heap = GetHeap();
11387
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011388 if (HasDictionaryElements()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000011389 // Convert to fast elements containing only the existing properties.
11390 // Ordering is irrelevant, since we are going to sort anyway.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011391 SeededNumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011392 if (IsJSArray() || dict->requires_slow_elements() ||
11393 dict->max_number_key() >= limit) {
11394 return PrepareSlowElementsForSort(limit);
11395 }
11396 // Convert to fast elements.
11397
lrn@chromium.org303ada72010-10-27 09:33:13 +000011398 Object* obj;
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011399 { MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
11400 FAST_ELEMENTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011401 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11402 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011403 Map* new_map = Map::cast(obj);
11404
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011405 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
lrn@chromium.org303ada72010-10-27 09:33:13 +000011406 Object* new_array;
11407 { MaybeObject* maybe_new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011408 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011409 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
11410 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011411 FixedArray* fast_elements = FixedArray::cast(new_array);
11412 dict->CopyValuesTo(fast_elements);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011413
11414 set_map(new_map);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011415 set_elements(fast_elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011416 } else if (HasExternalArrayElements()) {
11417 // External arrays cannot have holes or undefined elements.
11418 return Smi::FromInt(ExternalArray::cast(elements())->length());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011419 } else if (!HasFastDoubleElements()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011420 Object* obj;
11421 { MaybeObject* maybe_obj = EnsureWritableFastElements();
11422 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11423 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011424 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011425 ASSERT(HasFastTypeElements() || HasFastDoubleElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011426
11427 // Collect holes at the end, undefined before that and the rest at the
11428 // start, and return the number of non-hole, non-undefined values.
11429
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011430 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
11431 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011432 if (limit > elements_length) {
11433 limit = elements_length ;
11434 }
11435 if (limit == 0) {
11436 return Smi::FromInt(0);
11437 }
11438
11439 HeapNumber* result_double = NULL;
11440 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11441 // Pessimistically allocate space for return value before
11442 // we start mutating the array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011443 Object* new_double;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011444 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011445 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11446 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011447 result_double = HeapNumber::cast(new_double);
11448 }
11449
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011450 uint32_t result = 0;
11451 if (elements_base->map() == heap->fixed_double_array_map()) {
11452 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
11453 // Split elements into defined and the_hole, in that order.
11454 unsigned int holes = limit;
11455 // Assume most arrays contain no holes and undefined values, so minimize the
11456 // number of stores of non-undefined, non-the-hole values.
11457 for (unsigned int i = 0; i < holes; i++) {
11458 if (elements->is_the_hole(i)) {
11459 holes--;
11460 } else {
11461 continue;
11462 }
11463 // Position i needs to be filled.
11464 while (holes > i) {
11465 if (elements->is_the_hole(holes)) {
11466 holes--;
11467 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011468 elements->set(i, elements->get_scalar(holes));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011469 break;
11470 }
11471 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011472 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011473 result = holes;
11474 while (holes < limit) {
11475 elements->set_the_hole(holes);
11476 holes++;
11477 }
11478 } else {
11479 FixedArray* elements = FixedArray::cast(elements_base);
11480 AssertNoAllocation no_alloc;
11481
11482 // Split elements into defined, undefined and the_hole, in that order. Only
11483 // count locations for undefined and the hole, and fill them afterwards.
11484 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
11485 unsigned int undefs = limit;
11486 unsigned int holes = limit;
11487 // Assume most arrays contain no holes and undefined values, so minimize the
11488 // number of stores of non-undefined, non-the-hole values.
11489 for (unsigned int i = 0; i < undefs; i++) {
11490 Object* current = elements->get(i);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011491 if (current->IsTheHole()) {
11492 holes--;
11493 undefs--;
11494 } else if (current->IsUndefined()) {
11495 undefs--;
11496 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011497 continue;
11498 }
11499 // Position i needs to be filled.
11500 while (undefs > i) {
11501 current = elements->get(undefs);
11502 if (current->IsTheHole()) {
11503 holes--;
11504 undefs--;
11505 } else if (current->IsUndefined()) {
11506 undefs--;
11507 } else {
11508 elements->set(i, current, write_barrier);
11509 break;
11510 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011511 }
11512 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011513 result = undefs;
11514 while (undefs < holes) {
11515 elements->set_undefined(undefs);
11516 undefs++;
11517 }
11518 while (holes < limit) {
11519 elements->set_the_hole(holes);
11520 holes++;
11521 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011522 }
11523
11524 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11525 return Smi::FromInt(static_cast<int>(result));
11526 }
11527 ASSERT_NE(NULL, result_double);
11528 result_double->set_value(static_cast<double>(result));
11529 return result_double;
11530}
11531
11532
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011533Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011534 uint8_t clamped_value = 0;
11535 if (index < static_cast<uint32_t>(length())) {
11536 if (value->IsSmi()) {
11537 int int_value = Smi::cast(value)->value();
11538 if (int_value < 0) {
11539 clamped_value = 0;
11540 } else if (int_value > 255) {
11541 clamped_value = 255;
11542 } else {
11543 clamped_value = static_cast<uint8_t>(int_value);
11544 }
11545 } else if (value->IsHeapNumber()) {
11546 double double_value = HeapNumber::cast(value)->value();
11547 if (!(double_value > 0)) {
11548 // NaN and less than zero clamp to zero.
11549 clamped_value = 0;
11550 } else if (double_value > 255) {
11551 // Greater than 255 clamp to 255.
11552 clamped_value = 255;
11553 } else {
11554 // Other doubles are rounded to the nearest integer.
11555 clamped_value = static_cast<uint8_t>(double_value + 0.5);
11556 }
11557 } else {
11558 // Clamp undefined to zero (default). All other types have been
11559 // converted to a number type further up in the call chain.
11560 ASSERT(value->IsUndefined());
11561 }
11562 set(index, clamped_value);
11563 }
11564 return Smi::FromInt(clamped_value);
11565}
11566
11567
ager@chromium.org3811b432009-10-28 14:53:37 +000011568template<typename ExternalArrayClass, typename ValueType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011569static MaybeObject* ExternalArrayIntSetter(Heap* heap,
11570 ExternalArrayClass* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000011571 uint32_t index,
11572 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011573 ValueType cast_value = 0;
11574 if (index < static_cast<uint32_t>(receiver->length())) {
11575 if (value->IsSmi()) {
11576 int int_value = Smi::cast(value)->value();
11577 cast_value = static_cast<ValueType>(int_value);
11578 } else if (value->IsHeapNumber()) {
11579 double double_value = HeapNumber::cast(value)->value();
11580 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
11581 } else {
11582 // Clamp undefined to zero (default). All other types have been
11583 // converted to a number type further up in the call chain.
11584 ASSERT(value->IsUndefined());
11585 }
11586 receiver->set(index, cast_value);
11587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011588 return heap->NumberFromInt32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011589}
11590
11591
lrn@chromium.org303ada72010-10-27 09:33:13 +000011592MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011593 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011594 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011595}
11596
11597
lrn@chromium.org303ada72010-10-27 09:33:13 +000011598MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
11599 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011600 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011601 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011602}
11603
11604
lrn@chromium.org303ada72010-10-27 09:33:13 +000011605MaybeObject* ExternalShortArray::SetValue(uint32_t index,
11606 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011607 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011608 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011609}
11610
11611
lrn@chromium.org303ada72010-10-27 09:33:13 +000011612MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
11613 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011614 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011615 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011616}
11617
11618
lrn@chromium.org303ada72010-10-27 09:33:13 +000011619MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011620 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011622}
11623
11624
lrn@chromium.org303ada72010-10-27 09:33:13 +000011625MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011626 uint32_t cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011627 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000011628 if (index < static_cast<uint32_t>(length())) {
11629 if (value->IsSmi()) {
11630 int int_value = Smi::cast(value)->value();
11631 cast_value = static_cast<uint32_t>(int_value);
11632 } else if (value->IsHeapNumber()) {
11633 double double_value = HeapNumber::cast(value)->value();
11634 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
11635 } else {
11636 // Clamp undefined to zero (default). All other types have been
11637 // converted to a number type further up in the call chain.
11638 ASSERT(value->IsUndefined());
11639 }
11640 set(index, cast_value);
11641 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011642 return heap->NumberFromUint32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011643}
11644
11645
lrn@chromium.org303ada72010-10-27 09:33:13 +000011646MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000011647 float cast_value = static_cast<float>(OS::nan_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011648 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000011649 if (index < static_cast<uint32_t>(length())) {
11650 if (value->IsSmi()) {
11651 int int_value = Smi::cast(value)->value();
11652 cast_value = static_cast<float>(int_value);
11653 } else if (value->IsHeapNumber()) {
11654 double double_value = HeapNumber::cast(value)->value();
11655 cast_value = static_cast<float>(double_value);
11656 } else {
yangguo@chromium.org56454712012-02-16 15:33:53 +000011657 // Clamp undefined to NaN (default). All other types have been
ager@chromium.org3811b432009-10-28 14:53:37 +000011658 // converted to a number type further up in the call chain.
11659 ASSERT(value->IsUndefined());
11660 }
11661 set(index, cast_value);
11662 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011663 return heap->AllocateHeapNumber(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011664}
11665
11666
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011667MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000011668 double double_value = OS::nan_value();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011669 Heap* heap = GetHeap();
11670 if (index < static_cast<uint32_t>(length())) {
11671 if (value->IsSmi()) {
11672 int int_value = Smi::cast(value)->value();
11673 double_value = static_cast<double>(int_value);
11674 } else if (value->IsHeapNumber()) {
11675 double_value = HeapNumber::cast(value)->value();
11676 } else {
yangguo@chromium.org56454712012-02-16 15:33:53 +000011677 // Clamp undefined to NaN (default). All other types have been
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011678 // converted to a number type further up in the call chain.
11679 ASSERT(value->IsUndefined());
11680 }
11681 set(index, double_value);
11682 }
11683 return heap->AllocateHeapNumber(double_value);
11684}
11685
11686
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011687JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011688 ASSERT(!HasFastProperties());
11689 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011690 return JSGlobalPropertyCell::cast(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011691}
11692
11693
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011694Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
11695 Handle<GlobalObject> global,
11696 Handle<String> name) {
11697 Isolate* isolate = global->GetIsolate();
11698 CALL_HEAP_FUNCTION(isolate,
11699 global->EnsurePropertyCell(*name),
11700 JSGlobalPropertyCell);
11701}
11702
11703
lrn@chromium.org303ada72010-10-27 09:33:13 +000011704MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011705 ASSERT(!HasFastProperties());
11706 int entry = property_dictionary()->FindEntry(name);
11707 if (entry == StringDictionary::kNotFound) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011708 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +000011709 Object* cell;
11710 { MaybeObject* maybe_cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011711 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011712 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
11713 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011714 PropertyDetails details(NONE, NORMAL);
11715 details = details.AsDeleted();
lrn@chromium.org303ada72010-10-27 09:33:13 +000011716 Object* dictionary;
11717 { MaybeObject* maybe_dictionary =
11718 property_dictionary()->Add(name, cell, details);
11719 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
11720 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011721 set_properties(StringDictionary::cast(dictionary));
11722 return cell;
11723 } else {
11724 Object* value = property_dictionary()->ValueAt(entry);
11725 ASSERT(value->IsJSGlobalPropertyCell());
11726 return value;
11727 }
11728}
11729
11730
lrn@chromium.org303ada72010-10-27 09:33:13 +000011731MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011732 SymbolKey key(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011733 return LookupKey(&key, s);
11734}
11735
11736
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011737// This class is used for looking up two character strings in the symbol table.
11738// If we don't have a hit we don't want to waste much time so we unroll the
11739// string hash calculation loop here for speed. Doesn't work if the two
11740// characters form a decimal integer, since such strings have a different hash
11741// algorithm.
11742class TwoCharHashTableKey : public HashTableKey {
11743 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011744 TwoCharHashTableKey(uint32_t c1, uint32_t c2, uint32_t seed)
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011745 : c1_(c1), c2_(c2) {
11746 // Char 1.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011747 uint32_t hash = seed;
11748 hash += c1;
11749 hash += hash << 10;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011750 hash ^= hash >> 6;
11751 // Char 2.
11752 hash += c2;
11753 hash += hash << 10;
11754 hash ^= hash >> 6;
11755 // GetHash.
11756 hash += hash << 3;
11757 hash ^= hash >> 11;
11758 hash += hash << 15;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011759 if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011760#ifdef DEBUG
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011761 StringHasher hasher(2, seed);
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011762 hasher.AddCharacter(c1);
11763 hasher.AddCharacter(c2);
11764 // If this assert fails then we failed to reproduce the two-character
11765 // version of the string hashing algorithm above. One reason could be
11766 // that we were passed two digits as characters, since the hash
11767 // algorithm is different in that case.
11768 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
11769#endif
11770 hash_ = hash;
11771 }
11772
11773 bool IsMatch(Object* o) {
11774 if (!o->IsString()) return false;
11775 String* other = String::cast(o);
11776 if (other->length() != 2) return false;
11777 if (other->Get(0) != c1_) return false;
11778 return other->Get(1) == c2_;
11779 }
11780
11781 uint32_t Hash() { return hash_; }
11782 uint32_t HashForObject(Object* key) {
11783 if (!key->IsString()) return 0;
11784 return String::cast(key)->Hash();
11785 }
11786
11787 Object* AsObject() {
11788 // The TwoCharHashTableKey is only used for looking in the symbol
11789 // table, not for adding to it.
11790 UNREACHABLE();
11791 return NULL;
11792 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011793
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011794 private:
11795 uint32_t c1_;
11796 uint32_t c2_;
11797 uint32_t hash_;
11798};
11799
11800
ager@chromium.org7c537e22008-10-16 08:43:32 +000011801bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
11802 SymbolKey key(string);
11803 int entry = FindEntry(&key);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011804 if (entry == kNotFound) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011805 return false;
11806 } else {
11807 String* result = String::cast(KeyAt(entry));
ager@chromium.org870a0b62008-11-04 11:43:05 +000011808 ASSERT(StringShape(result).IsSymbol());
ager@chromium.org7c537e22008-10-16 08:43:32 +000011809 *symbol = result;
11810 return true;
11811 }
11812}
11813
11814
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011815bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
11816 uint32_t c2,
11817 String** symbol) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011818 TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011819 int entry = FindEntry(&key);
11820 if (entry == kNotFound) {
11821 return false;
11822 } else {
11823 String* result = String::cast(KeyAt(entry));
11824 ASSERT(StringShape(result).IsSymbol());
11825 *symbol = result;
11826 return true;
11827 }
11828}
11829
11830
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011831MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str,
11832 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011833 Utf8SymbolKey key(str, GetHeap()->HashSeed());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011834 return LookupKey(&key, s);
11835}
11836
11837
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011838MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
11839 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011840 AsciiSymbolKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011841 return LookupKey(&key, s);
11842}
11843
11844
danno@chromium.org40cb8782011-05-25 07:58:50 +000011845MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
11846 int from,
11847 int length,
11848 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011849 SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
danno@chromium.org40cb8782011-05-25 07:58:50 +000011850 return LookupKey(&key, s);
11851}
11852
11853
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011854MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
11855 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011856 TwoByteSymbolKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011857 return LookupKey(&key, s);
11858}
11859
lrn@chromium.org303ada72010-10-27 09:33:13 +000011860MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011861 int entry = FindEntry(key);
11862
11863 // Symbol already in table.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011864 if (entry != kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011865 *s = KeyAt(entry);
11866 return this;
11867 }
11868
11869 // Adding new symbol. Grow table if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011870 Object* obj;
11871 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11872 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11873 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011874
11875 // Create symbol object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011876 Object* symbol;
11877 { MaybeObject* maybe_symbol = key->AsObject();
11878 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
11879 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011880
11881 // If the symbol table grew as part of EnsureCapacity, obj is not
11882 // the current symbol table and therefore we cannot use
11883 // SymbolTable::cast here.
11884 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
11885
11886 // Add the new symbol and return it along with the symbol table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011887 entry = table->FindInsertionEntry(key->Hash());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011888 table->set(EntryToIndex(entry), symbol);
11889 table->ElementAdded();
11890 *s = symbol;
11891 return table;
11892}
11893
11894
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011895Object* CompilationCacheTable::Lookup(String* src) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011896 StringKey key(src);
11897 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011898 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011899 return get(EntryToIndex(entry) + 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011900}
11901
11902
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011903Object* CompilationCacheTable::LookupEval(String* src,
11904 Context* context,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011905 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011906 int scope_position) {
11907 StringSharedKey key(src,
11908 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011909 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011910 scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011911 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011912 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.org381abbb2009-02-25 13:23:22 +000011913 return get(EntryToIndex(entry) + 1);
11914}
11915
11916
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011917Object* CompilationCacheTable::LookupRegExp(String* src,
11918 JSRegExp::Flags flags) {
11919 RegExpKey key(src, flags);
11920 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011921 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011922 return get(EntryToIndex(entry) + 1);
11923}
11924
11925
lrn@chromium.org303ada72010-10-27 09:33:13 +000011926MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011927 StringKey key(src);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011928 Object* obj;
11929 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11930 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11931 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011932
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011933 CompilationCacheTable* cache =
11934 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011935 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011936 cache->set(EntryToIndex(entry), src);
11937 cache->set(EntryToIndex(entry) + 1, value);
11938 cache->ElementAdded();
11939 return cache;
11940}
11941
11942
lrn@chromium.org303ada72010-10-27 09:33:13 +000011943MaybeObject* CompilationCacheTable::PutEval(String* src,
11944 Context* context,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011945 SharedFunctionInfo* value,
11946 int scope_position) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011947 StringSharedKey key(src,
11948 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011949 value->language_mode(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011950 scope_position);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011951 Object* obj;
11952 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11953 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11954 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000011955
11956 CompilationCacheTable* cache =
11957 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011958 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org381abbb2009-02-25 13:23:22 +000011959
lrn@chromium.org303ada72010-10-27 09:33:13 +000011960 Object* k;
11961 { MaybeObject* maybe_k = key.AsObject();
11962 if (!maybe_k->ToObject(&k)) return maybe_k;
11963 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000011964
11965 cache->set(EntryToIndex(entry), k);
11966 cache->set(EntryToIndex(entry) + 1, value);
11967 cache->ElementAdded();
11968 return cache;
11969}
11970
11971
lrn@chromium.org303ada72010-10-27 09:33:13 +000011972MaybeObject* CompilationCacheTable::PutRegExp(String* src,
11973 JSRegExp::Flags flags,
11974 FixedArray* value) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011975 RegExpKey key(src, flags);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011976 Object* obj;
11977 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11978 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11979 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011980
11981 CompilationCacheTable* cache =
11982 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011983 int entry = cache->FindInsertionEntry(key.Hash());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000011984 // We store the value in the key slot, and compare the search key
11985 // to the stored value with a custon IsMatch function during lookups.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011986 cache->set(EntryToIndex(entry), value);
11987 cache->set(EntryToIndex(entry) + 1, value);
11988 cache->ElementAdded();
11989 return cache;
11990}
11991
11992
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011993void CompilationCacheTable::Remove(Object* value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011994 Object* the_hole_value = GetHeap()->the_hole_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011995 for (int entry = 0, size = Capacity(); entry < size; entry++) {
11996 int entry_index = EntryToIndex(entry);
11997 int value_index = entry_index + 1;
11998 if (get(value_index) == value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011999 NoWriteBarrierSet(this, entry_index, the_hole_value);
12000 NoWriteBarrierSet(this, value_index, the_hole_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012001 ElementRemoved();
12002 }
12003 }
12004 return;
12005}
12006
12007
ager@chromium.org236ad962008-09-25 09:45:57 +000012008// SymbolsKey used for HashTable where key is array of symbols.
12009class SymbolsKey : public HashTableKey {
12010 public:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012011 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
ager@chromium.org236ad962008-09-25 09:45:57 +000012012
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012013 bool IsMatch(Object* symbols) {
12014 FixedArray* o = FixedArray::cast(symbols);
ager@chromium.org236ad962008-09-25 09:45:57 +000012015 int len = symbols_->length();
12016 if (o->length() != len) return false;
12017 for (int i = 0; i < len; i++) {
12018 if (o->get(i) != symbols_->get(i)) return false;
12019 }
12020 return true;
12021 }
12022
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012023 uint32_t Hash() { return HashForObject(symbols_); }
ager@chromium.org236ad962008-09-25 09:45:57 +000012024
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012025 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012026 FixedArray* symbols = FixedArray::cast(obj);
12027 int len = symbols->length();
12028 uint32_t hash = 0;
ager@chromium.org236ad962008-09-25 09:45:57 +000012029 for (int i = 0; i < len; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012030 hash ^= String::cast(symbols->get(i))->Hash();
ager@chromium.org236ad962008-09-25 09:45:57 +000012031 }
12032 return hash;
12033 }
12034
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012035 Object* AsObject() { return symbols_; }
ager@chromium.org236ad962008-09-25 09:45:57 +000012036
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012037 private:
ager@chromium.org236ad962008-09-25 09:45:57 +000012038 FixedArray* symbols_;
12039};
12040
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012041
ager@chromium.org236ad962008-09-25 09:45:57 +000012042Object* MapCache::Lookup(FixedArray* array) {
12043 SymbolsKey key(array);
12044 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012045 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012046 return get(EntryToIndex(entry) + 1);
ager@chromium.org236ad962008-09-25 09:45:57 +000012047}
12048
12049
lrn@chromium.org303ada72010-10-27 09:33:13 +000012050MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
ager@chromium.org236ad962008-09-25 09:45:57 +000012051 SymbolsKey key(array);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012052 Object* obj;
12053 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
12054 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12055 }
ager@chromium.org236ad962008-09-25 09:45:57 +000012056
12057 MapCache* cache = reinterpret_cast<MapCache*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012058 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org236ad962008-09-25 09:45:57 +000012059 cache->set(EntryToIndex(entry), array);
12060 cache->set(EntryToIndex(entry) + 1, value);
12061 cache->ElementAdded();
12062 return cache;
12063}
12064
12065
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012066template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012067MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
12068 Object* obj;
12069 { MaybeObject* maybe_obj =
12070 HashTable<Shape, Key>::Allocate(at_least_space_for);
12071 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012072 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000012073 // Initialize the next enumeration index.
12074 Dictionary<Shape, Key>::cast(obj)->
12075 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012076 return obj;
12077}
12078
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012079
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012080template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012081MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012082 Heap* heap = Dictionary<Shape, Key>::GetHeap();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012083 int length = HashTable<Shape, Key>::NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012084
12085 // Allocate and initialize iteration order array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012086 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012087 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012088 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12089 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012090 FixedArray* iteration_order = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012091 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012092 iteration_order->set(i, Smi::FromInt(i));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012093 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012094
12095 // Allocate array with enumeration order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012096 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012097 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12098 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099 FixedArray* enumeration_order = FixedArray::cast(obj);
12100
12101 // Fill the enumeration order array with property details.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012102 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012103 int pos = 0;
12104 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012105 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012106 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012107 }
12108 }
12109
12110 // Sort the arrays wrt. enumeration order.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012111 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012112
12113 // Overwrite the enumeration_order with the enumeration indices.
12114 for (int i = 0; i < length; i++) {
12115 int index = Smi::cast(iteration_order->get(i))->value();
12116 int enum_index = PropertyDetails::kInitialIndex + i;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012117 enumeration_order->set(index, Smi::FromInt(enum_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012118 }
12119
12120 // Update the dictionary with new indices.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012121 capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012122 pos = 0;
12123 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012124 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012125 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
12126 PropertyDetails details = DetailsAt(i);
12127 PropertyDetails new_details =
12128 PropertyDetails(details.attributes(), details.type(), enum_index);
12129 DetailsAtPut(i, new_details);
12130 }
12131 }
12132
12133 // Set the next enumeration index.
12134 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
12135 return this;
12136}
12137
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012138template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012139MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012140 // Check whether there are enough enumeration indices to add n elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012141 if (Shape::kIsEnumerable &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012142 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
12143 // If not, we generate new indices for the properties.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012144 Object* result;
12145 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12146 if (!maybe_result->ToObject(&result)) return maybe_result;
12147 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012148 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012149 return HashTable<Shape, Key>::EnsureCapacity(n, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012150}
12151
12152
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012153template<typename Shape, typename Key>
12154Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012155 JSReceiver::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012156 Heap* heap = Dictionary<Shape, Key>::GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012157 PropertyDetails details = DetailsAt(entry);
ager@chromium.orge2902be2009-06-08 12:21:35 +000012158 // Ignore attributes if forcing a deletion.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012159 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012160 return heap->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +000012161 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012162 SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012163 HashTable<Shape, Key>::ElementRemoved();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012164 return heap->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012165}
12166
12167
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012168template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000012169MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
12170 return HashTable<Shape, Key>::Shrink(key);
12171}
12172
12173
12174template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012175MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012176 int entry = this->FindEntry(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012177
12178 // If the entry is present set the value;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012179 if (entry != Dictionary<Shape, Key>::kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012180 ValueAtPut(entry, value);
12181 return this;
12182 }
12183
12184 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012185 Object* obj;
12186 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12187 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12188 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012189
lrn@chromium.org303ada72010-10-27 09:33:13 +000012190 Object* k;
12191 { MaybeObject* maybe_k = Shape::AsObject(key);
12192 if (!maybe_k->ToObject(&k)) return maybe_k;
12193 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012194 PropertyDetails details = PropertyDetails(NONE, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012195
12196 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12197 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012198}
12199
12200
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012201template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012202MaybeObject* Dictionary<Shape, Key>::Add(Key key,
12203 Object* value,
12204 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012205 // Valdate key is absent.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012206 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012207 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012208 Object* obj;
12209 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12210 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12211 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012212
12213 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12214 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012215}
12216
12217
12218// Add a key, value pair to the dictionary.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012219template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012220MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
12221 Object* value,
12222 PropertyDetails details,
12223 uint32_t hash) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012224 // Compute the key object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012225 Object* k;
12226 { MaybeObject* maybe_k = Shape::AsObject(key);
12227 if (!maybe_k->ToObject(&k)) return maybe_k;
12228 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012229
12230 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012231 // Insert element at empty or deleted entry
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012232 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012233 // Assign an enumeration index to the property and update
12234 // SetNextEnumerationIndex.
12235 int index = NextEnumerationIndex();
12236 details = PropertyDetails(details.attributes(), details.type(), index);
12237 SetNextEnumerationIndex(index + 1);
12238 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012239 SetEntry(entry, k, value, details);
12240 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
12241 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
12242 HashTable<Shape, Key>::ElementAdded();
12243 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012244}
12245
12246
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012247void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012248 // If the dictionary requires slow elements an element has already
12249 // been added at a high index.
12250 if (requires_slow_elements()) return;
12251 // Check if this index is high enough that we should require slow
12252 // elements.
12253 if (key > kRequiresSlowElementsLimit) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012254 set_requires_slow_elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012255 return;
12256 }
12257 // Update max key value.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012258 Object* max_index_object = get(kMaxNumberKeyIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012259 if (!max_index_object->IsSmi() || max_number_key() < key) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012260 FixedArray::set(kMaxNumberKeyIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012261 Smi::FromInt(key << kRequiresSlowElementsTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012262 }
12263}
12264
12265
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012266MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
12267 Object* value,
12268 PropertyDetails details) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269 UpdateMaxNumberKey(key);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012270 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012271 return Add(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012272}
12273
12274
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012275MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
12276 Object* value) {
12277 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
12278 return Add(key, value, PropertyDetails(NONE, NORMAL));
12279}
12280
12281
12282MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012283 UpdateMaxNumberKey(key);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012284 return AtPut(key, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012285}
12286
12287
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012288MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
12289 Object* value) {
12290 return AtPut(key, value);
12291}
12292
12293
12294Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
12295 Handle<SeededNumberDictionary> dictionary,
12296 uint32_t index,
12297 Handle<Object> value,
12298 PropertyDetails details) {
12299 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12300 dictionary->Set(index, *value, details),
12301 SeededNumberDictionary);
12302}
12303
12304
12305Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
12306 Handle<UnseededNumberDictionary> dictionary,
12307 uint32_t index,
12308 Handle<Object> value) {
12309 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12310 dictionary->Set(index, *value),
12311 UnseededNumberDictionary);
12312}
12313
12314
12315MaybeObject* SeededNumberDictionary::Set(uint32_t key,
12316 Object* value,
12317 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012318 int entry = FindEntry(key);
12319 if (entry == kNotFound) return AddNumberEntry(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012320 // Preserve enumeration index.
12321 details = PropertyDetails(details.attributes(),
12322 details.type(),
12323 DetailsAt(entry).index());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012324 MaybeObject* maybe_object_key = SeededNumberDictionaryShape::AsObject(key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012325 Object* object_key;
12326 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000012327 SetEntry(entry, object_key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012328 return this;
12329}
12330
12331
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012332MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
12333 Object* value) {
12334 int entry = FindEntry(key);
12335 if (entry == kNotFound) return AddNumberEntry(key, value);
12336 MaybeObject* maybe_object_key = UnseededNumberDictionaryShape::AsObject(key);
12337 Object* object_key;
12338 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
12339 SetEntry(entry, object_key, value);
12340 return this;
12341}
12342
12343
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012344
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012345template<typename Shape, typename Key>
12346int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
12347 PropertyAttributes filter) {
12348 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012349 int result = 0;
12350 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012351 Object* k = HashTable<Shape, Key>::KeyAt(i);
12352 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012353 PropertyDetails details = DetailsAt(i);
12354 if (details.IsDeleted()) continue;
12355 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012356 if ((attr & filter) == 0) result++;
12357 }
12358 }
12359 return result;
12360}
12361
12362
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012363template<typename Shape, typename Key>
12364int Dictionary<Shape, Key>::NumberOfEnumElements() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012365 return NumberOfElementsFilterAttributes(
12366 static_cast<PropertyAttributes>(DONT_ENUM));
12367}
12368
12369
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012370template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012371void Dictionary<Shape, Key>::CopyKeysTo(
12372 FixedArray* storage,
12373 PropertyAttributes filter,
12374 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012375 ASSERT(storage->length() >= NumberOfEnumElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012376 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012377 int index = 0;
12378 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012379 Object* k = HashTable<Shape, Key>::KeyAt(i);
12380 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012381 PropertyDetails details = DetailsAt(i);
12382 if (details.IsDeleted()) continue;
12383 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012384 if ((attr & filter) == 0) storage->set(index++, k);
12385 }
12386 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012387 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12388 storage->SortPairs(storage, index);
12389 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012390 ASSERT(storage->length() >= index);
12391}
12392
12393
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012394void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
12395 FixedArray* sort_array) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012396 ASSERT(storage->length() >= NumberOfEnumElements());
12397 int capacity = Capacity();
12398 int index = 0;
12399 for (int i = 0; i < capacity; i++) {
12400 Object* k = KeyAt(i);
12401 if (IsKey(k)) {
12402 PropertyDetails details = DetailsAt(i);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012403 if (details.IsDeleted() || details.IsDontEnum()) continue;
12404 storage->set(index, k);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012405 sort_array->set(index, Smi::FromInt(details.index()));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012406 index++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012407 }
12408 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012409 storage->SortPairs(sort_array, sort_array->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012410 ASSERT(storage->length() >= index);
12411}
12412
12413
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012414template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012415void Dictionary<Shape, Key>::CopyKeysTo(
12416 FixedArray* storage,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012417 int index,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012418 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012419 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
12420 static_cast<PropertyAttributes>(NONE)));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012421 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012422 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012423 Object* k = HashTable<Shape, Key>::KeyAt(i);
12424 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012425 PropertyDetails details = DetailsAt(i);
12426 if (details.IsDeleted()) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012427 storage->set(index++, k);
12428 }
12429 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012430 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12431 storage->SortPairs(storage, index);
12432 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012433 ASSERT(storage->length() >= index);
12434}
12435
12436
12437// Backwards lookup (slow).
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012438template<typename Shape, typename Key>
12439Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
12440 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012441 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012442 Object* k = HashTable<Shape, Key>::KeyAt(i);
12443 if (Dictionary<Shape, Key>::IsKey(k)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012444 Object* e = ValueAt(i);
12445 if (e->IsJSGlobalPropertyCell()) {
12446 e = JSGlobalPropertyCell::cast(e)->value();
12447 }
12448 if (e == value) return k;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012449 }
12450 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012451 Heap* heap = Dictionary<Shape, Key>::GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012452 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012453}
12454
12455
lrn@chromium.org303ada72010-10-27 09:33:13 +000012456MaybeObject* StringDictionary::TransformPropertiesToFastFor(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012457 JSObject* obj, int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012458 // Make sure we preserve dictionary representation if there are too many
12459 // descriptors.
12460 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
12461
12462 // Figure out if it is necessary to generate new enumeration indices.
12463 int max_enumeration_index =
12464 NextEnumerationIndex() +
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012465 (DescriptorArray::kMaxNumberOfDescriptors -
12466 NumberOfElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012467 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012468 Object* result;
12469 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12470 if (!maybe_result->ToObject(&result)) return maybe_result;
12471 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012472 }
12473
12474 int instance_descriptor_length = 0;
12475 int number_of_fields = 0;
12476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012477 Heap* heap = GetHeap();
12478
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012479 // Compute the length of the instance descriptor.
12480 int capacity = Capacity();
12481 for (int i = 0; i < capacity; i++) {
12482 Object* k = KeyAt(i);
12483 if (IsKey(k)) {
12484 Object* value = ValueAt(i);
12485 PropertyType type = DetailsAt(i).type();
12486 ASSERT(type != FIELD);
12487 instance_descriptor_length++;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000012488 if (type == NORMAL &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012489 (!value->IsJSFunction() || heap->InNewSpace(value))) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000012490 number_of_fields += 1;
12491 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012492 }
12493 }
12494
12495 // Allocate the instance descriptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012496 DescriptorArray* descriptors;
12497 { MaybeObject* maybe_descriptors =
lrn@chromium.org303ada72010-10-27 09:33:13 +000012498 DescriptorArray::Allocate(instance_descriptor_length);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012499 if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) {
12500 return maybe_descriptors;
lrn@chromium.org303ada72010-10-27 09:33:13 +000012501 }
12502 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012503
12504 DescriptorArray::WhitenessWitness witness(descriptors);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012505
ager@chromium.org32912102009-01-16 10:38:43 +000012506 int inobject_props = obj->map()->inobject_properties();
12507 int number_of_allocated_fields =
12508 number_of_fields + unused_property_fields - inobject_props;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000012509 if (number_of_allocated_fields < 0) {
12510 // There is enough inobject space for all fields (including unused).
12511 number_of_allocated_fields = 0;
12512 unused_property_fields = inobject_props - number_of_fields;
12513 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012514
12515 // Allocate the fixed array for the fields.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012516 Object* fields;
12517 { MaybeObject* maybe_fields =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012518 heap->AllocateFixedArray(number_of_allocated_fields);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012519 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
12520 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012521
12522 // Fill in the instance descriptor and the fields.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012523 int next_descriptor = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012524 int current_offset = 0;
12525 for (int i = 0; i < capacity; i++) {
12526 Object* k = KeyAt(i);
12527 if (IsKey(k)) {
12528 Object* value = ValueAt(i);
12529 // Ensure the key is a symbol before writing into the instance descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012530 Object* key;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012531 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012532 if (!maybe_key->ToObject(&key)) return maybe_key;
12533 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012534 PropertyDetails details = DetailsAt(i);
12535 PropertyType type = details.type();
ager@chromium.org32912102009-01-16 10:38:43 +000012536
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012537 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012538 ConstantFunctionDescriptor d(String::cast(key),
12539 JSFunction::cast(value),
12540 details.attributes(),
12541 details.index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012542 descriptors->Set(next_descriptor++, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012543 } else if (type == NORMAL) {
ager@chromium.org32912102009-01-16 10:38:43 +000012544 if (current_offset < inobject_props) {
12545 obj->InObjectPropertyAtPut(current_offset,
12546 value,
12547 UPDATE_WRITE_BARRIER);
12548 } else {
12549 int offset = current_offset - inobject_props;
12550 FixedArray::cast(fields)->set(offset, value);
12551 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012552 FieldDescriptor d(String::cast(key),
12553 current_offset++,
12554 details.attributes(),
12555 details.index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012556 descriptors->Set(next_descriptor++, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012557 } else if (type == CALLBACKS) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +000012558 if (value->IsAccessorPair()) {
12559 MaybeObject* maybe_copy =
12560 AccessorPair::cast(value)->CopyWithoutTransitions();
12561 if (!maybe_copy->To(&value)) return maybe_copy;
12562 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012563 CallbacksDescriptor d(String::cast(key),
12564 value,
12565 details.attributes(),
12566 details.index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012567 descriptors->Set(next_descriptor++, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012568 } else {
12569 UNREACHABLE();
12570 }
12571 }
12572 }
12573 ASSERT(current_offset == number_of_fields);
12574
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012575 descriptors->Sort(witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012576 // Allocate new map.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012577 Object* new_map;
12578 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
12579 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
12580 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012581
12582 // Transform the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012583 obj->set_map(Map::cast(new_map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012584 obj->map()->set_instance_descriptors(descriptors);
12585 obj->map()->set_unused_property_fields(unused_property_fields);
12586
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012587 obj->set_properties(FixedArray::cast(fields));
12588 ASSERT(obj->IsJSObject());
12589
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012590 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
ager@chromium.org32912102009-01-16 10:38:43 +000012591 // Check that it really works.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012592 ASSERT(obj->HasFastProperties());
ager@chromium.org32912102009-01-16 10:38:43 +000012593
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012594 return obj;
12595}
12596
12597
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012598bool ObjectHashSet::Contains(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012599 ASSERT(IsKey(key));
12600
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012601 // If the object does not have an identity hash, it was never used as a key.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012602 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12603 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
12604 }
12605 return (FindEntry(key) != kNotFound);
12606}
12607
12608
12609MaybeObject* ObjectHashSet::Add(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012610 ASSERT(IsKey(key));
12611
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012612 // Make sure the key object has an identity hash code.
12613 int hash;
12614 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12615 if (maybe_hash->IsFailure()) return maybe_hash;
12616 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12617 }
12618 int entry = FindEntry(key);
12619
12620 // Check whether key is already present.
12621 if (entry != kNotFound) return this;
12622
12623 // Check whether the hash set should be extended and add entry.
12624 Object* obj;
12625 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12626 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12627 }
12628 ObjectHashSet* table = ObjectHashSet::cast(obj);
12629 entry = table->FindInsertionEntry(hash);
12630 table->set(EntryToIndex(entry), key);
12631 table->ElementAdded();
12632 return table;
12633}
12634
12635
12636MaybeObject* ObjectHashSet::Remove(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012637 ASSERT(IsKey(key));
12638
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012639 // If the object does not have an identity hash, it was never used as a key.
12640 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12641 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
12642 }
12643 int entry = FindEntry(key);
12644
12645 // Check whether key is actually present.
12646 if (entry == kNotFound) return this;
12647
12648 // Remove entry and try to shrink this hash set.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012649 set_the_hole(EntryToIndex(entry));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012650 ElementRemoved();
12651 return Shrink(key);
12652}
12653
12654
12655Object* ObjectHashTable::Lookup(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012656 ASSERT(IsKey(key));
12657
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012658 // If the object does not have an identity hash, it was never used as a key.
12659 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12660 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
12661 return GetHeap()->undefined_value();
12662 }
12663 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012664 int entry = FindEntry(key);
12665 if (entry == kNotFound) return GetHeap()->undefined_value();
12666 return get(EntryToIndex(entry) + 1);
12667}
12668
12669
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012670MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012671 ASSERT(IsKey(key));
12672
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012673 // Make sure the key object has an identity hash code.
12674 int hash;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012675 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012676 if (maybe_hash->IsFailure()) return maybe_hash;
12677 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12678 }
12679 int entry = FindEntry(key);
12680
12681 // Check whether to perform removal operation.
12682 if (value->IsUndefined()) {
12683 if (entry == kNotFound) return this;
12684 RemoveEntry(entry);
12685 return Shrink(key);
12686 }
12687
12688 // Key is already in table, just overwrite value.
12689 if (entry != kNotFound) {
12690 set(EntryToIndex(entry) + 1, value);
12691 return this;
12692 }
12693
12694 // Check whether the hash table should be extended.
12695 Object* obj;
12696 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12697 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12698 }
12699 ObjectHashTable* table = ObjectHashTable::cast(obj);
12700 table->AddEntry(table->FindInsertionEntry(hash), key, value);
12701 return table;
12702}
12703
12704
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012705void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012706 set(EntryToIndex(entry), key);
12707 set(EntryToIndex(entry) + 1, value);
12708 ElementAdded();
12709}
12710
12711
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012712void ObjectHashTable::RemoveEntry(int entry) {
12713 set_the_hole(EntryToIndex(entry));
12714 set_the_hole(EntryToIndex(entry) + 1);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012715 ElementRemoved();
12716}
12717
12718
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012719#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012720// Check if there is a break point at this code position.
12721bool DebugInfo::HasBreakPoint(int code_position) {
12722 // Get the break point info object for this code position.
12723 Object* break_point_info = GetBreakPointInfo(code_position);
12724
12725 // If there is no break point info object or no break points in the break
12726 // point info object there is no break point at this code position.
12727 if (break_point_info->IsUndefined()) return false;
12728 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
12729}
12730
12731
12732// Get the break point info object for this code position.
12733Object* DebugInfo::GetBreakPointInfo(int code_position) {
12734 // Find the index of the break point info object for this code position.
12735 int index = GetBreakPointInfoIndex(code_position);
12736
12737 // Return the break point info object if any.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012738 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012739 return BreakPointInfo::cast(break_points()->get(index));
12740}
12741
12742
12743// Clear a break point at the specified code position.
12744void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
12745 int code_position,
12746 Handle<Object> break_point_object) {
12747 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12748 if (break_point_info->IsUndefined()) return;
12749 BreakPointInfo::ClearBreakPoint(
12750 Handle<BreakPointInfo>::cast(break_point_info),
12751 break_point_object);
12752}
12753
12754
12755void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
12756 int code_position,
12757 int source_position,
12758 int statement_position,
12759 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012760 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012761 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12762 if (!break_point_info->IsUndefined()) {
12763 BreakPointInfo::SetBreakPoint(
12764 Handle<BreakPointInfo>::cast(break_point_info),
12765 break_point_object);
12766 return;
12767 }
12768
12769 // Adding a new break point for a code position which did not have any
12770 // break points before. Try to find a free slot.
12771 int index = kNoBreakPointInfo;
12772 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12773 if (debug_info->break_points()->get(i)->IsUndefined()) {
12774 index = i;
12775 break;
12776 }
12777 }
12778 if (index == kNoBreakPointInfo) {
12779 // No free slot - extend break point info array.
12780 Handle<FixedArray> old_break_points =
12781 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012782 Handle<FixedArray> new_break_points =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012783 isolate->factory()->NewFixedArray(
12784 old_break_points->length() +
12785 Debug::kEstimatedNofBreakPointsInFunction);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000012786
12787 debug_info->set_break_points(*new_break_points);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012788 for (int i = 0; i < old_break_points->length(); i++) {
12789 new_break_points->set(i, old_break_points->get(i));
12790 }
12791 index = old_break_points->length();
12792 }
12793 ASSERT(index != kNoBreakPointInfo);
12794
12795 // Allocate new BreakPointInfo object and set the break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012796 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
12797 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012798 new_break_point_info->set_code_position(Smi::FromInt(code_position));
12799 new_break_point_info->set_source_position(Smi::FromInt(source_position));
12800 new_break_point_info->
12801 set_statement_position(Smi::FromInt(statement_position));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012802 new_break_point_info->set_break_point_objects(
12803 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012804 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
12805 debug_info->break_points()->set(index, *new_break_point_info);
12806}
12807
12808
12809// Get the break point objects for a code position.
12810Object* DebugInfo::GetBreakPointObjects(int code_position) {
12811 Object* break_point_info = GetBreakPointInfo(code_position);
12812 if (break_point_info->IsUndefined()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012813 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012814 }
12815 return BreakPointInfo::cast(break_point_info)->break_point_objects();
12816}
12817
12818
12819// Get the total number of break points.
12820int DebugInfo::GetBreakPointCount() {
12821 if (break_points()->IsUndefined()) return 0;
12822 int count = 0;
12823 for (int i = 0; i < break_points()->length(); i++) {
12824 if (!break_points()->get(i)->IsUndefined()) {
12825 BreakPointInfo* break_point_info =
12826 BreakPointInfo::cast(break_points()->get(i));
12827 count += break_point_info->GetBreakPointCount();
12828 }
12829 }
12830 return count;
12831}
12832
12833
12834Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
12835 Handle<Object> break_point_object) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012836 Heap* heap = debug_info->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012837 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012838 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12839 if (!debug_info->break_points()->get(i)->IsUndefined()) {
12840 Handle<BreakPointInfo> break_point_info =
12841 Handle<BreakPointInfo>(BreakPointInfo::cast(
12842 debug_info->break_points()->get(i)));
12843 if (BreakPointInfo::HasBreakPointObject(break_point_info,
12844 break_point_object)) {
12845 return *break_point_info;
12846 }
12847 }
12848 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012849 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012850}
12851
12852
12853// Find the index of the break point info object for the specified code
12854// position.
12855int DebugInfo::GetBreakPointInfoIndex(int code_position) {
12856 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
12857 for (int i = 0; i < break_points()->length(); i++) {
12858 if (!break_points()->get(i)->IsUndefined()) {
12859 BreakPointInfo* break_point_info =
12860 BreakPointInfo::cast(break_points()->get(i));
12861 if (break_point_info->code_position()->value() == code_position) {
12862 return i;
12863 }
12864 }
12865 }
12866 return kNoBreakPointInfo;
12867}
12868
12869
12870// Remove the specified break point object.
12871void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
12872 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012873 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012874 // If there are no break points just ignore.
12875 if (break_point_info->break_point_objects()->IsUndefined()) return;
12876 // If there is a single break point clear it if it is the same.
12877 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12878 if (break_point_info->break_point_objects() == *break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012879 break_point_info->set_break_point_objects(
12880 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012881 }
12882 return;
12883 }
12884 // If there are multiple break points shrink the array
12885 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
12886 Handle<FixedArray> old_array =
12887 Handle<FixedArray>(
12888 FixedArray::cast(break_point_info->break_point_objects()));
12889 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012890 isolate->factory()->NewFixedArray(old_array->length() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012891 int found_count = 0;
12892 for (int i = 0; i < old_array->length(); i++) {
12893 if (old_array->get(i) == *break_point_object) {
12894 ASSERT(found_count == 0);
12895 found_count++;
12896 } else {
12897 new_array->set(i - found_count, old_array->get(i));
12898 }
12899 }
12900 // If the break point was found in the list change it.
12901 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
12902}
12903
12904
12905// Add the specified break point object.
12906void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
12907 Handle<Object> break_point_object) {
12908 // If there was no break point objects before just set it.
12909 if (break_point_info->break_point_objects()->IsUndefined()) {
12910 break_point_info->set_break_point_objects(*break_point_object);
12911 return;
12912 }
12913 // If the break point object is the same as before just ignore.
12914 if (break_point_info->break_point_objects() == *break_point_object) return;
12915 // If there was one break point object before replace with array.
12916 if (!break_point_info->break_point_objects()->IsFixedArray()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012917 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012918 array->set(0, break_point_info->break_point_objects());
12919 array->set(1, *break_point_object);
12920 break_point_info->set_break_point_objects(*array);
12921 return;
12922 }
12923 // If there was more than one break point before extend array.
12924 Handle<FixedArray> old_array =
12925 Handle<FixedArray>(
12926 FixedArray::cast(break_point_info->break_point_objects()));
12927 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012928 FACTORY->NewFixedArray(old_array->length() + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012929 for (int i = 0; i < old_array->length(); i++) {
12930 // If the break point was there before just ignore.
12931 if (old_array->get(i) == *break_point_object) return;
12932 new_array->set(i, old_array->get(i));
12933 }
12934 // Add the new break point.
12935 new_array->set(old_array->length(), *break_point_object);
12936 break_point_info->set_break_point_objects(*new_array);
12937}
12938
12939
12940bool BreakPointInfo::HasBreakPointObject(
12941 Handle<BreakPointInfo> break_point_info,
12942 Handle<Object> break_point_object) {
12943 // No break point.
12944 if (break_point_info->break_point_objects()->IsUndefined()) return false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012945 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012946 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12947 return break_point_info->break_point_objects() == *break_point_object;
12948 }
12949 // Multiple break points.
12950 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
12951 for (int i = 0; i < array->length(); i++) {
12952 if (array->get(i) == *break_point_object) {
12953 return true;
12954 }
12955 }
12956 return false;
12957}
12958
12959
12960// Get the number of break points.
12961int BreakPointInfo::GetBreakPointCount() {
12962 // No break point.
12963 if (break_point_objects()->IsUndefined()) return 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012964 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012965 if (!break_point_objects()->IsFixedArray()) return 1;
12966 // Multiple break points.
12967 return FixedArray::cast(break_point_objects())->length();
12968}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000012969#endif // ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012970
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012971
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012972} } // namespace v8::internal