blob: 4f99d590c89b85061307e6c761eda1ebf6dd21be [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"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000036#include "date.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000037#include "elements.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "execution.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000039#include "full-codegen.h"
40#include "hydrogen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "objects-inl.h"
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000042#include "objects-visiting.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000043#include "objects-visiting-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "macro-assembler.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "mark-compact.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000046#include "safepoint-table.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "string-stream.h"
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000048#include "utils.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000049#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050
mads.s.ager31e71382008-08-13 09:32:07 +000051#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052#include "disasm.h"
mads.s.ager31e71382008-08-13 09:32:07 +000053#include "disassembler.h"
54#endif
55
kasperl@chromium.org71affb52009-05-26 05:44:31 +000056namespace v8 {
57namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000059
lrn@chromium.org303ada72010-10-27 09:33:13 +000060MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
61 Object* value) {
62 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000063 { MaybeObject* maybe_result =
64 constructor->GetHeap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +000065 if (!maybe_result->ToObject(&result)) return maybe_result;
66 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067 JSValue::cast(result)->set_value(value);
68 return result;
69}
70
71
lrn@chromium.org303ada72010-10-27 09:33:13 +000072MaybeObject* Object::ToObject(Context* global_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073 if (IsNumber()) {
74 return CreateJSValue(global_context->number_function(), this);
75 } else if (IsBoolean()) {
76 return CreateJSValue(global_context->boolean_function(), this);
77 } else if (IsString()) {
78 return CreateJSValue(global_context->string_function(), this);
79 }
80 ASSERT(IsJSObject());
81 return this;
82}
83
84
lrn@chromium.org303ada72010-10-27 09:33:13 +000085MaybeObject* Object::ToObject() {
lrn@chromium.org34e60782011-09-15 07:25:40 +000086 if (IsJSReceiver()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087 return this;
88 } else if (IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000089 Isolate* isolate = Isolate::Current();
90 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091 return CreateJSValue(global_context->number_function(), this);
92 } else if (IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000093 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
94 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095 return CreateJSValue(global_context->boolean_function(), this);
96 } else if (IsString()) {
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->string_function(), this);
100 }
101
102 // Throw a type error.
103 return Failure::InternalError();
104}
105
106
107Object* Object::ToBoolean() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000108 if (IsTrue()) return this;
109 if (IsFalse()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 if (IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000113 HeapObject* heap_object = HeapObject::cast(this);
114 if (heap_object->IsUndefined() || heap_object->IsNull()) {
115 return heap_object->GetHeap()->false_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000116 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117 // Undetectable object is false
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000118 if (heap_object->IsUndetectableObject()) {
119 return heap_object->GetHeap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000121 if (heap_object->IsString()) {
122 return heap_object->GetHeap()->ToBoolean(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000123 String::cast(this)->length() != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000125 if (heap_object->IsHeapNumber()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126 return HeapNumber::cast(this)->HeapNumberToBoolean();
127 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000128 return heap_object->GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000129}
130
131
132void Object::Lookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000133 Object* holder = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000134 if (IsJSReceiver()) {
135 holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000136 } else {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000137 Context* global_context = Isolate::Current()->context()->global_context();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000138 if (IsNumber()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000139 holder = global_context->number_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000140 } else if (IsString()) {
141 holder = global_context->string_function()->instance_prototype();
142 } else if (IsBoolean()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000143 holder = global_context->boolean_function()->instance_prototype();
144 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000145 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000146 ASSERT(holder != NULL); // Cannot handle null or undefined.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000147 JSReceiver::cast(holder)->Lookup(name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148}
149
150
lrn@chromium.org303ada72010-10-27 09:33:13 +0000151MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
152 String* name,
153 PropertyAttributes* attributes) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000154 LookupResult result(name->GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155 Lookup(name, &result);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000157 ASSERT(*attributes <= ABSENT);
158 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159}
160
161
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000162MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
163 Object* structure,
164 String* name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000165 Isolate* isolate = name->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000167 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000168 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000169 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000170 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000171 reinterpret_cast<AccessorDescriptor*>(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000172 Foreign::cast(structure)->foreign_address());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000173 MaybeObject* value = (callback->getter)(receiver, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000174 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000175 return value;
176 }
177
178 // api style callbacks.
179 if (structure->IsAccessorInfo()) {
180 AccessorInfo* data = AccessorInfo::cast(structure);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000181 if (!data->IsCompatibleReceiver(receiver)) {
182 Handle<Object> name_handle(name);
183 Handle<Object> receiver_handle(receiver);
184 Handle<Object> args[2] = { name_handle, receiver_handle };
185 Handle<Object> error =
186 isolate->factory()->NewTypeError("incompatible_method_receiver",
187 HandleVector(args,
188 ARRAY_SIZE(args)));
189 return isolate->Throw(*error);
190 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000191 Object* fun_obj = data->getter();
192 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000193 HandleScope scope(isolate);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000194 JSObject* self = JSObject::cast(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000195 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000196 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000197 CustomArguments args(isolate, data->data(), self, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000198 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000199 v8::Handle<v8::Value> result;
200 {
201 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000202 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203 result = call_fun(v8::Utils::ToLocal(key), info);
204 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000205 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
206 if (result.IsEmpty()) {
207 return isolate->heap()->undefined_value();
208 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000209 return *v8::Utils::OpenHandle(*result);
210 }
211
212 // __defineGetter__ callback
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000213 if (structure->IsAccessorPair()) {
214 Object* getter = AccessorPair::cast(structure)->getter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000215 if (getter->IsSpecFunction()) {
216 // TODO(rossberg): nicer would be to cast to some JSCallable here...
217 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218 }
219 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000220 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000221 }
222
223 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000224 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225}
226
227
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000228MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
229 String* name_raw) {
230 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000231 HandleScope scope(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000232 Handle<Object> receiver(receiver_raw);
233 Handle<Object> name(name_raw);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000234
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000235 Handle<Object> args[] = { receiver, name };
236 Handle<Object> result = CallTrap(
237 "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000238 if (isolate->has_pending_exception()) return Failure::Exception();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000239
240 return *result;
241}
242
243
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000244Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
245 Isolate* isolate = object->IsHeapObject()
246 ? Handle<HeapObject>::cast(object)->GetIsolate()
247 : Isolate::Current();
248 CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
249}
250
251
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000252MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
253 uint32_t index) {
254 String* name;
255 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
256 if (!maybe->To<String>(&name)) return maybe;
257 return GetPropertyWithHandler(receiver, name);
258}
259
260
verwaest@chromium.org37141392012-05-31 13:27:02 +0000261MaybeObject* JSProxy::SetElementWithHandler(JSReceiver* receiver,
262 uint32_t index,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000263 Object* value,
264 StrictModeFlag strict_mode) {
265 String* name;
266 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
267 if (!maybe->To<String>(&name)) return maybe;
verwaest@chromium.org37141392012-05-31 13:27:02 +0000268 return SetPropertyWithHandler(receiver, name, value, NONE, strict_mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000269}
270
271
272bool JSProxy::HasElementWithHandler(uint32_t index) {
273 String* name;
274 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
275 if (!maybe->To<String>(&name)) return maybe;
276 return HasPropertyWithHandler(name);
277}
278
279
lrn@chromium.org303ada72010-10-27 09:33:13 +0000280MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000281 JSReceiver* getter) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000282 HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000283 Handle<JSReceiver> fun(getter);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000284 Handle<Object> self(receiver);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000285#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 Debug* debug = fun->GetHeap()->isolate()->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000287 // Handle stepping into a getter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000288 // TODO(rossberg): should this apply to getters that are function proxies?
289 if (debug->StepInActive() && fun->IsJSFunction()) {
290 debug->HandleStepIn(
291 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000292 }
293#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000294
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295 bool has_pending_exception;
296 Handle<Object> result =
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000297 Execution::Call(fun, self, 0, NULL, &has_pending_exception, true);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000298 // Check for pending exception and return the result.
299 if (has_pending_exception) return Failure::Exception();
300 return *result;
301}
302
303
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304// Only deal with CALLBACKS and INTERCEPTOR
lrn@chromium.org303ada72010-10-27 09:33:13 +0000305MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
ager@chromium.org8bb60582008-12-11 12:02:20 +0000306 Object* receiver,
307 LookupResult* result,
308 String* name,
309 PropertyAttributes* attributes) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000310 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000311 switch (result->type()) {
312 case CALLBACKS: {
313 // Only allow API accessors.
314 Object* obj = result->GetCallbackObject();
315 if (obj->IsAccessorInfo()) {
316 AccessorInfo* info = AccessorInfo::cast(obj);
317 if (info->all_can_read()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000318 *attributes = result->GetAttributes();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000319 return result->holder()->GetPropertyWithCallback(
320 receiver, result->GetCallbackObject(), name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000321 }
322 }
323 break;
324 }
325 case NORMAL:
326 case FIELD:
327 case CONSTANT_FUNCTION: {
328 // Search ALL_CAN_READ accessors in prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000329 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000331 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000332 return GetPropertyWithFailedAccessCheck(receiver,
333 &r,
334 name,
335 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336 }
337 break;
338 }
339 case INTERCEPTOR: {
340 // If the object has an interceptor, try real named properties.
341 // No access check in GetPropertyAttributeWithInterceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000342 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 result->holder()->LookupRealNamedProperty(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000344 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000345 return GetPropertyWithFailedAccessCheck(receiver,
346 &r,
347 name,
348 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349 }
ager@chromium.org9ed6c322010-02-19 12:24:05 +0000350 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000352 default:
353 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354 }
355 }
356
ager@chromium.org8bb60582008-12-11 12:02:20 +0000357 // No accessible property found.
358 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000359 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
361 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362}
363
364
ager@chromium.org870a0b62008-11-04 11:43:05 +0000365PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
366 Object* receiver,
367 LookupResult* result,
368 String* name,
369 bool continue_search) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000370 if (result->IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000371 switch (result->type()) {
372 case CALLBACKS: {
373 // Only allow API accessors.
374 Object* obj = result->GetCallbackObject();
375 if (obj->IsAccessorInfo()) {
376 AccessorInfo* info = AccessorInfo::cast(obj);
377 if (info->all_can_read()) {
378 return result->GetAttributes();
379 }
380 }
381 break;
382 }
383
384 case NORMAL:
385 case FIELD:
386 case CONSTANT_FUNCTION: {
387 if (!continue_search) break;
388 // Search ALL_CAN_READ accessors in prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000389 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000390 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000391 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000392 return GetPropertyAttributeWithFailedAccessCheck(receiver,
393 &r,
394 name,
395 continue_search);
396 }
397 break;
398 }
399
400 case INTERCEPTOR: {
401 // If the object has an interceptor, try real named properties.
402 // No access check in GetPropertyAttributeWithInterceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000403 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000404 if (continue_search) {
405 result->holder()->LookupRealNamedProperty(name, &r);
406 } else {
407 result->holder()->LocalLookupRealNamedProperty(name, &r);
408 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000409 if (!r.IsFound()) break;
410 return GetPropertyAttributeWithFailedAccessCheck(receiver,
411 &r,
412 name,
413 continue_search);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000414 }
415
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000416 case HANDLER:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000417 case TRANSITION:
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000418 case NONEXISTENT:
ager@chromium.org5c838252010-02-19 08:53:10 +0000419 UNREACHABLE();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000420 }
421 }
422
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000423 GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000424 return ABSENT;
425}
426
427
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000428Object* JSObject::GetNormalizedProperty(LookupResult* result) {
429 ASSERT(!HasFastProperties());
430 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
431 if (IsGlobalObject()) {
432 value = JSGlobalPropertyCell::cast(value)->value();
433 }
434 ASSERT(!value->IsJSGlobalPropertyCell());
435 return value;
436}
437
438
439Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
440 ASSERT(!HasFastProperties());
441 if (IsGlobalObject()) {
442 JSGlobalPropertyCell* cell =
443 JSGlobalPropertyCell::cast(
444 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
445 cell->set_value(value);
446 } else {
447 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
448 }
449 return value;
450}
451
452
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000453Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
454 Handle<String> key,
455 Handle<Object> value,
456 PropertyDetails details) {
457 CALL_HEAP_FUNCTION(object->GetIsolate(),
458 object->SetNormalizedProperty(*key, *value, details),
459 Object);
460}
461
462
lrn@chromium.org303ada72010-10-27 09:33:13 +0000463MaybeObject* JSObject::SetNormalizedProperty(String* name,
464 Object* value,
465 PropertyDetails details) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000466 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000467 int entry = property_dictionary()->FindEntry(name);
468 if (entry == StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000469 Object* store_value = value;
470 if (IsGlobalObject()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000471 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000472 MaybeObject* maybe_store_value =
473 heap->AllocateJSGlobalPropertyCell(value);
474 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000475 }
lrn@chromium.org303ada72010-10-27 09:33:13 +0000476 Object* dict;
477 { MaybeObject* maybe_dict =
478 property_dictionary()->Add(name, store_value, details);
479 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
480 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000481 set_properties(StringDictionary::cast(dict));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000482 return value;
483 }
484 // Preserve enumeration index.
485 details = PropertyDetails(details.attributes(),
486 details.type(),
487 property_dictionary()->DetailsAt(entry).index());
488 if (IsGlobalObject()) {
489 JSGlobalPropertyCell* cell =
490 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
491 cell->set_value(value);
492 // Please note we have to update the property details.
493 property_dictionary()->DetailsAtPut(entry, details);
494 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000495 property_dictionary()->SetEntry(entry, name, value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000496 }
497 return value;
498}
499
500
lrn@chromium.org303ada72010-10-27 09:33:13 +0000501MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000502 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000503 StringDictionary* dictionary = property_dictionary();
504 int entry = dictionary->FindEntry(name);
505 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000506 // If we have a global object set the cell to the hole.
507 if (IsGlobalObject()) {
508 PropertyDetails details = dictionary->DetailsAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000509 if (details.IsDontDelete()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000510 if (mode != FORCE_DELETION) return GetHeap()->false_value();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000511 // When forced to delete global properties, we have to make a
512 // map change to invalidate any ICs that think they can load
513 // from the DontDelete cell without checking if it contains
514 // the hole value.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000515 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000516 MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
517 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
518
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000519 set_map(new_map);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000520 }
521 JSGlobalPropertyCell* cell =
522 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000523 cell->set_value(cell->GetHeap()->the_hole_value());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000524 dictionary->DetailsAtPut(entry, details.AsDeleted());
525 } else {
ager@chromium.org04921a82011-06-27 13:21:41 +0000526 Object* deleted = dictionary->DeleteProperty(entry, mode);
527 if (deleted == GetHeap()->true_value()) {
528 FixedArray* new_properties = NULL;
529 MaybeObject* maybe_properties = dictionary->Shrink(name);
530 if (!maybe_properties->To(&new_properties)) {
531 return maybe_properties;
532 }
533 set_properties(new_properties);
534 }
535 return deleted;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000536 }
537 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000538 return GetHeap()->true_value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000539}
540
541
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000542bool JSObject::IsDirty() {
543 Object* cons_obj = map()->constructor();
544 if (!cons_obj->IsJSFunction())
545 return true;
546 JSFunction* fun = JSFunction::cast(cons_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000547 if (!fun->shared()->IsApiFunction())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000548 return true;
549 // If the object is fully fast case and has the same map it was
550 // created with then no changes can have been made to it.
551 return map() != fun->initial_map()
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000552 || !HasFastObjectElements()
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000553 || !HasFastProperties();
554}
555
556
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000557Handle<Object> Object::GetProperty(Handle<Object> object,
558 Handle<Object> receiver,
559 LookupResult* result,
560 Handle<String> key,
561 PropertyAttributes* attributes) {
562 Isolate* isolate = object->IsHeapObject()
563 ? Handle<HeapObject>::cast(object)->GetIsolate()
564 : Isolate::Current();
565 CALL_HEAP_FUNCTION(
566 isolate,
567 object->GetProperty(*receiver, result, *key, attributes),
568 Object);
569}
570
571
lrn@chromium.org303ada72010-10-27 09:33:13 +0000572MaybeObject* Object::GetProperty(Object* receiver,
573 LookupResult* result,
574 String* name,
575 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576 // Make sure that the top context does not change when doing
577 // callbacks or interceptor calls.
578 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 Heap* heap = name->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580
581 // Traverse the prototype chain from the current object (this) to
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000582 // the holder and check for access rights. This avoids traversing the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583 // objects more than once in case of interceptors, because the
584 // holder will always be the interceptor holder and the search may
585 // only continue with a current object just after the interceptor
586 // holder in the prototype chain.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000587 // Proxy handlers do not use the proxy's prototype, so we can skip this.
588 if (!result->IsHandler()) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000589 Object* last = result->IsProperty()
590 ? result->holder()
591 : Object::cast(heap->null_value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000592 ASSERT(this != this->GetPrototype());
593 for (Object* current = this; true; current = current->GetPrototype()) {
594 if (current->IsAccessCheckNeeded()) {
595 // Check if we're allowed to read from the current object. Note
596 // that even though we may not actually end up loading the named
597 // property from the current object, we still check that we have
598 // access to it.
599 JSObject* checked = JSObject::cast(current);
600 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
601 return checked->GetPropertyWithFailedAccessCheck(receiver,
602 result,
603 name,
604 attributes);
605 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000606 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000607 // Stop traversing the chain once we reach the last object in the
608 // chain; either the holder of the result or null in case of an
609 // absent property.
610 if (current == last) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000611 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000612 }
613
kasper.lund44510672008-07-25 07:37:58 +0000614 if (!result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 *attributes = ABSENT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000616 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617 }
618 *attributes = result->GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 switch (result->type()) {
621 case NORMAL:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000622 value = result->holder()->GetNormalizedProperty(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000624 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000625 case FIELD:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000626 value = result->holder()->FastPropertyAt(result->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000627 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000628 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629 case CONSTANT_FUNCTION:
630 return result->GetConstantFunction();
631 case CALLBACKS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000632 return result->holder()->GetPropertyWithCallback(
633 receiver, result->GetCallbackObject(), name);
634 case HANDLER:
635 return result->proxy()->GetPropertyWithHandler(receiver, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636 case INTERCEPTOR: {
637 JSObject* recvr = JSObject::cast(receiver);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000638 return result->holder()->GetPropertyWithInterceptor(
639 recvr, name, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000641 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000642 case NONEXISTENT:
643 UNREACHABLE();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000644 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000646 UNREACHABLE();
647 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648}
649
650
lrn@chromium.org303ada72010-10-27 09:33:13 +0000651MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000652 Heap* heap = IsSmi()
653 ? Isolate::Current()->heap()
654 : HeapObject::cast(this)->GetHeap();
655 Object* holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000656
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000657 // Iterate up the prototype chain until an element is found or the null
658 // prototype is encountered.
659 for (holder = this;
660 holder != heap->null_value();
661 holder = holder->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000662 if (!holder->IsJSObject()) {
663 Isolate* isolate = heap->isolate();
664 Context* global_context = isolate->context()->global_context();
665 if (holder->IsNumber()) {
666 holder = global_context->number_function()->instance_prototype();
667 } else if (holder->IsString()) {
668 holder = global_context->string_function()->instance_prototype();
669 } else if (holder->IsBoolean()) {
670 holder = global_context->boolean_function()->instance_prototype();
671 } else if (holder->IsJSProxy()) {
672 return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
673 } else {
674 // Undefined and null have no indexed properties.
675 ASSERT(holder->IsUndefined() || holder->IsNull());
676 return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000677 }
678 }
679
680 // Inline the case for JSObjects. Doing so significantly improves the
681 // performance of fetching elements where checking the prototype chain is
682 // necessary.
683 JSObject* js_object = JSObject::cast(holder);
684
685 // Check access rights if needed.
686 if (js_object->IsAccessCheckNeeded()) {
687 Isolate* isolate = heap->isolate();
688 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
689 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
690 return heap->undefined_value();
691 }
692 }
693
694 if (js_object->HasIndexedInterceptor()) {
695 return js_object->GetElementWithInterceptor(receiver, index);
696 }
697
698 if (js_object->elements() != heap->empty_fixed_array()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000699 MaybeObject* result = js_object->GetElementsAccessor()->Get(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000700 receiver, js_object, index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000701 if (result != heap->the_hole_value()) return result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000702 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000703 }
704
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000705 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000706}
707
708
709Object* Object::GetPrototype() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000710 if (IsSmi()) {
711 Heap* heap = Isolate::Current()->heap();
712 Context* context = heap->isolate()->context()->global_context();
713 return context->number_function()->instance_prototype();
714 }
715
716 HeapObject* heap_object = HeapObject::cast(this);
717
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000718 // The object is either a number, a string, a boolean,
719 // a real JS object, or a Harmony proxy.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000720 if (heap_object->IsJSReceiver()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000721 return heap_object->map()->prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000722 }
723 Heap* heap = heap_object->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000724 Context* context = heap->isolate()->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000726 if (heap_object->IsHeapNumber()) {
727 return context->number_function()->instance_prototype();
728 }
729 if (heap_object->IsString()) {
730 return context->string_function()->instance_prototype();
731 }
732 if (heap_object->IsBoolean()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000733 return context->boolean_function()->instance_prototype();
734 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000735 return heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000736 }
737}
738
739
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000740MaybeObject* Object::GetHash(CreationFlag flag) {
741 // The object is either a number, a string, an odd-ball,
742 // a real JS object, or a Harmony proxy.
743 if (IsNumber()) {
744 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
745 return Smi::FromInt(hash & Smi::kMaxValue);
746 }
747 if (IsString()) {
748 uint32_t hash = String::cast(this)->Hash();
749 return Smi::FromInt(hash);
750 }
751 if (IsOddball()) {
752 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
753 return Smi::FromInt(hash);
754 }
755 if (IsJSReceiver()) {
756 return JSReceiver::cast(this)->GetIdentityHash(flag);
757 }
758
759 UNREACHABLE();
760 return Smi::FromInt(0);
761}
762
763
764bool Object::SameValue(Object* other) {
765 if (other == this) return true;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000766
767 // The object is either a number, a string, an odd-ball,
768 // a real JS object, or a Harmony proxy.
769 if (IsNumber() && other->IsNumber()) {
770 double this_value = Number();
771 double other_value = other->Number();
772 return (this_value == other_value) ||
773 (isnan(this_value) && isnan(other_value));
774 }
775 if (IsString() && other->IsString()) {
776 return String::cast(this)->Equals(String::cast(other));
777 }
778 return false;
779}
780
781
whesse@chromium.org023421e2010-12-21 12:19:12 +0000782void Object::ShortPrint(FILE* out) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000783 HeapStringAllocator allocator;
784 StringStream accumulator(&allocator);
785 ShortPrint(&accumulator);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000786 accumulator.OutputToFile(out);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787}
788
789
790void Object::ShortPrint(StringStream* accumulator) {
791 if (IsSmi()) {
792 Smi::cast(this)->SmiPrint(accumulator);
793 } else if (IsFailure()) {
794 Failure::cast(this)->FailurePrint(accumulator);
795 } else {
796 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
797 }
798}
799
800
whesse@chromium.org023421e2010-12-21 12:19:12 +0000801void Smi::SmiPrint(FILE* out) {
802 PrintF(out, "%d", value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000803}
804
805
806void Smi::SmiPrint(StringStream* accumulator) {
807 accumulator->Add("%d", value());
808}
809
810
811void Failure::FailurePrint(StringStream* accumulator) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000812 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813}
814
815
whesse@chromium.org023421e2010-12-21 12:19:12 +0000816void Failure::FailurePrint(FILE* out) {
817 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000818}
819
820
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000821// Should a word be prefixed by 'a' or 'an' in order to read naturally in
822// English? Returns false for non-ASCII or words that don't start with
823// a capital letter. The a/an rule follows pronunciation in English.
824// We don't use the BBC's overcorrect "an historic occasion" though if
825// you speak a dialect you may well say "an 'istoric occasion".
826static bool AnWord(String* str) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000827 if (str->length() == 0) return false; // A nothing.
828 int c0 = str->Get(0);
829 int c1 = str->length() > 1 ? str->Get(1) : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830 if (c0 == 'U') {
831 if (c1 > 'Z') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000832 return true; // An Umpire, but a UTF8String, a U.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000833 }
834 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000835 return true; // An Ape, an ABCBook.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000836 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
837 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
838 c0 == 'S' || c0 == 'X')) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000839 return true; // An MP3File, an M.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 }
841 return false;
842}
843
844
lrn@chromium.org303ada72010-10-27 09:33:13 +0000845MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000846#ifdef DEBUG
847 // Do not attempt to flatten in debug mode when allocation is not
848 // allowed. This is to avoid an assertion failure when allocating.
849 // Flattening strings is the only case where we always allow
850 // allocation because no GC is performed if the allocation fails.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000851 if (!HEAP->IsAllocationAllowed()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000852#endif
853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000855 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000856 case kConsStringTag: {
857 ConsString* cs = ConsString::cast(this);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000858 if (cs->second()->length() == 0) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000859 return cs->first();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000860 }
861 // There's little point in putting the flat string in new space if the
862 // cons string is in old space. It can never get GCed until there is
863 // an old space GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000864 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000865 int len = length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000866 Object* object;
867 String* result;
ager@chromium.org5ec48922009-05-05 07:25:34 +0000868 if (IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000869 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000870 if (!maybe_object->ToObject(&object)) return maybe_object;
871 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000872 result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000873 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000874 int first_length = first->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000875 char* dest = SeqAsciiString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000876 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000877 String* second = cs->second();
878 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000879 dest + first_length,
880 0,
881 len - first_length);
882 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000883 { MaybeObject* maybe_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000884 heap->AllocateRawTwoByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000885 if (!maybe_object->ToObject(&object)) return maybe_object;
886 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000887 result = String::cast(object);
888 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000889 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000890 int first_length = first->length();
891 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000892 String* second = cs->second();
893 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000894 dest + first_length,
895 0,
896 len - first_length);
897 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000898 cs->set_first(result);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000899 cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000900 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000901 }
902 default:
903 return this;
904 }
905}
906
907
ager@chromium.org6f10e412009-02-13 10:11:16 +0000908bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000909 // Externalizing twice leaks the external resource, so it's
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000910 // prohibited by the API.
911 ASSERT(!this->IsExternalString());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000912#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +0000913 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000914 // Assert that the resource and the string are equivalent.
915 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000916 ScopedVector<uc16> smart_chars(this->length());
917 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
918 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +0000919 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000920 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000921 }
922#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000923 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000924 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000925 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000926 return false;
927 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000928 bool is_ascii = this->IsAsciiRepresentation();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000929 bool is_symbol = this->IsSymbol();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000930
931 // Morph the object to an external string by adjusting the map and
932 // reinitializing the fields.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000933 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000934 this->set_map_no_write_barrier(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000935 is_symbol
936 ? (is_ascii ? heap->external_symbol_with_ascii_data_map()
937 : heap->external_symbol_map())
938 : (is_ascii ? heap->external_string_with_ascii_data_map()
939 : heap->external_string_map()));
940 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000941 this->set_map_no_write_barrier(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000942 is_symbol
943 ? (is_ascii ? heap->short_external_symbol_with_ascii_data_map()
944 : heap->short_external_symbol_map())
945 : (is_ascii ? heap->short_external_string_with_ascii_data_map()
946 : heap->short_external_string_map()));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000947 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000948 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
949 self->set_resource(resource);
950 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +0000951
952 // Fill the remainder of the string with dead wood.
953 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000954 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000955 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000956 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
957 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000958 }
ager@chromium.org6f10e412009-02-13 10:11:16 +0000959 return true;
960}
961
962
963bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
964#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +0000965 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000966 // Assert that the resource and the string are equivalent.
967 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000968 ScopedVector<char> smart_chars(this->length());
969 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
970 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +0000971 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000972 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000973 }
974#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000975 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000976 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000977 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000978 return false;
979 }
ager@chromium.org6f10e412009-02-13 10:11:16 +0000980 bool is_symbol = this->IsSymbol();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000981
982 // Morph the object to an external string by adjusting the map and
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000983 // reinitializing the fields. Use short version if space is limited.
984 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000985 this->set_map_no_write_barrier(
986 is_symbol ? heap->external_ascii_symbol_map()
987 : heap->external_ascii_string_map());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000988 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000989 this->set_map_no_write_barrier(
990 is_symbol ? heap->short_external_ascii_symbol_map()
991 : heap->short_external_ascii_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000992 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000993 ExternalAsciiString* self = ExternalAsciiString::cast(this);
994 self->set_resource(resource);
995 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +0000996
997 // Fill the remainder of the string with dead wood.
998 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000999 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001000 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001001 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
1002 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001003 }
ager@chromium.org6f10e412009-02-13 10:11:16 +00001004 return true;
1005}
1006
1007
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008void String::StringShortPrint(StringStream* accumulator) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001009 int len = length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001010 if (len > kMaxShortPrintLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 accumulator->Add("<Very long string[%u]>", len);
1012 return;
1013 }
1014
1015 if (!LooksValid()) {
1016 accumulator->Add("<Invalid String>");
1017 return;
1018 }
1019
1020 StringInputBuffer buf(this);
1021
1022 bool truncated = false;
kasper.lund7276f142008-07-30 08:49:36 +00001023 if (len > kMaxShortPrintLength) {
1024 len = kMaxShortPrintLength;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025 truncated = true;
1026 }
1027 bool ascii = true;
1028 for (int i = 0; i < len; i++) {
1029 int c = buf.GetNext();
1030
1031 if (c < 32 || c >= 127) {
1032 ascii = false;
1033 }
1034 }
1035 buf.Reset(this);
1036 if (ascii) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001037 accumulator->Add("<String[%u]: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038 for (int i = 0; i < len; i++) {
1039 accumulator->Put(buf.GetNext());
1040 }
1041 accumulator->Put('>');
1042 } else {
1043 // Backslash indicates that the string contains control
1044 // characters and that backslashes are therefore escaped.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001045 accumulator->Add("<String[%u]\\: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046 for (int i = 0; i < len; i++) {
1047 int c = buf.GetNext();
1048 if (c == '\n') {
1049 accumulator->Add("\\n");
1050 } else if (c == '\r') {
1051 accumulator->Add("\\r");
1052 } else if (c == '\\') {
1053 accumulator->Add("\\\\");
1054 } else if (c < 32 || c > 126) {
1055 accumulator->Add("\\x%02x", c);
1056 } else {
1057 accumulator->Put(c);
1058 }
1059 }
1060 if (truncated) {
1061 accumulator->Put('.');
1062 accumulator->Put('.');
1063 accumulator->Put('.');
1064 }
1065 accumulator->Put('>');
1066 }
1067 return;
1068}
1069
1070
1071void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1072 switch (map()->instance_type()) {
1073 case JS_ARRAY_TYPE: {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001074 double length = JSArray::cast(this)->length()->IsUndefined()
1075 ? 0
1076 : JSArray::cast(this)->length()->Number();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001077 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078 break;
1079 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001080 case JS_WEAK_MAP_TYPE: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001081 accumulator->Add("<JS WeakMap>");
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001082 break;
1083 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001084 case JS_REGEXP_TYPE: {
1085 accumulator->Add("<JS RegExp>");
1086 break;
1087 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 case JS_FUNCTION_TYPE: {
1089 Object* fun_name = JSFunction::cast(this)->shared()->name();
1090 bool printed = false;
1091 if (fun_name->IsString()) {
1092 String* str = String::cast(fun_name);
1093 if (str->length() > 0) {
1094 accumulator->Add("<JS Function ");
1095 accumulator->Put(str);
1096 accumulator->Put('>');
1097 printed = true;
1098 }
1099 }
1100 if (!printed) {
1101 accumulator->Add("<JS Function>");
1102 }
1103 break;
1104 }
1105 // All other JSObjects are rather similar to each other (JSObject,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001106 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107 default: {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001108 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001109 Heap* heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001110 Object* constructor = map_of_this->constructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111 bool printed = false;
1112 if (constructor->IsHeapObject() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 !heap->Contains(HeapObject::cast(constructor))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001114 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1115 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001116 bool global_object = IsJSGlobalProxy();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001117 if (constructor->IsJSFunction()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001118 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001119 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1120 } else {
1121 Object* constructor_name =
1122 JSFunction::cast(constructor)->shared()->name();
1123 if (constructor_name->IsString()) {
1124 String* str = String::cast(constructor_name);
1125 if (str->length() > 0) {
1126 bool vowel = AnWord(str);
1127 accumulator->Add("<%sa%s ",
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001128 global_object ? "Global Object: " : "",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129 vowel ? "n" : "");
1130 accumulator->Put(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131 printed = true;
1132 }
1133 }
1134 }
1135 }
1136 if (!printed) {
1137 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1138 }
1139 }
1140 if (IsJSValue()) {
1141 accumulator->Add(" value = ");
1142 JSValue::cast(this)->value()->ShortPrint(accumulator);
1143 }
1144 accumulator->Put('>');
1145 break;
1146 }
1147 }
1148}
1149
1150
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001151void JSObject::PrintElementsTransition(
1152 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1153 ElementsKind to_kind, FixedArrayBase* to_elements) {
1154 if (from_kind != to_kind) {
1155 PrintF(file, "elements transition [");
1156 PrintElementsKind(file, from_kind);
1157 PrintF(file, " -> ");
1158 PrintElementsKind(file, to_kind);
1159 PrintF(file, "] in ");
1160 JavaScriptFrame::PrintTop(file, false, true);
1161 PrintF(file, " for ");
1162 ShortPrint(file);
1163 PrintF(file, " from ");
1164 from_elements->ShortPrint(file);
1165 PrintF(file, " to ");
1166 to_elements->ShortPrint(file);
1167 PrintF(file, "\n");
1168 }
1169}
1170
1171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001173 Heap* heap = GetHeap();
1174 if (!heap->Contains(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 accumulator->Add("!!!INVALID POINTER!!!");
1176 return;
1177 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001178 if (!heap->Contains(map())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179 accumulator->Add("!!!INVALID MAP!!!");
1180 return;
1181 }
1182
1183 accumulator->Add("%p ", this);
1184
1185 if (IsString()) {
1186 String::cast(this)->StringShortPrint(accumulator);
1187 return;
1188 }
1189 if (IsJSObject()) {
1190 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1191 return;
1192 }
1193 switch (map()->instance_type()) {
1194 case MAP_TYPE:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001195 accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196 break;
1197 case FIXED_ARRAY_TYPE:
1198 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1199 break;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001200 case FIXED_DOUBLE_ARRAY_TYPE:
1201 accumulator->Add("<FixedDoubleArray[%u]>",
1202 FixedDoubleArray::cast(this)->length());
1203 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204 case BYTE_ARRAY_TYPE:
1205 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1206 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001207 case FREE_SPACE_TYPE:
1208 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1209 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001210 case EXTERNAL_PIXEL_ARRAY_TYPE:
1211 accumulator->Add("<ExternalPixelArray[%u]>",
1212 ExternalPixelArray::cast(this)->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001213 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00001214 case EXTERNAL_BYTE_ARRAY_TYPE:
1215 accumulator->Add("<ExternalByteArray[%u]>",
1216 ExternalByteArray::cast(this)->length());
1217 break;
1218 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1219 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1220 ExternalUnsignedByteArray::cast(this)->length());
1221 break;
1222 case EXTERNAL_SHORT_ARRAY_TYPE:
1223 accumulator->Add("<ExternalShortArray[%u]>",
1224 ExternalShortArray::cast(this)->length());
1225 break;
1226 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1227 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1228 ExternalUnsignedShortArray::cast(this)->length());
1229 break;
1230 case EXTERNAL_INT_ARRAY_TYPE:
1231 accumulator->Add("<ExternalIntArray[%u]>",
1232 ExternalIntArray::cast(this)->length());
1233 break;
1234 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1235 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1236 ExternalUnsignedIntArray::cast(this)->length());
1237 break;
1238 case EXTERNAL_FLOAT_ARRAY_TYPE:
1239 accumulator->Add("<ExternalFloatArray[%u]>",
1240 ExternalFloatArray::cast(this)->length());
1241 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001242 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1243 accumulator->Add("<ExternalDoubleArray[%u]>",
1244 ExternalDoubleArray::cast(this)->length());
1245 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246 case SHARED_FUNCTION_INFO_TYPE:
1247 accumulator->Add("<SharedFunctionInfo>");
1248 break;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001249 case JS_MESSAGE_OBJECT_TYPE:
1250 accumulator->Add("<JSMessageObject>");
1251 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252#define MAKE_STRUCT_CASE(NAME, Name, name) \
1253 case NAME##_TYPE: \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001254 accumulator->Put('<'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 accumulator->Add(#Name); \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001256 accumulator->Put('>'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 break;
1258 STRUCT_LIST(MAKE_STRUCT_CASE)
1259#undef MAKE_STRUCT_CASE
1260 case CODE_TYPE:
1261 accumulator->Add("<Code>");
1262 break;
1263 case ODDBALL_TYPE: {
1264 if (IsUndefined())
1265 accumulator->Add("<undefined>");
1266 else if (IsTheHole())
1267 accumulator->Add("<the hole>");
1268 else if (IsNull())
1269 accumulator->Add("<null>");
1270 else if (IsTrue())
1271 accumulator->Add("<true>");
1272 else if (IsFalse())
1273 accumulator->Add("<false>");
1274 else
1275 accumulator->Add("<Odd Oddball>");
1276 break;
1277 }
1278 case HEAP_NUMBER_TYPE:
1279 accumulator->Add("<Number: ");
1280 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1281 accumulator->Put('>');
1282 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001283 case JS_PROXY_TYPE:
1284 accumulator->Add("<JSProxy>");
1285 break;
1286 case JS_FUNCTION_PROXY_TYPE:
1287 accumulator->Add("<JSFunctionProxy>");
1288 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001289 case FOREIGN_TYPE:
1290 accumulator->Add("<Foreign>");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001292 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1293 accumulator->Add("Cell for ");
1294 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1295 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296 default:
1297 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1298 break;
1299 }
1300}
1301
1302
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303void HeapObject::Iterate(ObjectVisitor* v) {
1304 // Handle header
1305 IteratePointer(v, kMapOffset);
1306 // Handle object body
1307 Map* m = map();
1308 IterateBody(m->instance_type(), SizeFromMap(m), v);
1309}
1310
1311
1312void HeapObject::IterateBody(InstanceType type, int object_size,
1313 ObjectVisitor* v) {
1314 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1315 // During GC, the map pointer field is encoded.
1316 if (type < FIRST_NONSTRING_TYPE) {
1317 switch (type & kStringRepresentationMask) {
1318 case kSeqStringTag:
1319 break;
1320 case kConsStringTag:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001321 ConsString::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001322 break;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001323 case kSlicedStringTag:
1324 SlicedString::BodyDescriptor::IterateBody(this, v);
1325 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001326 case kExternalStringTag:
1327 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1328 reinterpret_cast<ExternalAsciiString*>(this)->
1329 ExternalAsciiStringIterateBody(v);
1330 } else {
1331 reinterpret_cast<ExternalTwoByteString*>(this)->
1332 ExternalTwoByteStringIterateBody(v);
1333 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001334 break;
1335 }
1336 return;
1337 }
1338
1339 switch (type) {
1340 case FIXED_ARRAY_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001341 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001343 case FIXED_DOUBLE_ARRAY_TYPE:
1344 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 case JS_OBJECT_TYPE:
ager@chromium.org32912102009-01-16 10:38:43 +00001346 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001347 case JS_MODULE_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 case JS_VALUE_TYPE:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001349 case JS_DATE_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350 case JS_ARRAY_TYPE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001351 case JS_SET_TYPE:
1352 case JS_MAP_TYPE:
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001353 case JS_WEAK_MAP_TYPE:
ager@chromium.org236ad962008-09-25 09:45:57 +00001354 case JS_REGEXP_TYPE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001355 case JS_GLOBAL_PROXY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 case JS_GLOBAL_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357 case JS_BUILTINS_OBJECT_TYPE:
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001358 case JS_MESSAGE_OBJECT_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001359 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 break;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001361 case JS_FUNCTION_TYPE:
1362 reinterpret_cast<JSFunction*>(this)
1363 ->JSFunctionIterateBody(object_size, v);
1364 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365 case ODDBALL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001366 Oddball::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367 break;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001368 case JS_PROXY_TYPE:
1369 JSProxy::BodyDescriptor::IterateBody(this, v);
1370 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001371 case JS_FUNCTION_PROXY_TYPE:
1372 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1373 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001374 case FOREIGN_TYPE:
1375 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 break;
1377 case MAP_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001378 Map::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001379 break;
1380 case CODE_TYPE:
1381 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1382 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001383 case JS_GLOBAL_PROPERTY_CELL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001384 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001385 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001386 case HEAP_NUMBER_TYPE:
1387 case FILLER_TYPE:
1388 case BYTE_ARRAY_TYPE:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001389 case FREE_SPACE_TYPE:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001390 case EXTERNAL_PIXEL_ARRAY_TYPE:
ager@chromium.org3811b432009-10-28 14:53:37 +00001391 case EXTERNAL_BYTE_ARRAY_TYPE:
1392 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1393 case EXTERNAL_SHORT_ARRAY_TYPE:
1394 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1395 case EXTERNAL_INT_ARRAY_TYPE:
1396 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1397 case EXTERNAL_FLOAT_ARRAY_TYPE:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001398 case EXTERNAL_DOUBLE_ARRAY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 break;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001400 case SHARED_FUNCTION_INFO_TYPE: {
1401 SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this);
1402 shared->SharedFunctionInfoIterateBody(v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403 break;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001404 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001405
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406#define MAKE_STRUCT_CASE(NAME, Name, name) \
1407 case NAME##_TYPE:
1408 STRUCT_LIST(MAKE_STRUCT_CASE)
1409#undef MAKE_STRUCT_CASE
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001410 StructBodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411 break;
1412 default:
1413 PrintF("Unknown type: %d\n", type);
1414 UNREACHABLE();
1415 }
1416}
1417
1418
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419Object* HeapNumber::HeapNumberToBoolean() {
1420 // NaN, +0, and -0 should return the false object
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001421#if __BYTE_ORDER == __LITTLE_ENDIAN
1422 union IeeeDoubleLittleEndianArchType u;
1423#elif __BYTE_ORDER == __BIG_ENDIAN
1424 union IeeeDoubleBigEndianArchType u;
1425#endif
1426 u.d = value();
1427 if (u.bits.exp == 2047) {
1428 // Detect NaN for IEEE double precision floating point.
1429 if ((u.bits.man_low | u.bits.man_high) != 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001430 return GetHeap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001432 if (u.bits.exp == 0) {
1433 // Detect +0, and -0 for IEEE double precision floating point.
1434 if ((u.bits.man_low | u.bits.man_high) == 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001435 return GetHeap()->false_value();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001436 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001437 return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438}
1439
1440
whesse@chromium.org023421e2010-12-21 12:19:12 +00001441void HeapNumber::HeapNumberPrint(FILE* out) {
1442 PrintF(out, "%.16g", Number());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001443}
1444
1445
1446void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1447 // The Windows version of vsnprintf can allocate when printing a %g string
1448 // into a buffer that may not be big enough. We don't want random memory
1449 // allocation when producing post-crash stack traces, so we print into a
1450 // buffer that is plenty big enough for any floating point number, then
1451 // print that using vsnprintf (which may truncate but never allocate if
1452 // there is no more space in the buffer).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001453 EmbeddedVector<char, 100> buffer;
1454 OS::SNPrintF(buffer, "%.16g", Number());
1455 accumulator->Add("%s", buffer.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456}
1457
1458
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001459String* JSReceiver::class_name() {
1460 if (IsJSFunction() && IsJSFunctionProxy()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001461 return GetHeap()->function_class_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001462 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463 if (map()->constructor()->IsJSFunction()) {
1464 JSFunction* constructor = JSFunction::cast(map()->constructor());
1465 return String::cast(constructor->shared()->instance_class_name());
1466 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001467 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001468 return GetHeap()->Object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469}
1470
1471
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001472String* JSReceiver::constructor_name() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001473 if (map()->constructor()->IsJSFunction()) {
1474 JSFunction* constructor = JSFunction::cast(map()->constructor());
1475 String* name = String::cast(constructor->shared()->name());
vegorov@chromium.org42841962010-10-18 11:18:59 +00001476 if (name->length() > 0) return name;
1477 String* inferred_name = constructor->shared()->inferred_name();
1478 if (inferred_name->length() > 0) return inferred_name;
1479 Object* proto = GetPrototype();
1480 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001481 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001482 // TODO(rossberg): what about proxies?
ager@chromium.orga1645e22009-09-09 19:27:10 +00001483 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 return GetHeap()->Object_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001485}
1486
1487
lrn@chromium.org303ada72010-10-27 09:33:13 +00001488MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1489 String* name,
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001490 Object* value,
1491 int field_index) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001492 if (map()->unused_property_fields() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493 int new_unused = new_map->unused_property_fields();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001494 FixedArray* values;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001495 { MaybeObject* maybe_values =
1496 properties()->CopySize(properties()->length() + new_unused + 1);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001497 if (!maybe_values->To(&values)) return maybe_values;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001498 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001499 set_properties(values);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500 }
1501 set_map(new_map);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001502 return FastPropertyAtPut(field_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001503}
1504
1505
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001506static bool IsIdentifier(UnicodeCache* cache,
1507 unibrow::CharacterStream* buffer) {
1508 // Checks whether the buffer contains an identifier (no escape).
1509 if (!buffer->has_more()) return false;
1510 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1511 return false;
1512 }
1513 while (buffer->has_more()) {
1514 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1515 return false;
1516 }
1517 }
1518 return true;
1519}
1520
1521
lrn@chromium.org303ada72010-10-27 09:33:13 +00001522MaybeObject* JSObject::AddFastProperty(String* name,
1523 Object* value,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001524 PropertyAttributes attributes,
1525 StoreFromKeyed store_mode) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001526 ASSERT(!IsJSGlobalProxy());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001527 ASSERT(map()->instance_descriptors()->Search(name) ==
1528 DescriptorArray::kNotFound);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001529
ager@chromium.org8c51fc92009-04-22 11:54:55 +00001530 // Normalize the object if the name is an actual string (not the
1531 // hidden symbols) and is not a real identifier.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001532 // Normalize the object if it will have too many fast properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001533 Isolate* isolate = GetHeap()->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 StringInputBuffer buffer(name);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001535 if ((!IsIdentifier(isolate->unicode_cache(), &buffer)
1536 && name != isolate->heap()->hidden_symbol()) ||
1537 (map()->unused_property_fields() == 0 &&
1538 TooManyFastProperties(properties()->length(), store_mode))) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001539 Object* obj;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001540 MaybeObject* maybe_obj =
1541 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1542 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1543
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544 return AddSlowProperty(name, value, attributes);
1545 }
1546
1547 // Compute the new index for new field.
1548 int index = map()->NextFreePropertyIndex();
1549
1550 // Allocate new instance descriptors with (name, index) added
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001551 FieldDescriptor new_field(name, index, attributes, 0);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001552
ager@chromium.org7c537e22008-10-16 08:43:32 +00001553 ASSERT(index < map()->inobject_properties() ||
1554 (index - map()->inobject_properties()) < properties()->length() ||
1555 map()->unused_property_fields() == 0);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001556
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001557 FixedArray* values = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001558
ager@chromium.org7c537e22008-10-16 08:43:32 +00001559 if (map()->unused_property_fields() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 // Make room for the new value
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001561 MaybeObject* maybe_values =
1562 properties()->CopySize(properties()->length() + kFieldsAdded);
1563 if (!maybe_values->To(&values)) return maybe_values;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001564 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001565
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001566 // Only allow map transition if the object isn't the global object.
1567 TransitionFlag flag = isolate->empty_object_map() != map()
1568 ? INSERT_TRANSITION
1569 : OMIT_TRANSITION;
1570
1571 Map* new_map;
1572 MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&new_field, flag);
1573 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
1574
1575 if (map()->unused_property_fields() == 0) {
1576 ASSERT(values != NULL);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001577 set_properties(values);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001578 new_map->set_unused_property_fields(kFieldsAdded - 1);
1579 } else {
1580 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 }
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001582
ager@chromium.org7c537e22008-10-16 08:43:32 +00001583 set_map(new_map);
1584 return FastPropertyAtPut(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585}
1586
1587
lrn@chromium.org303ada72010-10-27 09:33:13 +00001588MaybeObject* JSObject::AddConstantFunctionProperty(
1589 String* name,
1590 JSFunction* function,
1591 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592 // Allocate new instance descriptors with (name, function) added
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001593 ConstantFunctionDescriptor d(name, function, attributes, 0);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001594
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001595 Heap* heap = GetHeap();
1596 TransitionFlag flag =
1597 // Do not add transitions to the empty object map (map of "new Object()"),
1598 // nor to global objects.
1599 (map() == heap->isolate()->empty_object_map() || IsGlobalObject() ||
1600 // Don't add transitions to special properties with non-trivial
1601 // attributes.
1602 // TODO(verwaest): Once we support attribute changes, these transitions
1603 // should be kept as well.
1604 attributes != NONE)
1605 ? OMIT_TRANSITION
1606 : INSERT_TRANSITION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001608 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001609 MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&d, flag);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001610 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001612 set_map(new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 return function;
1614}
1615
1616
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617// Add property in slow mode
lrn@chromium.org303ada72010-10-27 09:33:13 +00001618MaybeObject* JSObject::AddSlowProperty(String* name,
1619 Object* value,
1620 PropertyAttributes attributes) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001621 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001622 StringDictionary* dict = property_dictionary();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001623 Object* store_value = value;
1624 if (IsGlobalObject()) {
1625 // In case name is an orphaned property reuse the cell.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001626 int entry = dict->FindEntry(name);
1627 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001628 store_value = dict->ValueAt(entry);
1629 JSGlobalPropertyCell::cast(store_value)->set_value(value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001630 // Assign an enumeration index to the property and update
1631 // SetNextEnumerationIndex.
1632 int index = dict->NextEnumerationIndex();
1633 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1634 dict->SetNextEnumerationIndex(index + 1);
1635 dict->SetEntry(entry, name, store_value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001636 return value;
1637 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001638 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001639 { MaybeObject* maybe_store_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 heap->AllocateJSGlobalPropertyCell(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001641 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1642 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001643 JSGlobalPropertyCell::cast(store_value)->set_value(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001645 PropertyDetails details = PropertyDetails(attributes, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001646 Object* result;
1647 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1648 if (!maybe_result->ToObject(&result)) return maybe_result;
1649 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001650 if (dict != result) set_properties(StringDictionary::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651 return value;
1652}
1653
1654
lrn@chromium.org303ada72010-10-27 09:33:13 +00001655MaybeObject* JSObject::AddProperty(String* name,
1656 Object* value,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001657 PropertyAttributes attributes,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001658 StrictModeFlag strict_mode,
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00001659 JSReceiver::StoreFromKeyed store_mode,
1660 ExtensibilityCheck extensibility_check) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001661 ASSERT(!IsJSGlobalProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001662 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001663 Heap* heap = GetHeap();
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00001664 if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK &&
1665 !map_of_this->is_extensible()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001666 if (strict_mode == kNonStrictMode) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001667 return value;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001668 } else {
1669 Handle<Object> args[1] = {Handle<String>(name)};
1670 return heap->isolate()->Throw(
1671 *FACTORY->NewTypeError("object_not_extensible",
1672 HandleVector(args, 1)));
1673 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001674 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675 if (HasFastProperties()) {
1676 // Ensure the descriptor array does not get too big.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001677 if (map_of_this->instance_descriptors()->number_of_descriptors() <
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001678 DescriptorArray::kMaxNumberOfDescriptors) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001679 if (value->IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 return AddConstantFunctionProperty(name,
1681 JSFunction::cast(value),
1682 attributes);
1683 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001684 return AddFastProperty(name, value, attributes, store_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001685 }
1686 } else {
1687 // Normalize the object to prevent very large instance descriptors.
1688 // This eliminates unwanted N^2 allocation and lookup behavior.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001689 Object* obj;
1690 { MaybeObject* maybe_obj =
1691 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1692 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1693 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001694 }
1695 }
1696 return AddSlowProperty(name, value, attributes);
1697}
1698
1699
lrn@chromium.org303ada72010-10-27 09:33:13 +00001700MaybeObject* JSObject::SetPropertyPostInterceptor(
1701 String* name,
1702 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001703 PropertyAttributes attributes,
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00001704 StrictModeFlag strict_mode,
1705 ExtensibilityCheck extensibility_check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001707 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001708 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001709 if (!result.IsFound()) map()->LookupTransition(this, name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00001710 if (result.IsFound()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001711 // An existing property or a map transition was found. Use set property to
1712 // handle all these cases.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001713 return SetProperty(&result, name, value, attributes, strict_mode);
ager@chromium.org5c838252010-02-19 08:53:10 +00001714 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001715 bool done = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001716 MaybeObject* result_object;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001717 result_object =
1718 SetPropertyViaPrototypes(name, value, attributes, strict_mode, &done);
1719 if (done) return result_object;
ager@chromium.org5c838252010-02-19 08:53:10 +00001720 // Add a new real property.
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00001721 return AddProperty(name, value, attributes, strict_mode,
1722 MAY_BE_STORE_FROM_KEYED, extensibility_check);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723}
1724
1725
lrn@chromium.org303ada72010-10-27 09:33:13 +00001726MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1727 Object* value,
1728 PropertyAttributes attributes) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001729 StringDictionary* dictionary = property_dictionary();
1730 int old_index = dictionary->FindEntry(name);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001731 int new_enumeration_index = 0; // 0 means "Use the next available index."
1732 if (old_index != -1) {
1733 // All calls to ReplaceSlowProperty have had all transitions removed.
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001734 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1735 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001736
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001737 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001738 return SetNormalizedProperty(name, value, new_details);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001739}
1740
ager@chromium.org6141cbe2009-11-20 12:14:52 +00001741
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001742MaybeObject* JSObject::ConvertTransitionToMapTransition(
1743 int transition_index,
ager@chromium.org7c537e22008-10-16 08:43:32 +00001744 String* name,
1745 Object* new_value,
1746 PropertyAttributes attributes) {
1747 Map* old_map = map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001748 Object* result;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001749
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001750 MaybeObject* maybe_result =
1751 ConvertDescriptorToField(name, new_value, attributes);
1752 if (!maybe_result->To(&result)) return maybe_result;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001753
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001754 if (!HasFastProperties()) return result;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001755
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001756 // This method should only be used to convert existing transitions. Objects
1757 // with the map of "new Object()" cannot have transitions in the first place.
1758 ASSERT(map() != GetIsolate()->empty_object_map());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001759
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001760 // TODO(verwaest): From here on we lose existing map transitions, causing
1761 // invalid back pointers. This will change once we can store multiple
1762 // transitions with the same key.
1763 old_map->SetTransition(transition_index, map());
1764 map()->SetBackPointer(old_map);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001765 return result;
1766}
1767
1768
lrn@chromium.org303ada72010-10-27 09:33:13 +00001769MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1770 Object* new_value,
1771 PropertyAttributes attributes) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001772 if (map()->unused_property_fields() == 0 &&
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001773 TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001774 Object* obj;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001775 MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1776 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001777 return ReplaceSlowProperty(name, new_value, attributes);
1778 }
1779
1780 int index = map()->NextFreePropertyIndex();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001781 FieldDescriptor new_field(name, index, attributes, 0);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001782
ager@chromium.org7c537e22008-10-16 08:43:32 +00001783 // Make a new map for the object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001784 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001785 MaybeObject* maybe_new_map = map()->CopyInsertDescriptor(&new_field,
1786 OMIT_TRANSITION);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001787 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001788
1789 // Make new properties array if necessary.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001790 FixedArray* new_properties = NULL;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001791 int new_unused_property_fields = map()->unused_property_fields() - 1;
1792 if (map()->unused_property_fields() == 0) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001793 new_unused_property_fields = kFieldsAdded - 1;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001794 MaybeObject* maybe_new_properties =
1795 properties()->CopySize(properties()->length() + kFieldsAdded);
1796 if (!maybe_new_properties->To(&new_properties)) return maybe_new_properties;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001797 }
1798
1799 // Update pointers to commit changes.
1800 // Object points to the new map.
1801 new_map->set_unused_property_fields(new_unused_property_fields);
1802 set_map(new_map);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001803 if (new_properties != NULL) {
1804 set_properties(new_properties);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001805 }
1806 return FastPropertyAtPut(index, new_value);
1807}
1808
1809
1810
lrn@chromium.org303ada72010-10-27 09:33:13 +00001811MaybeObject* JSObject::SetPropertyWithInterceptor(
1812 String* name,
1813 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001814 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001815 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 Isolate* isolate = GetIsolate();
1817 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001818 Handle<JSObject> this_handle(this);
1819 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001820 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001821 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1822 if (!interceptor->setter()->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001823 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1824 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001825 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001826 v8::NamedPropertySetter setter =
1827 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1828 v8::Handle<v8::Value> result;
1829 {
1830 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001832 Handle<Object> value_unhole(value->IsTheHole() ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 isolate->heap()->undefined_value() :
1834 value,
1835 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001836 result = setter(v8::Utils::ToLocal(name_handle),
1837 v8::Utils::ToLocal(value_unhole),
1838 info);
1839 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001841 if (!result.IsEmpty()) return *value_handle;
1842 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001843 MaybeObject* raw_result =
1844 this_handle->SetPropertyPostInterceptor(*name_handle,
1845 *value_handle,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001846 attributes,
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00001847 strict_mode,
1848 PERFORM_EXTENSIBILITY_CHECK);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001850 return raw_result;
1851}
1852
1853
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001854Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
1855 Handle<String> key,
1856 Handle<Object> value,
1857 PropertyAttributes attributes,
1858 StrictModeFlag strict_mode) {
1859 CALL_HEAP_FUNCTION(object->GetIsolate(),
1860 object->SetProperty(*key, *value, attributes, strict_mode),
1861 Object);
1862}
1863
1864
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001865MaybeObject* JSReceiver::SetProperty(String* name,
1866 Object* value,
1867 PropertyAttributes attributes,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001868 StrictModeFlag strict_mode,
1869 JSReceiver::StoreFromKeyed store_mode) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001870 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001871 LocalLookup(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001872 if (!result.IsFound()) {
1873 map()->LookupTransition(JSObject::cast(this), name, &result);
1874 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001875 return SetProperty(&result, name, value, attributes, strict_mode, store_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001876}
1877
1878
lrn@chromium.org303ada72010-10-27 09:33:13 +00001879MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1880 String* name,
1881 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001882 JSObject* holder,
1883 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001884 Isolate* isolate = GetIsolate();
1885 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001886
1887 // We should never get here to initialize a const with the hole
1888 // value since a const declaration would conflict with the setter.
1889 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001890 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001891
1892 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001893 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001894 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001895 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001897 reinterpret_cast<AccessorDescriptor*>(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001898 Foreign::cast(structure)->foreign_address());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001899 MaybeObject* obj = (callback->setter)(this, value, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001900 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001901 if (obj->IsFailure()) return obj;
1902 return *value_handle;
1903 }
1904
1905 if (structure->IsAccessorInfo()) {
1906 // api style callbacks
1907 AccessorInfo* data = AccessorInfo::cast(structure);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001908 if (!data->IsCompatibleReceiver(this)) {
1909 Handle<Object> name_handle(name);
1910 Handle<Object> receiver_handle(this);
1911 Handle<Object> args[2] = { name_handle, receiver_handle };
1912 Handle<Object> error =
1913 isolate->factory()->NewTypeError("incompatible_method_receiver",
1914 HandleVector(args,
1915 ARRAY_SIZE(args)));
1916 return isolate->Throw(*error);
1917 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 Object* call_obj = data->setter();
1919 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1920 if (call_fun == NULL) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001921 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001922 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1923 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001924 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 {
1926 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001927 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001928 call_fun(v8::Utils::ToLocal(key),
1929 v8::Utils::ToLocal(value_handle),
1930 info);
1931 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001932 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 return *value_handle;
1934 }
1935
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001936 if (structure->IsAccessorPair()) {
1937 Object* setter = AccessorPair::cast(structure)->setter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001938 if (setter->IsSpecFunction()) {
1939 // TODO(rossberg): nicer would be to cast to some JSCallable here...
1940 return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001942 if (strict_mode == kNonStrictMode) {
1943 return value;
1944 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001945 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001946 Handle<Object> holder_handle(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001948 return isolate->Throw(
1949 *isolate->factory()->NewTypeError("no_setter_in_callback",
1950 HandleVector(args, 2)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001952 }
1953
1954 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001955 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956}
1957
1958
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001959MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
1960 Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001961 Isolate* isolate = GetIsolate();
1962 Handle<Object> value_handle(value, isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001963 Handle<JSReceiver> fun(setter, isolate);
1964 Handle<JSReceiver> self(this, isolate);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001965#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001966 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001967 // Handle stepping into a setter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001968 // TODO(rossberg): should this apply to getters that are function proxies?
1969 if (debug->StepInActive() && fun->IsJSFunction()) {
1970 debug->HandleStepIn(
1971 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001972 }
1973#endif
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001974 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001975 Handle<Object> argv[] = { value_handle };
1976 Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001977 // Check for pending exception and return the result.
1978 if (has_pending_exception) return Failure::Exception();
1979 return *value_handle;
1980}
1981
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001982
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001983MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
1984 uint32_t index,
1985 Object* value,
1986 bool* found,
1987 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001988 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001989 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001990 pt != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001991 pt = pt->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001992 if (pt->IsJSProxy()) {
1993 String* name;
1994 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
1995 if (!maybe->To<String>(&name)) {
1996 *found = true; // Force abort
1997 return maybe;
1998 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001999 return JSProxy::cast(pt)->SetPropertyViaPrototypesWithHandler(
verwaest@chromium.org37141392012-05-31 13:27:02 +00002000 this, name, value, NONE, strict_mode, found);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002001 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002002 if (!JSObject::cast(pt)->HasDictionaryElements()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002003 continue;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002004 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002005 SeededNumberDictionary* dictionary =
2006 JSObject::cast(pt)->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002007 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002008 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002009 PropertyDetails details = dictionary->DetailsAt(entry);
2010 if (details.type() == CALLBACKS) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002011 *found = true;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002012 return SetElementWithCallback(dictionary->ValueAt(entry),
2013 index,
2014 value,
2015 JSObject::cast(pt),
2016 strict_mode);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002017 }
2018 }
2019 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002020 *found = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002021 return heap->the_hole_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002022}
2023
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002024MaybeObject* JSObject::SetPropertyViaPrototypes(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002025 String* name,
2026 Object* value,
2027 PropertyAttributes attributes,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002028 StrictModeFlag strict_mode,
2029 bool* done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002030 Heap* heap = GetHeap();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002031 Isolate* isolate = heap->isolate();
2032
2033 *done = false;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002034 // We could not find a local property so let's check whether there is an
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002035 // accessor that wants to handle the property, or whether the property is
2036 // read-only on the prototype chain.
2037 LookupResult result(isolate);
2038 LookupRealNamedPropertyInPrototypes(name, &result);
2039 if (result.IsFound()) {
2040 switch (result.type()) {
2041 case NORMAL:
2042 case FIELD:
2043 case CONSTANT_FUNCTION:
2044 *done = result.IsReadOnly();
2045 break;
2046 case INTERCEPTOR: {
2047 PropertyAttributes attr =
2048 result.holder()->GetPropertyAttributeWithInterceptor(
2049 this, name, true);
2050 *done = !!(attr & READ_ONLY);
2051 break;
2052 }
2053 case CALLBACKS: {
2054 if (!FLAG_es5_readonly && result.IsReadOnly()) break;
2055 *done = true;
2056 return SetPropertyWithCallback(result.GetCallbackObject(),
2057 name, value, result.holder(), strict_mode);
2058 }
2059 case HANDLER: {
2060 return result.proxy()->SetPropertyViaPrototypesWithHandler(
2061 this, name, value, attributes, strict_mode, done);
2062 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002063 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002064 case NONEXISTENT:
2065 UNREACHABLE();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002066 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002067 }
2068 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002069
2070 // If we get here with *done true, we have encountered a read-only property.
2071 if (!FLAG_es5_readonly) *done = false;
2072 if (*done) {
2073 if (strict_mode == kNonStrictMode) return value;
2074 Handle<Object> args[] = { Handle<Object>(name), Handle<Object>(this)};
2075 return isolate->Throw(*isolate->factory()->NewTypeError(
2076 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
2077 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002078 return heap->the_hole_value();
2079}
2080
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002081
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002082void Map::LookupDescriptor(JSObject* holder,
2083 String* name,
2084 LookupResult* result) {
2085 DescriptorArray* descriptors = this->instance_descriptors();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002086 int number = descriptors->SearchWithCache(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002087 if (number != DescriptorArray::kNotFound) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002088 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002089 } else {
2090 result->NotFound();
2091 }
2092}
2093
2094
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002095void Map::LookupTransition(JSObject* holder,
2096 String* name,
2097 LookupResult* result) {
2098 if (HasTransitionArray()) {
2099 TransitionArray* transition_array = transitions();
2100 int number = transition_array->Search(name);
2101 if (number != TransitionArray::kNotFound) {
2102 return result->TransitionResult(holder, number);
2103 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002104 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002105 result->NotFound();
2106}
2107
2108
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002109static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2110 ASSERT(!map.is_null());
2111 for (int i = 0; i < maps->length(); ++i) {
2112 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2113 }
2114 return false;
2115}
2116
2117
2118template <class T>
2119static Handle<T> MaybeNull(T* p) {
2120 if (p == NULL) return Handle<T>::null();
2121 return Handle<T>(p);
2122}
2123
2124
2125Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002126 ElementsKind kind = elements_kind();
2127 Handle<Map> transitioned_map = Handle<Map>::null();
2128 Handle<Map> current_map(this);
2129 bool packed = IsFastPackedElementsKind(kind);
2130 if (IsTransitionableFastElementsKind(kind)) {
2131 while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) {
2132 kind = GetNextMoreGeneralFastElementsKind(kind, false);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002133 Handle<Map> maybe_transitioned_map =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002134 MaybeNull(current_map->LookupElementsTransitionMap(kind));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002135 if (maybe_transitioned_map.is_null()) break;
2136 if (ContainsMap(candidates, maybe_transitioned_map) &&
2137 (packed || !IsFastPackedElementsKind(kind))) {
2138 transitioned_map = maybe_transitioned_map;
2139 if (!IsFastPackedElementsKind(kind)) packed = false;
2140 }
2141 current_map = maybe_transitioned_map;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002142 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002143 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002144 return transitioned_map;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002145}
2146
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002147
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002148static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
2149 Map* current_map = map;
2150 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
verwaest@chromium.org50915592012-06-18 12:15:44 +00002151 int to_index = IsFastElementsKind(to_kind)
2152 ? GetSequenceIndexFromFastElementsKind(to_kind)
2153 : GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
2154
2155 ASSERT(index <= to_index);
2156
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002157 for (; index < to_index; ++index) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002158 if (!current_map->HasElementsTransition()) return current_map;
2159 current_map = current_map->elements_transition_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002160 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002161 if (!IsFastElementsKind(to_kind) && current_map->HasElementsTransition()) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00002162 Map* next_map = current_map->elements_transition_map();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002163 if (next_map->elements_kind() == to_kind) return next_map;
verwaest@chromium.org50915592012-06-18 12:15:44 +00002164 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002165 ASSERT(IsFastElementsKind(to_kind)
2166 ? current_map->elements_kind() == to_kind
2167 : current_map->elements_kind() == TERMINAL_FAST_ELEMENTS_KIND);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002168 return current_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002169}
2170
2171
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002172Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00002173 Map* to_map = FindClosestElementsTransition(this, to_kind);
2174 if (to_map->elements_kind() == to_kind) return to_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002175 return NULL;
2176}
2177
2178
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002179static MaybeObject* AddMissingElementsTransitions(Map* map,
2180 ElementsKind to_kind) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00002181 ASSERT(IsFastElementsKind(map->elements_kind()));
2182 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
2183 int to_index = IsFastElementsKind(to_kind)
2184 ? GetSequenceIndexFromFastElementsKind(to_kind)
2185 : GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
2186
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002187 ASSERT(index <= to_index);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002188
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002189 Map* current_map = map;
2190
verwaest@chromium.org50915592012-06-18 12:15:44 +00002191 for (; index < to_index; ++index) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002192 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1);
2193 MaybeObject* maybe_next_map =
2194 current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
2195 if (!maybe_next_map->To(&current_map)) return maybe_next_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002196 }
2197
verwaest@chromium.org50915592012-06-18 12:15:44 +00002198 // In case we are exiting the fast elements kind system, just add the map in
2199 // the end.
2200 if (!IsFastElementsKind(to_kind)) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002201 MaybeObject* maybe_next_map =
2202 current_map->CopyAsElementsKind(to_kind, INSERT_TRANSITION);
2203 if (!maybe_next_map->To(&current_map)) return maybe_next_map;
verwaest@chromium.org50915592012-06-18 12:15:44 +00002204 }
2205
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002206 ASSERT(current_map->elements_kind() == to_kind);
2207 return current_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002208}
2209
2210
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002211Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
2212 ElementsKind to_kind) {
2213 Isolate* isolate = object->GetIsolate();
2214 CALL_HEAP_FUNCTION(isolate,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002215 object->GetElementsTransitionMap(isolate, to_kind),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002216 Map);
2217}
2218
2219
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002220MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002221 Map* start_map = map();
2222 ElementsKind from_kind = start_map->elements_kind();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002223
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002224 if (from_kind == to_kind) {
2225 return start_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002226 }
2227
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002228 bool allow_store_transition =
2229 // Only remember the map transition if the object's map is NOT equal to
2230 // the global object_function's map and there is not an already existing
2231 // non-matching element transition.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002232 (GetIsolate()->empty_object_map() != map()) &&
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002233 !start_map->IsUndefined() && !start_map->is_shared() &&
verwaest@chromium.org50915592012-06-18 12:15:44 +00002234 IsFastElementsKind(from_kind);
2235
2236 // Only store fast element maps in ascending generality.
2237 if (IsFastElementsKind(to_kind)) {
2238 allow_store_transition &=
2239 IsTransitionableFastElementsKind(from_kind) &&
2240 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
2241 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002242
2243 if (!allow_store_transition) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002244 return start_map->CopyAsElementsKind(to_kind, OMIT_TRANSITION);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002245 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002246
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002247 Map* closest_map = FindClosestElementsTransition(start_map, to_kind);
2248
2249 if (closest_map->elements_kind() == to_kind) {
2250 return closest_map;
2251 }
2252
2253 return AddMissingElementsTransitions(closest_map, to_kind);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002254}
2255
2256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002257void JSObject::LocalLookupRealNamedProperty(String* name,
2258 LookupResult* result) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002259 if (IsJSGlobalProxy()) {
2260 Object* proto = GetPrototype();
2261 if (proto->IsNull()) return result->NotFound();
2262 ASSERT(proto->IsJSGlobalObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002263 // A GlobalProxy's prototype should always be a proper JSObject.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002264 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2265 }
2266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002267 if (HasFastProperties()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002268 map()->LookupDescriptor(this, name, result);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002269 // A property or a map transition was found. We return all of these result
2270 // types because LocalLookupRealNamedProperty is used when setting
2271 // properties where map transitions are handled.
2272 ASSERT(!result->IsFound() ||
2273 (result->holder() == this && result->IsFastPropertyType()));
2274 // Disallow caching for uninitialized constants. These can only
2275 // occur as fields.
2276 if (result->IsField() &&
2277 result->IsReadOnly() &&
2278 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2279 result->DisallowCaching();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002280 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002281 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002282 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002283
2284 int entry = property_dictionary()->FindEntry(name);
2285 if (entry != StringDictionary::kNotFound) {
2286 Object* value = property_dictionary()->ValueAt(entry);
2287 if (IsGlobalObject()) {
2288 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2289 if (d.IsDeleted()) {
2290 result->NotFound();
2291 return;
2292 }
2293 value = JSGlobalPropertyCell::cast(value)->value();
2294 }
2295 // Make sure to disallow caching for uninitialized constants
2296 // found in the dictionary-mode objects.
2297 if (value->IsTheHole()) result->DisallowCaching();
2298 result->DictionaryResult(this, entry);
2299 return;
2300 }
2301
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002302 result->NotFound();
2303}
2304
2305
2306void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2307 LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002308 if (result->IsFound()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002309
2310 LookupRealNamedPropertyInPrototypes(name, result);
2311}
2312
2313
2314void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2315 LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002316 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002317 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002318 pt != heap->null_value();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002319 pt = pt->GetPrototype()) {
2320 if (pt->IsJSProxy()) {
2321 return result->HandlerResult(JSProxy::cast(pt));
2322 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002323 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002324 ASSERT(!(result->IsFound() && result->type() == INTERCEPTOR));
2325 if (result->IsFound()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002326 }
2327 result->NotFound();
2328}
2329
2330
2331// We only need to deal with CALLBACKS and INTERCEPTORS
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002332MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2333 LookupResult* result,
2334 String* name,
2335 Object* value,
2336 bool check_prototype,
2337 StrictModeFlag strict_mode) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002338 if (check_prototype && !result->IsProperty()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002339 LookupRealNamedPropertyInPrototypes(name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002340 }
2341
2342 if (result->IsProperty()) {
2343 if (!result->IsReadOnly()) {
2344 switch (result->type()) {
2345 case CALLBACKS: {
2346 Object* obj = result->GetCallbackObject();
2347 if (obj->IsAccessorInfo()) {
2348 AccessorInfo* info = AccessorInfo::cast(obj);
2349 if (info->all_can_write()) {
2350 return SetPropertyWithCallback(result->GetCallbackObject(),
2351 name,
2352 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002353 result->holder(),
2354 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002355 }
2356 }
2357 break;
2358 }
2359 case INTERCEPTOR: {
2360 // Try lookup real named properties. Note that only property can be
2361 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002362 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002363 LookupRealNamedProperty(name, &r);
2364 if (r.IsProperty()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002365 return SetPropertyWithFailedAccessCheck(&r,
2366 name,
2367 value,
2368 check_prototype,
2369 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002370 }
2371 break;
2372 }
2373 default: {
2374 break;
2375 }
2376 }
2377 }
2378 }
2379
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002380 Isolate* isolate = GetIsolate();
2381 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002382 Handle<Object> value_handle(value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002383 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002384 return *value_handle;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002385}
2386
2387
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002388MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2389 String* key,
2390 Object* value,
2391 PropertyAttributes attributes,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002392 StrictModeFlag strict_mode,
2393 JSReceiver::StoreFromKeyed store_mode) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002394 if (result->IsHandler()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002395 return result->proxy()->SetPropertyWithHandler(
verwaest@chromium.org37141392012-05-31 13:27:02 +00002396 this, key, value, attributes, strict_mode);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002397 } else {
2398 return JSObject::cast(this)->SetPropertyForResult(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002399 result, key, value, attributes, strict_mode, store_mode);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002400 }
2401}
2402
2403
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002404bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2405 Isolate* isolate = GetIsolate();
2406 HandleScope scope(isolate);
2407 Handle<Object> receiver(this);
2408 Handle<Object> name(name_raw);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002409
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002410 Handle<Object> args[] = { name };
2411 Handle<Object> result = CallTrap(
2412 "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002413 if (isolate->has_pending_exception()) return false;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002414
2415 return result->ToBoolean()->IsTrue();
2416}
2417
2418
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002419MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
verwaest@chromium.org37141392012-05-31 13:27:02 +00002420 JSReceiver* receiver_raw,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002421 String* name_raw,
2422 Object* value_raw,
2423 PropertyAttributes attributes,
2424 StrictModeFlag strict_mode) {
2425 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002426 HandleScope scope(isolate);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002427 Handle<JSReceiver> receiver(receiver_raw);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002428 Handle<Object> name(name_raw);
2429 Handle<Object> value(value_raw);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002430
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002431 Handle<Object> args[] = { receiver, name, value };
2432 CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002433 if (isolate->has_pending_exception()) return Failure::Exception();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002434
2435 return *value;
2436}
2437
2438
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002439MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler(
verwaest@chromium.org37141392012-05-31 13:27:02 +00002440 JSReceiver* receiver_raw,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002441 String* name_raw,
2442 Object* value_raw,
2443 PropertyAttributes attributes,
2444 StrictModeFlag strict_mode,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002445 bool* done) {
2446 Isolate* isolate = GetIsolate();
rossberg@chromium.org052b24a2012-06-11 12:32:17 +00002447 Handle<JSProxy> proxy(this);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002448 Handle<JSReceiver> receiver(receiver_raw);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002449 Handle<String> name(name_raw);
2450 Handle<Object> value(value_raw);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002451 Handle<Object> handler(this->handler()); // Trap might morph proxy.
2452
2453 *done = true; // except where redefined...
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002454 Handle<Object> args[] = { name };
2455 Handle<Object> result = proxy->CallTrap(
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002456 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002457 if (isolate->has_pending_exception()) return Failure::Exception();
2458
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002459 if (result->IsUndefined()) {
2460 *done = false;
2461 return GetHeap()->the_hole_value();
rossberg@chromium.org400388e2012-06-06 09:29:22 +00002462 }
2463
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002464 // Emulate [[GetProperty]] semantics for proxies.
2465 bool has_pending_exception;
2466 Handle<Object> argv[] = { result };
2467 Handle<Object> desc =
2468 Execution::Call(isolate->to_complete_property_descriptor(), result,
2469 ARRAY_SIZE(argv), argv, &has_pending_exception);
2470 if (has_pending_exception) return Failure::Exception();
2471
2472 // [[GetProperty]] requires to check that all properties are configurable.
2473 Handle<String> configurable_name =
2474 isolate->factory()->LookupAsciiSymbol("configurable_");
2475 Handle<Object> configurable(
2476 v8::internal::GetProperty(desc, configurable_name));
2477 ASSERT(!isolate->has_pending_exception());
2478 ASSERT(configurable->IsTrue() || configurable->IsFalse());
2479 if (configurable->IsFalse()) {
2480 Handle<String> trap =
2481 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2482 Handle<Object> args[] = { handler, trap, name };
2483 Handle<Object> error = isolate->factory()->NewTypeError(
2484 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2485 return isolate->Throw(*error);
2486 }
2487 ASSERT(configurable->IsTrue());
2488
2489 // Check for DataDescriptor.
2490 Handle<String> hasWritable_name =
2491 isolate->factory()->LookupAsciiSymbol("hasWritable_");
2492 Handle<Object> hasWritable(v8::internal::GetProperty(desc, hasWritable_name));
2493 ASSERT(!isolate->has_pending_exception());
2494 ASSERT(hasWritable->IsTrue() || hasWritable->IsFalse());
2495 if (hasWritable->IsTrue()) {
2496 Handle<String> writable_name =
2497 isolate->factory()->LookupAsciiSymbol("writable_");
2498 Handle<Object> writable(v8::internal::GetProperty(desc, writable_name));
2499 ASSERT(!isolate->has_pending_exception());
2500 ASSERT(writable->IsTrue() || writable->IsFalse());
2501 *done = writable->IsFalse();
2502 if (!*done) return GetHeap()->the_hole_value();
2503 if (strict_mode == kNonStrictMode) return *value;
2504 Handle<Object> args[] = { name, receiver };
2505 Handle<Object> error = isolate->factory()->NewTypeError(
2506 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
2507 return isolate->Throw(*error);
2508 }
2509
2510 // We have an AccessorDescriptor.
2511 Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
2512 Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
2513 ASSERT(!isolate->has_pending_exception());
2514 if (!setter->IsUndefined()) {
2515 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2516 return receiver->SetPropertyWithDefinedSetter(
2517 JSReceiver::cast(*setter), *value);
2518 }
2519
2520 if (strict_mode == kNonStrictMode) return *value;
2521 Handle<Object> args2[] = { name, proxy };
2522 Handle<Object> error = isolate->factory()->NewTypeError(
2523 "no_setter_in_callback", HandleVector(args2, ARRAY_SIZE(args2)));
2524 return isolate->Throw(*error);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002525}
2526
2527
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002528MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2529 String* name_raw, DeleteMode mode) {
2530 Isolate* isolate = GetIsolate();
2531 HandleScope scope(isolate);
2532 Handle<Object> receiver(this);
2533 Handle<Object> name(name_raw);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002534
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002535 Handle<Object> args[] = { name };
2536 Handle<Object> result = CallTrap(
2537 "delete", Handle<Object>(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002538 if (isolate->has_pending_exception()) return Failure::Exception();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002539
2540 Object* bool_result = result->ToBoolean();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002541 if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
2542 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2543 Handle<Object> args[] = { Handle<Object>(handler()), trap_name };
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002544 Handle<Object> error = isolate->factory()->NewTypeError(
2545 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2546 isolate->Throw(*error);
2547 return Failure::Exception();
2548 }
2549 return bool_result;
2550}
2551
2552
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002553MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
2554 uint32_t index,
2555 DeleteMode mode) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002556 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002557 HandleScope scope(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002558 Handle<String> name = isolate->factory()->Uint32ToString(index);
2559 return JSProxy::DeletePropertyWithHandler(*name, mode);
2560}
2561
2562
2563MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2564 JSReceiver* receiver_raw,
2565 String* name_raw) {
2566 Isolate* isolate = GetIsolate();
2567 HandleScope scope(isolate);
2568 Handle<JSProxy> proxy(this);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002569 Handle<Object> handler(this->handler()); // Trap might morph proxy.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002570 Handle<JSReceiver> receiver(receiver_raw);
2571 Handle<Object> name(name_raw);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002572
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002573 Handle<Object> args[] = { name };
2574 Handle<Object> result = CallTrap(
2575 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002576 if (isolate->has_pending_exception()) return NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002577
2578 if (result->IsUndefined()) return ABSENT;
2579
2580 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002581 Handle<Object> argv[] = { result };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002582 Handle<Object> desc =
2583 Execution::Call(isolate->to_complete_property_descriptor(), result,
2584 ARRAY_SIZE(argv), argv, &has_pending_exception);
2585 if (has_pending_exception) return NONE;
2586
2587 // Convert result to PropertyAttributes.
2588 Handle<String> enum_n = isolate->factory()->LookupAsciiSymbol("enumerable");
2589 Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_n));
2590 if (isolate->has_pending_exception()) return NONE;
2591 Handle<String> conf_n = isolate->factory()->LookupAsciiSymbol("configurable");
2592 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_n));
2593 if (isolate->has_pending_exception()) return NONE;
2594 Handle<String> writ_n = isolate->factory()->LookupAsciiSymbol("writable");
2595 Handle<Object> writable(v8::internal::GetProperty(desc, writ_n));
2596 if (isolate->has_pending_exception()) return NONE;
2597
2598 if (configurable->IsFalse()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002599 Handle<String> trap =
2600 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2601 Handle<Object> args[] = { handler, trap, name };
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002602 Handle<Object> error = isolate->factory()->NewTypeError(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002603 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002604 isolate->Throw(*error);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002605 return NONE;
2606 }
2607
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002608 int attributes = NONE;
2609 if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM;
2610 if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE;
2611 if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY;
2612 return static_cast<PropertyAttributes>(attributes);
2613}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002614
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002615
2616MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
2617 JSReceiver* receiver,
2618 uint32_t index) {
2619 Isolate* isolate = GetIsolate();
2620 HandleScope scope(isolate);
2621 Handle<String> name = isolate->factory()->Uint32ToString(index);
2622 return GetPropertyAttributeWithHandler(receiver, *name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002623}
2624
2625
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002626void JSProxy::Fix() {
2627 Isolate* isolate = GetIsolate();
2628 HandleScope scope(isolate);
2629 Handle<JSProxy> self(this);
2630
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002631 // Save identity hash.
2632 MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
2633
lrn@chromium.org34e60782011-09-15 07:25:40 +00002634 if (IsJSFunctionProxy()) {
2635 isolate->factory()->BecomeJSFunction(self);
2636 // Code will be set on the JavaScript side.
2637 } else {
2638 isolate->factory()->BecomeJSObject(self);
2639 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00002640 ASSERT(self->IsJSObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002641
2642 // Inherit identity, if it was present.
2643 Object* hash;
2644 if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
2645 Handle<JSObject> new_self(JSObject::cast(*self));
2646 isolate->factory()->SetIdentityHash(new_self, hash);
2647 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002648}
2649
2650
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002651MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
2652 Handle<Object> derived,
2653 int argc,
2654 Handle<Object> argv[]) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002655 Isolate* isolate = GetIsolate();
2656 Handle<Object> handler(this->handler());
2657
2658 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol(name);
2659 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2660 if (isolate->has_pending_exception()) return trap;
2661
2662 if (trap->IsUndefined()) {
2663 if (derived.is_null()) {
2664 Handle<Object> args[] = { handler, trap_name };
2665 Handle<Object> error = isolate->factory()->NewTypeError(
2666 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2667 isolate->Throw(*error);
2668 return Handle<Object>();
2669 }
2670 trap = Handle<Object>(derived);
2671 }
2672
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002673 bool threw;
2674 return Execution::Call(trap, handler, argc, argv, &threw);
2675}
2676
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002677
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002678MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002679 String* name_raw,
2680 Object* value_raw,
whesse@chromium.org030d38e2011-07-13 13:23:34 +00002681 PropertyAttributes attributes,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002682 StrictModeFlag strict_mode,
2683 StoreFromKeyed store_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002684 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002685 // Make sure that the top context does not change when doing callbacks or
2686 // interceptor calls.
2687 AssertNoContextChange ncc;
2688
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002689 // Optimization for 2-byte strings often used as keys in a decompression
2690 // dictionary. We make these short keys into symbols to avoid constantly
2691 // reallocating them.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002692 if (!name_raw->IsSymbol() && name_raw->length() <= 2) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002693 Object* symbol_version;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002694 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name_raw);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002695 if (maybe_symbol_version->ToObject(&symbol_version)) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002696 name_raw = String::cast(symbol_version);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002697 }
2698 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002699 }
2700
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002701 // Check access rights if needed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002702 if (IsAccessCheckNeeded()) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002703 if (!heap->isolate()->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002704 return SetPropertyWithFailedAccessCheck(
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002705 result, name_raw, value_raw, true, strict_mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002706 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002707 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002708
2709 if (IsJSGlobalProxy()) {
2710 Object* proto = GetPrototype();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002711 if (proto->IsNull()) return value_raw;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002712 ASSERT(proto->IsJSGlobalObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002713 return JSObject::cast(proto)->SetPropertyForResult(
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002714 result, name_raw, value_raw, attributes, strict_mode, store_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002715 }
2716
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002717 // From this point on everything needs to be handlified, because
2718 // SetPropertyViaPrototypes might call back into JavaScript.
2719 HandleScope scope(GetIsolate());
2720 Handle<JSObject> self(this);
2721 Handle<String> name(name_raw);
2722 Handle<Object> value(value_raw);
2723
2724 if (!result->IsProperty() && !self->IsJSContextExtensionObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002725 bool done = false;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002726 MaybeObject* result_object = self->SetPropertyViaPrototypes(
2727 *name, *value, attributes, strict_mode, &done);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002728 if (done) return result_object;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002729 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002730
ager@chromium.org5c838252010-02-19 08:53:10 +00002731 if (!result->IsFound()) {
2732 // Neither properties nor transitions found.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002733 return self->AddProperty(
2734 *name, *value, attributes, strict_mode, store_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002735 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002736 if (result->IsProperty() && result->IsReadOnly()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002737 if (strict_mode == kStrictMode) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002738 Handle<Object> args[] = { name, self };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002739 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002740 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002741 } else {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002742 return *value;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002743 }
2744 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002745
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002746 // This is a real property that is not read-only, or it is a
2747 // transition or null descriptor and there are no setters in the prototypes.
2748 switch (result->type()) {
2749 case NORMAL:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002750 return self->SetNormalizedProperty(result, *value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002751 case FIELD:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002752 return self->FastPropertyAtPut(result->GetFieldIndex(), *value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002753 case CONSTANT_FUNCTION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002754 // Only replace the function if necessary.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002755 if (*value == result->GetConstantFunction()) return *value;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002756 // Preserve the attributes of this existing property.
2757 attributes = result->GetAttributes();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002758 return self->ConvertDescriptorToField(*name, *value, attributes);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002759 case CALLBACKS: {
2760 Object* callback_object = result->GetCallbackObject();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002761 return self->SetPropertyWithCallback(callback_object,
2762 *name,
2763 *value,
2764 result->holder(),
2765 strict_mode);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002766 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002767 case INTERCEPTOR:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002768 return self->SetPropertyWithInterceptor(*name,
2769 *value,
2770 attributes,
2771 strict_mode);
2772 case TRANSITION: {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002773 Map* transition_map = result->GetTransitionTarget();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002774
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002775 DescriptorArray* descriptors = transition_map->instance_descriptors();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00002776 int descriptor = descriptors->LastAdded();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002777 PropertyDetails details = descriptors->GetDetails(descriptor);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002778
2779 if (details.type() == FIELD) {
2780 if (attributes == details.attributes()) {
2781 int field_index = descriptors->GetFieldIndex(descriptor);
2782 return self->AddFastPropertyUsingMap(transition_map,
2783 *name,
2784 *value,
2785 field_index);
2786 }
2787 return self->ConvertDescriptorToField(*name, *value, attributes);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002788 } else if (details.type() == CALLBACKS) {
2789 return ConvertDescriptorToField(*name, *value, attributes);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002790 }
2791
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002792 ASSERT(details.type() == CONSTANT_FUNCTION);
2793
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002794 Object* constant_function = descriptors->GetValue(descriptor);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002795 // If the same constant function is being added we can simply
2796 // transition to the target map.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002797 if (constant_function == *value) {
2798 self->set_map(transition_map);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002799 return constant_function;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002800 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002801 // Otherwise, replace with a map transition to a new map with a FIELD,
2802 // even if the value is a constant function.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002803 return ConvertTransitionToMapTransition(
2804 result->GetTransitionIndex(), *name, *value, attributes);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002805 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00002806 case HANDLER:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002807 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002808 UNREACHABLE();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002809 return *value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002810 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00002811 UNREACHABLE(); // keep the compiler happy
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002812 return *value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002813}
2814
2815
2816// Set a real local property, even if it is READ_ONLY. If the property is not
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002817// present, add it with attributes NONE. This code is an exact clone of
2818// SetProperty, with the check for IsReadOnly and the check for a
2819// callback setter removed. The two lines looking up the LookupResult
2820// result are also added. If one of the functions is changed, the other
2821// should be.
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002822// Note that this method cannot be used to set the prototype of a function
2823// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
2824// doesn't handle function prototypes correctly.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002825Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
2826 Handle<JSObject> object,
2827 Handle<String> key,
2828 Handle<Object> value,
2829 PropertyAttributes attributes) {
2830 CALL_HEAP_FUNCTION(
2831 object->GetIsolate(),
2832 object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
2833 Object);
2834}
2835
2836
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002837MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002838 String* name,
2839 Object* value,
2840 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002841 // Make sure that the top context does not change when doing callbacks or
2842 // interceptor calls.
2843 AssertNoContextChange ncc;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002844 Isolate* isolate = GetIsolate();
2845 LookupResult result(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00002846 LocalLookup(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002847 if (!result.IsFound()) map()->LookupTransition(this, name, &result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002848 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002849 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002850 if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002851 return SetPropertyWithFailedAccessCheck(&result,
2852 name,
2853 value,
2854 false,
2855 kNonStrictMode);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002856 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002857 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002858
2859 if (IsJSGlobalProxy()) {
2860 Object* proto = GetPrototype();
2861 if (proto->IsNull()) return value;
2862 ASSERT(proto->IsJSGlobalObject());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002863 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002864 name,
2865 value,
2866 attributes);
2867 }
2868
ager@chromium.org7c537e22008-10-16 08:43:32 +00002869 // Check for accessor in prototype chain removed here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00002870 if (!result.IsFound()) {
2871 // Neither properties nor transitions found.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002872 return AddProperty(name, value, attributes, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002873 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002874
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002875 // Check of IsReadOnly removed from here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00002876 switch (result.type()) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002877 case NORMAL: {
2878 PropertyDetails details = PropertyDetails(attributes, NORMAL);
ager@chromium.org5c838252010-02-19 08:53:10 +00002879 return SetNormalizedProperty(name, value, details);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002880 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002881 case FIELD:
ager@chromium.org5c838252010-02-19 08:53:10 +00002882 return FastPropertyAtPut(result.GetFieldIndex(), value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002883 case CONSTANT_FUNCTION:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002884 // Only replace the function if necessary.
ager@chromium.org5c838252010-02-19 08:53:10 +00002885 if (value == result.GetConstantFunction()) return value;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002886 // Preserve the attributes of this existing property.
ager@chromium.org5c838252010-02-19 08:53:10 +00002887 attributes = result.GetAttributes();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002888 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002889 case CALLBACKS:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002890 case INTERCEPTOR:
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002891 // Override callback in clone
2892 return ConvertDescriptorToField(name, value, attributes);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002893 case TRANSITION: {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002894 Map* transition_map = result.GetTransitionTarget();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002895
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002896 DescriptorArray* descriptors = transition_map->instance_descriptors();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00002897 int descriptor = descriptors->LastAdded();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002898 PropertyDetails details = descriptors->GetDetails(descriptor);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002899
2900 if (details.type() == FIELD) {
2901 if (attributes == details.attributes()) {
2902 int field_index = descriptors->GetFieldIndex(descriptor);
2903 return AddFastPropertyUsingMap(transition_map,
2904 name,
2905 value,
2906 field_index);
2907 }
2908 return ConvertDescriptorToField(name, value, attributes);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002909 } else if (details.type() == CALLBACKS) {
2910 return ConvertDescriptorToField(name, value, attributes);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002911 }
2912
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002913 ASSERT(details.type() == CONSTANT_FUNCTION);
2914
2915 // Replace transition to CONSTANT FUNCTION with a map transition to a new
2916 // map with a FIELD, even if the value is a function.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002917 return ConvertTransitionToMapTransition(
2918 result.GetTransitionIndex(), name, value, attributes);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002919 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00002920 case HANDLER:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002921 case NONEXISTENT:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002922 UNREACHABLE();
2923 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00002924 UNREACHABLE(); // keep the compiler happy
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002925 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002926}
2927
2928
2929PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
2930 JSObject* receiver,
2931 String* name,
2932 bool continue_search) {
2933 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002934 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002935 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002936 if (result.IsFound()) return result.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002937
2938 if (continue_search) {
2939 // Continue searching via the prototype chain.
2940 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002941 if (!pt->IsNull()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002942 return JSObject::cast(pt)->
2943 GetPropertyAttributeWithReceiver(receiver, name);
2944 }
2945 }
2946 return ABSENT;
2947}
2948
2949
2950PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2951 JSObject* receiver,
2952 String* name,
2953 bool continue_search) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002954 Isolate* isolate = GetIsolate();
2955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002956 // Make sure that the top context does not change when doing
2957 // callbacks or interceptor calls.
2958 AssertNoContextChange ncc;
2959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002960 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002961 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2962 Handle<JSObject> receiver_handle(receiver);
2963 Handle<JSObject> holder_handle(this);
2964 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002965 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002966 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002967 if (!interceptor->query()->IsUndefined()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002968 v8::NamedPropertyQuery query =
2969 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002970 LOG(isolate,
2971 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002972 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002973 {
2974 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002975 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002976 result = query(v8::Utils::ToLocal(name_handle), info);
2977 }
2978 if (!result.IsEmpty()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002979 ASSERT(result->IsInt32());
2980 return static_cast<PropertyAttributes>(result->Int32Value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002981 }
2982 } else if (!interceptor->getter()->IsUndefined()) {
2983 v8::NamedPropertyGetter getter =
2984 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002985 LOG(isolate,
2986 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002987 v8::Handle<v8::Value> result;
2988 {
2989 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002990 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002991 result = getter(v8::Utils::ToLocal(name_handle), info);
2992 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002993 if (!result.IsEmpty()) return DONT_ENUM;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002994 }
2995 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2996 *name_handle,
2997 continue_search);
2998}
2999
3000
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003001PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
3002 JSReceiver* receiver,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003003 String* key) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003004 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003005 if (IsJSObject() && key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003006 return JSObject::cast(this)->HasElementWithReceiver(receiver, index)
3007 ? NONE : ABSENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003008 }
3009 // Named property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003010 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003011 Lookup(key, &result);
3012 return GetPropertyAttribute(receiver, &result, key, true);
3013}
3014
3015
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003016PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
3017 LookupResult* result,
3018 String* name,
3019 bool continue_search) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003020 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003021 if (IsAccessCheckNeeded()) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003022 JSObject* this_obj = JSObject::cast(this);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003023 Heap* heap = GetHeap();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003024 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
3025 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
3026 receiver, result, name, continue_search);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003027 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003028 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003029 if (result->IsFound()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003030 switch (result->type()) {
3031 case NORMAL: // fall through
3032 case FIELD:
3033 case CONSTANT_FUNCTION:
3034 case CALLBACKS:
3035 return result->GetAttributes();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003036 case HANDLER: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003037 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler(
3038 receiver, name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003039 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003040 case INTERCEPTOR:
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003041 return result->holder()->GetPropertyAttributeWithInterceptor(
3042 JSObject::cast(receiver), name, continue_search);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003043 case TRANSITION:
3044 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003045 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003046 }
3047 }
3048 return ABSENT;
3049}
3050
3051
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003052PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003053 // Check whether the name is an array index.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003054 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003055 if (IsJSObject() && name->AsArrayIndex(&index)) {
3056 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003057 return ABSENT;
3058 }
3059 // Named property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003060 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003061 LocalLookup(name, &result);
3062 return GetPropertyAttribute(this, &result, name, false);
3063}
3064
3065
lrn@chromium.org303ada72010-10-27 09:33:13 +00003066MaybeObject* NormalizedMapCache::Get(JSObject* obj,
3067 PropertyNormalizationMode mode) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003068 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003069 Map* fast = obj->map();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003070 int index = fast->Hash() % kEntries;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003071 Object* result = get(index);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003072 if (result->IsMap() &&
3073 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003074#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003075 if (FLAG_verify_heap) {
3076 Map::cast(result)->SharedMapVerify();
3077 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003078 if (FLAG_enable_slow_asserts) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003079 // The cached map should match newly created normalized map bit-by-bit,
3080 // except for the code cache, which can contain some ics which can be
3081 // applied to the shared map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003082 Object* fresh;
3083 { MaybeObject* maybe_fresh =
3084 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3085 if (maybe_fresh->ToObject(&fresh)) {
3086 ASSERT(memcmp(Map::cast(fresh)->address(),
3087 Map::cast(result)->address(),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003088 Map::kCodeCacheOffset) == 0);
3089 int offset = Map::kCodeCacheOffset + kPointerSize;
3090 ASSERT(memcmp(Map::cast(fresh)->address() + offset,
3091 Map::cast(result)->address() + offset,
3092 Map::kSize - offset) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003093 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003094 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003095 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003096#endif
3097 return result;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003098 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003099
lrn@chromium.org303ada72010-10-27 09:33:13 +00003100 { MaybeObject* maybe_result =
3101 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3102 if (!maybe_result->ToObject(&result)) return maybe_result;
3103 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003104 set(index, result);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003105 isolate->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003106
3107 return result;
3108}
3109
3110
ricow@chromium.org65fae842010-08-25 15:26:24 +00003111void NormalizedMapCache::Clear() {
3112 int entries = length();
3113 for (int i = 0; i != entries; i++) {
3114 set_undefined(i);
3115 }
3116}
3117
3118
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003119void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
3120 Handle<String> name,
3121 Handle<Code> code) {
3122 Isolate* isolate = object->GetIsolate();
3123 CALL_HEAP_FUNCTION_VOID(isolate,
3124 object->UpdateMapCodeCache(*name, *code));
3125}
3126
3127
lrn@chromium.org303ada72010-10-27 09:33:13 +00003128MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003129 if (map()->is_shared()) {
3130 // Fast case maps are never marked as shared.
3131 ASSERT(!HasFastProperties());
3132 // Replace the map with an identical copy that can be safely modified.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003133 Object* obj;
3134 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
3135 UNIQUE_NORMALIZED_MAP);
3136 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3137 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003138 GetIsolate()->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003139
3140 set_map(Map::cast(obj));
3141 }
3142 return map()->UpdateCodeCache(name, code);
3143}
3144
3145
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003146void JSObject::NormalizeProperties(Handle<JSObject> object,
3147 PropertyNormalizationMode mode,
3148 int expected_additional_properties) {
3149 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
3150 object->NormalizeProperties(
3151 mode, expected_additional_properties));
3152}
3153
3154
lrn@chromium.org303ada72010-10-27 09:33:13 +00003155MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
3156 int expected_additional_properties) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003157 if (!HasFastProperties()) return this;
3158
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003159 // The global object is always normalized.
3160 ASSERT(!IsGlobalObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003161 // JSGlobalProxy must never be normalized
3162 ASSERT(!IsJSGlobalProxy());
3163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003164 Map* map_of_this = map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003165
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003166 // Allocate new content.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003167 int property_count = map_of_this->NumberOfDescribedProperties();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003168 if (expected_additional_properties > 0) {
3169 property_count += expected_additional_properties;
3170 } else {
3171 property_count += 2; // Make space for two more properties.
3172 }
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003173 StringDictionary* dictionary;
3174 { MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count);
3175 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003176 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003178 DescriptorArray* descs = map_of_this->instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003179 for (int i = 0; i < descs->number_of_descriptors(); i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003180 PropertyDetails details = descs->GetDetails(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003181 switch (details.type()) {
3182 case CONSTANT_FUNCTION: {
3183 PropertyDetails d =
3184 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003185 Object* value = descs->GetConstantFunction(i);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003186 MaybeObject* maybe_dictionary =
3187 dictionary->Add(descs->GetKey(i), value, d);
3188 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003189 break;
3190 }
3191 case FIELD: {
3192 PropertyDetails d =
3193 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003194 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003195 MaybeObject* maybe_dictionary =
3196 dictionary->Add(descs->GetKey(i), value, d);
3197 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003198 break;
3199 }
3200 case CALLBACKS: {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003201 Object* value = descs->GetCallbacksObject(i);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003202 MaybeObject* maybe_dictionary =
3203 dictionary->Add(descs->GetKey(i), value, details);
3204 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003205 break;
3206 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003207 case INTERCEPTOR:
3208 break;
danno@chromium.orgc612e022011-11-10 11:38:15 +00003209 case HANDLER:
3210 case NORMAL:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003211 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003212 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003213 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +00003214 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003215 }
3216 }
3217
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003218 Heap* current_heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003219
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003220 // Copy the next enumeration index from instance descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003221 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003222 dictionary->SetNextEnumerationIndex(index);
3223
ulan@chromium.org65a89c22012-02-14 11:46:07 +00003224 Map* new_map;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00003225 MaybeObject* maybe_map =
3226 current_heap->isolate()->context()->global_context()->
3227 normalized_map_cache()->Get(this, mode);
3228 if (!maybe_map->To(&new_map)) return maybe_map;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003229
ager@chromium.org32912102009-01-16 10:38:43 +00003230 // We have now successfully allocated all the necessary objects.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003231 // Changes can now be made with the guarantee that all of them take effect.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003232
3233 // Resize the object in the heap if necessary.
3234 int new_instance_size = new_map->instance_size();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003235 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003236 ASSERT(instance_size_delta >= 0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003237 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
3238 instance_size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003239 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003240 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
3241 -instance_size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003242 }
3243
ager@chromium.org32912102009-01-16 10:38:43 +00003244 set_map(new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003245
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003246 set_properties(dictionary);
3247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003248 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003249
3250#ifdef DEBUG
3251 if (FLAG_trace_normalization) {
3252 PrintF("Object properties have been normalized:\n");
3253 Print();
3254 }
3255#endif
3256 return this;
3257}
3258
3259
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003260void JSObject::TransformToFastProperties(Handle<JSObject> object,
3261 int unused_property_fields) {
3262 CALL_HEAP_FUNCTION_VOID(
3263 object->GetIsolate(),
3264 object->TransformToFastProperties(unused_property_fields));
3265}
3266
3267
lrn@chromium.org303ada72010-10-27 09:33:13 +00003268MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003269 if (HasFastProperties()) return this;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003270 ASSERT(!IsGlobalObject());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003271 return property_dictionary()->
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003272 TransformPropertiesToFastFor(this, unused_property_fields);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003273}
3274
3275
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003276Handle<SeededNumberDictionary> JSObject::NormalizeElements(
3277 Handle<JSObject> object) {
3278 CALL_HEAP_FUNCTION(object->GetIsolate(),
3279 object->NormalizeElements(),
3280 SeededNumberDictionary);
3281}
3282
3283
lrn@chromium.org303ada72010-10-27 09:33:13 +00003284MaybeObject* JSObject::NormalizeElements() {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003285 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00003286
whesse@chromium.org7b260152011-06-20 15:33:18 +00003287 // Find the backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003288 FixedArrayBase* array = FixedArrayBase::cast(elements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00003289 Map* old_map = array->map();
3290 bool is_arguments =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003291 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
whesse@chromium.org7b260152011-06-20 15:33:18 +00003292 if (is_arguments) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003293 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003294 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00003295 if (array->IsDictionary()) return array;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003296
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003297 ASSERT(HasFastSmiOrObjectElements() ||
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003298 HasFastDoubleElements() ||
3299 HasFastArgumentsElements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00003300 // Compute the effective length and allocate a new backing store.
3301 int length = IsJSArray()
3302 ? Smi::cast(JSArray::cast(this)->length())->value()
3303 : array->length();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00003304 int old_capacity = 0;
3305 int used_elements = 0;
3306 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003307 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003308 { Object* object;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003309 MaybeObject* maybe = SeededNumberDictionary::Allocate(used_elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003310 if (!maybe->ToObject(&object)) return maybe;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003311 dictionary = SeededNumberDictionary::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003312 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00003313
3314 // Copy the elements to the new backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003315 bool has_double_elements = array->IsFixedDoubleArray();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003316 for (int i = 0; i < length; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003317 Object* value = NULL;
3318 if (has_double_elements) {
3319 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
3320 if (double_array->is_the_hole(i)) {
3321 value = GetIsolate()->heap()->the_hole_value();
3322 } else {
3323 // Objects must be allocated in the old object space, since the
3324 // overall number of HeapNumbers needed for the conversion might
3325 // exceed the capacity of new space, and we would fail repeatedly
3326 // trying to convert the FixedDoubleArray.
3327 MaybeObject* maybe_value_object =
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003328 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003329 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003330 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003331 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003332 ASSERT(old_map->has_fast_smi_or_object_elements());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003333 value = FixedArray::cast(array)->get(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003334 }
3335 PropertyDetails details = PropertyDetails(NONE, NORMAL);
3336 if (!value->IsTheHole()) {
3337 Object* result;
3338 MaybeObject* maybe_result =
3339 dictionary->AddNumberEntry(i, value, details);
3340 if (!maybe_result->ToObject(&result)) return maybe_result;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003341 dictionary = SeededNumberDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003342 }
3343 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003344
whesse@chromium.org7b260152011-06-20 15:33:18 +00003345 // Switch to using the dictionary as the backing storage for elements.
3346 if (is_arguments) {
3347 FixedArray::cast(elements())->set(1, dictionary);
3348 } else {
3349 // Set the new map first to satify the elements type assert in
3350 // set_elements().
3351 Object* new_map;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003352 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
3353 DICTIONARY_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003354 if (!maybe->ToObject(&new_map)) return maybe;
3355 set_map(Map::cast(new_map));
3356 set_elements(dictionary);
3357 }
3358
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003359 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
3360 Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003361
3362#ifdef DEBUG
3363 if (FLAG_trace_normalization) {
3364 PrintF("Object elements have been normalized:\n");
3365 Print();
3366 }
3367#endif
3368
whesse@chromium.org7b260152011-06-20 15:33:18 +00003369 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
3370 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003371}
3372
3373
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003374Smi* JSReceiver::GenerateIdentityHash() {
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003375 Isolate* isolate = GetIsolate();
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003376
3377 int hash_value;
3378 int attempts = 0;
3379 do {
3380 // Generate a random 32-bit hash value but limit range to fit
3381 // within a smi.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003382 hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003383 attempts++;
3384 } while (hash_value == 0 && attempts < 30);
3385 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
3386
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003387 return Smi::FromInt(hash_value);
3388}
3389
3390
3391MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
3392 MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3393 hash);
3394 if (maybe->IsFailure()) return maybe;
3395 return this;
3396}
3397
3398
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003399int JSObject::GetIdentityHash(Handle<JSObject> obj) {
3400 CALL_AND_RETRY(obj->GetIsolate(),
3401 obj->GetIdentityHash(ALLOW_CREATION),
3402 return Smi::cast(__object__)->value(),
3403 return 0);
3404}
3405
3406
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003407MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
3408 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
3409 if (stored_value->IsSmi()) return stored_value;
3410
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003411 // Do not generate permanent identity hash code if not requested.
3412 if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
3413
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003414 Smi* hash = GenerateIdentityHash();
3415 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3416 hash);
3417 if (result->IsFailure()) return result;
3418 if (result->ToObjectUnchecked()->IsUndefined()) {
3419 // Trying to get hash of detached proxy.
3420 return Smi::FromInt(0);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003421 }
3422 return hash;
3423}
3424
3425
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003426MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
3427 Object* hash = this->hash();
3428 if (!hash->IsSmi() && flag == ALLOW_CREATION) {
3429 hash = GenerateIdentityHash();
3430 set_hash(hash);
3431 }
3432 return hash;
3433}
3434
3435
3436Object* JSObject::GetHiddenProperty(String* key) {
3437 if (IsJSGlobalProxy()) {
3438 // For a proxy, use the prototype as target object.
3439 Object* proxy_parent = GetPrototype();
3440 // If the proxy is detached, return undefined.
3441 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3442 ASSERT(proxy_parent->IsJSGlobalObject());
3443 return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
3444 }
3445 ASSERT(!IsJSGlobalProxy());
3446 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3447 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3448 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
3449 return GetHeap()->undefined_value();
3450 }
3451 StringDictionary* dictionary =
3452 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3453 int entry = dictionary->FindEntry(key);
3454 if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
3455 return dictionary->ValueAt(entry);
3456}
3457
3458
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003459Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
3460 Handle<String> key,
3461 Handle<Object> value) {
3462 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3463 obj->SetHiddenProperty(*key, *value),
3464 Object);
3465}
3466
3467
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003468MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
3469 if (IsJSGlobalProxy()) {
3470 // For a proxy, use the prototype as target object.
3471 Object* proxy_parent = GetPrototype();
3472 // If the proxy is detached, return undefined.
3473 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3474 ASSERT(proxy_parent->IsJSGlobalObject());
3475 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
3476 }
3477 ASSERT(!IsJSGlobalProxy());
3478 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
3479 StringDictionary* dictionary;
3480 if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
3481
3482 // If it was found, check if the key is already in the dictionary.
3483 int entry = dictionary->FindEntry(key);
3484 if (entry != StringDictionary::kNotFound) {
3485 // If key was found, just update the value.
3486 dictionary->ValueAtPut(entry, value);
3487 return this;
3488 }
3489 // Key was not already in the dictionary, so add the entry.
3490 MaybeObject* insert_result = dictionary->Add(key,
3491 value,
3492 PropertyDetails(NONE, NORMAL));
3493 StringDictionary* new_dict;
3494 if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
3495 if (new_dict != dictionary) {
3496 // If adding the key expanded the dictionary (i.e., Add returned a new
3497 // dictionary), store it back to the object.
3498 MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
3499 if (store_result->IsFailure()) return store_result;
3500 }
3501 // Return this to mark success.
3502 return this;
3503}
3504
3505
3506void JSObject::DeleteHiddenProperty(String* key) {
3507 if (IsJSGlobalProxy()) {
3508 // For a proxy, use the prototype as target object.
3509 Object* proxy_parent = GetPrototype();
3510 // If the proxy is detached, return immediately.
3511 if (proxy_parent->IsNull()) return;
3512 ASSERT(proxy_parent->IsJSGlobalObject());
3513 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
3514 return;
3515 }
3516 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3517 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3518 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
3519 StringDictionary* dictionary =
3520 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3521 int entry = dictionary->FindEntry(key);
3522 if (entry == StringDictionary::kNotFound) {
3523 // Key wasn't in dictionary. Deletion is a success.
3524 return;
3525 }
3526 // Key was in the dictionary. Remove it.
3527 dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
3528}
3529
3530
3531bool JSObject::HasHiddenProperties() {
erik.corry@gmail.comb99cabf2011-10-07 09:45:13 +00003532 return GetPropertyAttributePostInterceptor(this,
3533 GetHeap()->hidden_symbol(),
3534 false) != ABSENT;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003535}
3536
3537
3538MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
3539 ASSERT(!IsJSGlobalProxy());
3540 if (HasFastProperties()) {
3541 // If the object has fast properties, check whether the first slot
3542 // in the descriptor array matches the hidden symbol. Since the
3543 // hidden symbols hash code is zero (and no other string has hash
3544 // code zero) it will always occupy the first entry if present.
3545 DescriptorArray* descriptors = this->map()->instance_descriptors();
3546 if ((descriptors->number_of_descriptors() > 0) &&
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00003547 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003548 ASSERT(descriptors->GetType(0) == FIELD);
3549 Object* hidden_store =
3550 this->FastPropertyAt(descriptors->GetFieldIndex(0));
3551 return StringDictionary::cast(hidden_store);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003552 }
3553 } else {
3554 PropertyAttributes attributes;
3555 // You can't install a getter on a property indexed by the hidden symbol,
3556 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
3557 // object.
3558 Object* lookup =
3559 GetLocalPropertyPostInterceptor(this,
3560 GetHeap()->hidden_symbol(),
3561 &attributes)->ToObjectUnchecked();
3562 if (!lookup->IsUndefined()) {
3563 return StringDictionary::cast(lookup);
3564 }
3565 }
3566 if (!create_if_absent) return GetHeap()->undefined_value();
3567 const int kInitialSize = 5;
3568 MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
3569 StringDictionary* dictionary;
3570 if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00003571 MaybeObject* store_result =
3572 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3573 dictionary,
3574 DONT_ENUM,
3575 kNonStrictMode,
3576 OMIT_EXTENSIBILITY_CHECK);
3577 if (store_result->IsFailure()) return store_result;
3578 return dictionary;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003579}
3580
3581
3582MaybeObject* JSObject::SetHiddenPropertiesDictionary(
3583 StringDictionary* dictionary) {
3584 ASSERT(!IsJSGlobalProxy());
3585 ASSERT(HasHiddenProperties());
3586 if (HasFastProperties()) {
3587 // If the object has fast properties, check whether the first slot
3588 // in the descriptor array matches the hidden symbol. Since the
3589 // hidden symbols hash code is zero (and no other string has hash
3590 // code zero) it will always occupy the first entry if present.
3591 DescriptorArray* descriptors = this->map()->instance_descriptors();
3592 if ((descriptors->number_of_descriptors() > 0) &&
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00003593 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003594 ASSERT(descriptors->GetType(0) == FIELD);
3595 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
3596 return this;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003597 }
3598 }
3599 MaybeObject* store_result =
3600 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3601 dictionary,
3602 DONT_ENUM,
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00003603 kNonStrictMode,
3604 OMIT_EXTENSIBILITY_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003605 if (store_result->IsFailure()) return store_result;
3606 return this;
3607}
3608
3609
lrn@chromium.org303ada72010-10-27 09:33:13 +00003610MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3611 DeleteMode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003612 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003613 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003614 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003615 if (!result.IsFound()) return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616
3617 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003618 Object* obj;
3619 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3620 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3621 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003623 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003624}
3625
3626
lrn@chromium.org303ada72010-10-27 09:33:13 +00003627MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003628 Isolate* isolate = GetIsolate();
3629 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003630 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3631 Handle<String> name_handle(name);
3632 Handle<JSObject> this_handle(this);
3633 if (!interceptor->deleter()->IsUndefined()) {
3634 v8::NamedPropertyDeleter deleter =
3635 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003636 LOG(isolate,
3637 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3638 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003639 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003640 v8::Handle<v8::Boolean> result;
3641 {
3642 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644 result = deleter(v8::Utils::ToLocal(name_handle), info);
3645 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003647 if (!result.IsEmpty()) {
3648 ASSERT(result->IsBoolean());
3649 return *v8::Utils::OpenHandle(*result);
3650 }
3651 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003652 MaybeObject* raw_result =
ager@chromium.orge2902be2009-06-08 12:21:35 +00003653 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003654 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003655 return raw_result;
3656}
3657
3658
lrn@chromium.org303ada72010-10-27 09:33:13 +00003659MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003660 Isolate* isolate = GetIsolate();
3661 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003662 // Make sure that the top context does not change when doing
3663 // callbacks or interceptor calls.
3664 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003665 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003667 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003668 v8::IndexedPropertyDeleter deleter =
3669 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3670 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003671 LOG(isolate,
3672 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3673 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003674 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003675 v8::Handle<v8::Boolean> result;
3676 {
3677 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003678 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679 result = deleter(index, info);
3680 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003681 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003682 if (!result.IsEmpty()) {
3683 ASSERT(result->IsBoolean());
3684 return *v8::Utils::OpenHandle(*result);
3685 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00003686 MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3687 *this_handle,
3688 index,
3689 NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003690 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003691 return raw_result;
3692}
3693
3694
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003695Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
3696 uint32_t index) {
3697 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3698 obj->DeleteElement(index, JSObject::NORMAL_DELETION),
3699 Object);
3700}
3701
3702
lrn@chromium.org303ada72010-10-27 09:33:13 +00003703MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003704 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003705 // Check access rights if needed.
3706 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003707 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3708 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3709 return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003710 }
3711
3712 if (IsJSGlobalProxy()) {
3713 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003714 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003715 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00003716 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003717 }
3718
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003719 if (HasIndexedInterceptor()) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003720 // Skip interceptor if forcing deletion.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003721 if (mode != FORCE_DELETION) {
3722 return DeleteElementWithInterceptor(index);
3723 }
3724 mode = JSReceiver::FORCE_DELETION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725 }
3726
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003727 return GetElementsAccessor()->Delete(this, index, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728}
3729
3730
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003731Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj,
3732 Handle<String> prop) {
3733 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3734 obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
3735 Object);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003736}
3737
3738
lrn@chromium.org303ada72010-10-27 09:33:13 +00003739MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003740 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003741 // ECMA-262, 3rd, 8.6.2.5
3742 ASSERT(name->IsString());
3743
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003744 // Check access rights if needed.
3745 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003746 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3747 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3748 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 }
3750
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003751 if (IsJSGlobalProxy()) {
3752 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003753 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003754 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00003755 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003756 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003757
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003758 uint32_t index = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003759 if (name->AsArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003760 return DeleteElement(index, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003761 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003762 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003763 LocalLookup(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003764 if (!result.IsFound()) return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003765 // Ignore attributes if forcing a deletion.
3766 if (result.IsDontDelete() && mode != FORCE_DELETION) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003767 if (mode == STRICT_DELETION) {
3768 // Deleting a non-configurable property in strict mode.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003769 HandleScope scope(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003770 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003771 return isolate->Throw(*isolate->factory()->NewTypeError(
3772 "strict_delete_property", HandleVector(args, 2)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003773 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003774 return isolate->heap()->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003775 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003776 // Check for interceptor.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00003777 if (result.IsInterceptor()) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003778 // Skip interceptor if forcing a deletion.
3779 if (mode == FORCE_DELETION) {
3780 return DeletePropertyPostInterceptor(name, mode);
3781 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003782 return DeletePropertyWithInterceptor(name);
3783 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003784 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003785 Object* obj;
3786 { MaybeObject* maybe_obj =
3787 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3788 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3789 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003790 // Make sure the properties are normalized before removing the entry.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003791 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003792 }
3793}
3794
3795
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003796MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
3797 if (IsJSProxy()) {
3798 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
3799 }
3800 return JSObject::cast(this)->DeleteElement(index, mode);
3801}
3802
3803
3804MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3805 if (IsJSProxy()) {
3806 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
3807 }
3808 return JSObject::cast(this)->DeleteProperty(name, mode);
3809}
3810
3811
whesse@chromium.org7b260152011-06-20 15:33:18 +00003812bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
3813 ElementsKind kind,
3814 Object* object) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003815 ASSERT(IsFastObjectElementsKind(kind) ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003816 kind == DICTIONARY_ELEMENTS);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003817 if (IsFastObjectElementsKind(kind)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003818 int length = IsJSArray()
3819 ? Smi::cast(JSArray::cast(this)->length())->value()
3820 : elements->length();
3821 for (int i = 0; i < length; ++i) {
3822 Object* element = elements->get(i);
3823 if (!element->IsTheHole() && element == object) return true;
3824 }
3825 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003826 Object* key =
3827 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003828 if (!key->IsUndefined()) return true;
3829 }
3830 return false;
3831}
3832
3833
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003834// Check whether this object references another object.
3835bool JSObject::ReferencesObject(Object* obj) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003836 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003837 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838 AssertNoAllocation no_alloc;
3839
3840 // Is the object the constructor for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003841 if (map_of_this->constructor() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003842 return true;
3843 }
3844
3845 // Is the object the prototype for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003846 if (map_of_this->prototype() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003847 return true;
3848 }
3849
3850 // Check if the object is among the named properties.
3851 Object* key = SlowReverseLookup(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003852 if (!key->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003853 return true;
3854 }
3855
3856 // Check if the object is among the indexed properties.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003857 ElementsKind kind = GetElementsKind();
3858 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003859 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003860 case EXTERNAL_BYTE_ELEMENTS:
3861 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3862 case EXTERNAL_SHORT_ELEMENTS:
3863 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3864 case EXTERNAL_INT_ELEMENTS:
3865 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3866 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003867 case EXTERNAL_DOUBLE_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +00003868 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003869 case FAST_HOLEY_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003870 // Raw pixels and external arrays do not reference other
3871 // objects.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003872 break;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003873 case FAST_SMI_ELEMENTS:
3874 case FAST_HOLEY_SMI_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003875 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003876 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003877 case FAST_HOLEY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003878 case DICTIONARY_ELEMENTS: {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003879 FixedArray* elements = FixedArray::cast(this->elements());
3880 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003881 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003882 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00003883 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3884 FixedArray* parameter_map = FixedArray::cast(elements());
3885 // Check the mapped parameters.
3886 int length = parameter_map->length();
3887 for (int i = 2; i < length; ++i) {
3888 Object* value = parameter_map->get(i);
3889 if (!value->IsTheHole() && value == obj) return true;
3890 }
3891 // Check the arguments.
3892 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003893 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
3894 FAST_HOLEY_ELEMENTS;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003895 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003896 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003897 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003898 }
3899
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003900 // For functions check the context.
3901 if (IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003902 // Get the constructor function for arguments array.
3903 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003904 heap->isolate()->context()->global_context()->
3905 arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003906 JSFunction* arguments_function =
3907 JSFunction::cast(arguments_boilerplate->map()->constructor());
3908
3909 // Get the context and don't check if it is the global context.
3910 JSFunction* f = JSFunction::cast(this);
3911 Context* context = f->context();
3912 if (context->IsGlobalContext()) {
3913 return false;
3914 }
3915
3916 // Check the non-special context slots.
3917 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
3918 // Only check JS objects.
3919 if (context->get(i)->IsJSObject()) {
3920 JSObject* ctxobj = JSObject::cast(context->get(i));
3921 // If it is an arguments array check the content.
3922 if (ctxobj->map()->constructor() == arguments_function) {
3923 if (ctxobj->ReferencesObject(obj)) {
3924 return true;
3925 }
3926 } else if (ctxobj == obj) {
3927 return true;
3928 }
3929 }
3930 }
3931
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003932 // Check the context extension (if any) if it can have references.
3933 if (context->has_extension() && !context->IsCatchContext()) {
3934 return JSObject::cast(context->extension())->ReferencesObject(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003935 }
3936 }
3937
3938 // No references to object.
3939 return false;
3940}
3941
3942
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003943Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
3944 CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
3945}
3946
3947
lrn@chromium.org303ada72010-10-27 09:33:13 +00003948MaybeObject* JSObject::PreventExtensions() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003949 Isolate* isolate = GetIsolate();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003950 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003951 !isolate->MayNamedAccess(this,
3952 isolate->heap()->undefined_value(),
3953 v8::ACCESS_KEYS)) {
3954 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
3955 return isolate->heap()->false_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003956 }
3957
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003958 if (IsJSGlobalProxy()) {
3959 Object* proto = GetPrototype();
3960 if (proto->IsNull()) return this;
3961 ASSERT(proto->IsJSGlobalObject());
3962 return JSObject::cast(proto)->PreventExtensions();
3963 }
3964
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003965 // It's not possible to seal objects with external array elements
3966 if (HasExternalArrayElements()) {
3967 HandleScope scope(isolate);
3968 Handle<Object> object(this);
3969 Handle<Object> error =
3970 isolate->factory()->NewTypeError(
3971 "cant_prevent_ext_external_array_elements",
3972 HandleVector(&object, 1));
3973 return isolate->Throw(*error);
3974 }
3975
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003976 // If there are fast elements we normalize.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003977 SeededNumberDictionary* dictionary = NULL;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003978 { MaybeObject* maybe = NormalizeElements();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003979 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003980 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003981 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003982 // Make sure that we never go back to fast case.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003983 dictionary->set_requires_slow_elements();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003984
3985 // Do a map transition, other objects with this map may still
3986 // be extensible.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003987 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003988 MaybeObject* maybe = map()->Copy(DescriptorArray::MAY_BE_SHARED);
3989 if (!maybe->To(&new_map)) return maybe;
3990
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003991 new_map->set_is_extensible(false);
3992 set_map(new_map);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003993 ASSERT(!map()->is_extensible());
3994 return new_map;
3995}
3996
3997
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998// Tests for the fast common case for property enumeration:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003999// - This object and all prototypes has an enum cache (which means that
4000// it is no proxy, has no interceptors and needs no access checks).
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004001// - This object has no elements.
4002// - No prototype has enumerable properties/elements.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004003bool JSReceiver::IsSimpleEnum() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004004 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004005 for (Object* o = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 o != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004007 o = JSObject::cast(o)->GetPrototype()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004008 if (!o->IsJSObject()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 JSObject* curr = JSObject::cast(o);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004011 ASSERT(!curr->HasNamedInterceptor());
4012 ASSERT(!curr->HasIndexedInterceptor());
4013 ASSERT(!curr->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 if (curr->NumberOfEnumElements() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 if (curr != this) {
4016 FixedArray* curr_fixed_array =
4017 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004018 if (curr_fixed_array->length() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 }
4020 }
4021 return true;
4022}
4023
4024
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004025int Map::NumberOfDescribedProperties(PropertyAttributes filter) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004027 DescriptorArray* descs = instance_descriptors();
4028 for (int i = 0; i < descs->number_of_descriptors(); i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004029 PropertyDetails details = descs->GetDetails(i);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004030 if ((details.attributes() & filter) == 0) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004031 result++;
4032 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 }
4034 return result;
4035}
4036
4037
4038int Map::PropertyIndexFor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004039 DescriptorArray* descs = instance_descriptors();
4040 for (int i = 0; i < descs->number_of_descriptors(); i++) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00004041 if (name->Equals(descs->GetKey(i))) return descs->GetFieldIndex(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042 }
4043 return -1;
4044}
4045
4046
4047int Map::NextFreePropertyIndex() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004048 int max_index = -1;
4049 DescriptorArray* descs = instance_descriptors();
4050 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4051 if (descs->GetType(i) == FIELD) {
4052 int current_index = descs->GetFieldIndex(i);
4053 if (current_index > max_index) max_index = current_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 }
4055 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004056 return max_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057}
4058
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059
4060AccessorDescriptor* Map::FindAccessor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004061 DescriptorArray* descs = instance_descriptors();
4062 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4063 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
4064 return descs->GetCallbacks(i);
4065 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 }
4067 return NULL;
4068}
4069
4070
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004071void JSReceiver::LocalLookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 ASSERT(name->IsString());
4073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004074 Heap* heap = GetHeap();
4075
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004076 if (IsJSGlobalProxy()) {
4077 Object* proto = GetPrototype();
4078 if (proto->IsNull()) return result->NotFound();
4079 ASSERT(proto->IsJSGlobalObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004080 return JSReceiver::cast(proto)->LocalLookup(name, result);
4081 }
4082
4083 if (IsJSProxy()) {
4084 result->HandlerResult(JSProxy::cast(this));
4085 return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004086 }
4087
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 // Do not use inline caching if the object is a non-global object
4089 // that requires access checks.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004090 if (IsAccessCheckNeeded()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 result->DisallowCaching();
4092 }
4093
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004094 JSObject* js_object = JSObject::cast(this);
4095
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 // Check __proto__ before interceptor.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004097 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004098 result->ConstantResult(js_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 return;
4100 }
4101
4102 // Check for lookup interceptor except when bootstrapping.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004103 if (js_object->HasNamedInterceptor() &&
4104 !heap->isolate()->bootstrapper()->IsActive()) {
4105 result->InterceptorResult(js_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106 return;
4107 }
4108
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004109 js_object->LocalLookupRealNamedProperty(name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004110}
4111
4112
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004113void JSReceiver::Lookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 // Ecma-262 3rd 8.6.2.4
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004115 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004117 current != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118 current = JSObject::cast(current)->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004119 JSReceiver::cast(current)->LocalLookup(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004120 if (result->IsFound()) return;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004121 }
4122 result->NotFound();
4123}
4124
4125
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004126// Search object and its prototype chain for callback properties.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004127void JSObject::LookupCallbackProperty(String* name, LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004128 Heap* heap = GetHeap();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004129 for (Object* current = this;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00004130 current != heap->null_value() && current->IsJSObject();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004131 current = JSObject::cast(current)->GetPrototype()) {
4132 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004133 if (result->IsPropertyCallbacks()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134 }
4135 result->NotFound();
4136}
4137
4138
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004139// Try to update an accessor in an elements dictionary. Return true if the
4140// update succeeded, and false otherwise.
4141static bool UpdateGetterSetterInDictionary(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004142 SeededNumberDictionary* dictionary,
4143 uint32_t index,
danno@chromium.org88aa0582012-03-23 15:11:57 +00004144 Object* getter,
4145 Object* setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004146 PropertyAttributes attributes) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004147 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004148 if (entry != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004149 Object* result = dictionary->ValueAt(entry);
4150 PropertyDetails details = dictionary->DetailsAt(entry);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004151 if (details.type() == CALLBACKS && result->IsAccessorPair()) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00004152 ASSERT(!details.IsDontDelete());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004153 if (details.attributes() != attributes) {
4154 dictionary->DetailsAtPut(entry,
4155 PropertyDetails(attributes, CALLBACKS, index));
4156 }
danno@chromium.org88aa0582012-03-23 15:11:57 +00004157 AccessorPair::cast(result)->SetComponents(getter, setter);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004158 return true;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004159 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004160 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004161 return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004162}
4163
4164
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004165MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
danno@chromium.org88aa0582012-03-23 15:11:57 +00004166 Object* getter,
4167 Object* setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004168 PropertyAttributes attributes) {
4169 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004170 case FAST_SMI_ELEMENTS:
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004171 case FAST_ELEMENTS:
4172 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004173 case FAST_HOLEY_SMI_ELEMENTS:
4174 case FAST_HOLEY_ELEMENTS:
4175 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004176 break;
4177 case EXTERNAL_PIXEL_ELEMENTS:
4178 case EXTERNAL_BYTE_ELEMENTS:
4179 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4180 case EXTERNAL_SHORT_ELEMENTS:
4181 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4182 case EXTERNAL_INT_ELEMENTS:
4183 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4184 case EXTERNAL_FLOAT_ELEMENTS:
4185 case EXTERNAL_DOUBLE_ELEMENTS:
4186 // Ignore getters and setters on pixel and external array elements.
4187 return GetHeap()->undefined_value();
4188 case DICTIONARY_ELEMENTS:
4189 if (UpdateGetterSetterInDictionary(element_dictionary(),
4190 index,
danno@chromium.org88aa0582012-03-23 15:11:57 +00004191 getter,
4192 setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004193 attributes)) {
4194 return GetHeap()->undefined_value();
whesse@chromium.org7b260152011-06-20 15:33:18 +00004195 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004196 break;
4197 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4198 // Ascertain whether we have read-only properties or an existing
4199 // getter/setter pair in an arguments elements dictionary backing
4200 // store.
4201 FixedArray* parameter_map = FixedArray::cast(elements());
4202 uint32_t length = parameter_map->length();
4203 Object* probe =
4204 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
4205 if (probe == NULL || probe->IsTheHole()) {
4206 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4207 if (arguments->IsDictionary()) {
4208 SeededNumberDictionary* dictionary =
4209 SeededNumberDictionary::cast(arguments);
4210 if (UpdateGetterSetterInDictionary(dictionary,
4211 index,
danno@chromium.org88aa0582012-03-23 15:11:57 +00004212 getter,
4213 setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004214 attributes)) {
4215 return GetHeap()->undefined_value();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004216 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004217 }
4218 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004219 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004220 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004221 }
4222
4223 AccessorPair* accessors;
4224 { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
4225 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4226 }
danno@chromium.org88aa0582012-03-23 15:11:57 +00004227 accessors->SetComponents(getter, setter);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004228
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004229 return SetElementCallback(index, accessors, attributes);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004230}
4231
4232
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004233MaybeObject* JSObject::CreateAccessorPairFor(String* name) {
4234 LookupResult result(GetHeap()->isolate());
4235 LocalLookupRealNamedProperty(name, &result);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004236 if (result.IsPropertyCallbacks()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004237 // Note that the result can actually have IsDontDelete() == true when we
4238 // e.g. have to fall back to the slow case while adding a setter after
4239 // successfully reusing a map transition for a getter. Nevertheless, this is
4240 // OK, because the assertion only holds for the whole addition of both
4241 // accessors, not for the addition of each part. See first comment in
4242 // DefinePropertyAccessor below.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004243 Object* obj = result.GetCallbackObject();
4244 if (obj->IsAccessorPair()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004245 return AccessorPair::cast(obj)->Copy();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004246 }
4247 }
4248 return GetHeap()->AllocateAccessorPair();
4249}
4250
4251
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004252MaybeObject* JSObject::DefinePropertyAccessor(String* name,
danno@chromium.org88aa0582012-03-23 15:11:57 +00004253 Object* getter,
4254 Object* setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004255 PropertyAttributes attributes) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004256 // We could assert that the property is configurable here, but we would need
4257 // to do a lookup, which seems to be a bit of overkill.
4258 Heap* heap = GetHeap();
4259 bool only_attribute_changes = getter->IsNull() && setter->IsNull();
4260 if (HasFastProperties() && !only_attribute_changes) {
4261 MaybeObject* getterOk = heap->undefined_value();
4262 if (!getter->IsNull()) {
4263 getterOk = DefineFastAccessor(name, ACCESSOR_GETTER, getter, attributes);
4264 if (getterOk->IsFailure()) return getterOk;
4265 }
4266
4267 MaybeObject* setterOk = heap->undefined_value();
4268 if (getterOk != heap->null_value() && !setter->IsNull()) {
4269 setterOk = DefineFastAccessor(name, ACCESSOR_SETTER, setter, attributes);
4270 if (setterOk->IsFailure()) return setterOk;
4271 }
4272
4273 if (getterOk != heap->null_value() && setterOk != heap->null_value()) {
4274 return heap->undefined_value();
4275 }
4276 }
4277
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004278 AccessorPair* accessors;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004279 MaybeObject* maybe_accessors = CreateAccessorPairFor(name);
4280 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4281
danno@chromium.org88aa0582012-03-23 15:11:57 +00004282 accessors->SetComponents(getter, setter);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004283 return SetPropertyCallback(name, accessors, attributes);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004284}
4285
4286
4287bool JSObject::CanSetCallback(String* name) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004288 ASSERT(!IsAccessCheckNeeded() ||
4289 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004290
4291 // Check if there is an API defined callback object which prohibits
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004292 // callback overwriting in this object or its prototype chain.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004293 // This mechanism is needed for instance in a browser setting, where
4294 // certain accessors such as window.location should not be allowed
4295 // to be overwritten because allowing overwriting could potentially
4296 // cause security problems.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004297 LookupResult callback_result(GetIsolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004298 LookupCallbackProperty(name, &callback_result);
4299 if (callback_result.IsFound()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004300 Object* obj = callback_result.GetCallbackObject();
4301 if (obj->IsAccessorInfo() &&
4302 AccessorInfo::cast(obj)->prohibits_overwriting()) {
4303 return false;
4304 }
4305 }
4306
4307 return true;
4308}
4309
4310
lrn@chromium.org303ada72010-10-27 09:33:13 +00004311MaybeObject* JSObject::SetElementCallback(uint32_t index,
4312 Object* structure,
4313 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004314 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4315
4316 // Normalize elements to make this operation simple.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004317 SeededNumberDictionary* dictionary;
4318 { MaybeObject* maybe_dictionary = NormalizeElements();
4319 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004320 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004321 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004322
4323 // Update the dictionary with the new CALLBACKS property.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004324 { MaybeObject* maybe_dictionary = dictionary->Set(index, structure, details);
4325 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004326 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004327
whesse@chromium.org7b260152011-06-20 15:33:18 +00004328 dictionary->set_requires_slow_elements();
4329 // Update the dictionary backing store on the object.
4330 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
4331 // Also delete any parameter alias.
4332 //
4333 // TODO(kmillikin): when deleting the last parameter alias we could
4334 // switch to a direct backing store without the parameter map. This
4335 // would allow GC of the context.
4336 FixedArray* parameter_map = FixedArray::cast(elements());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004337 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004338 parameter_map->set(index + 2, GetHeap()->the_hole_value());
4339 }
4340 parameter_map->set(1, dictionary);
4341 } else {
4342 set_elements(dictionary);
4343 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004344
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004345 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346}
4347
4348
lrn@chromium.org303ada72010-10-27 09:33:13 +00004349MaybeObject* JSObject::SetPropertyCallback(String* name,
4350 Object* structure,
4351 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004352 // Normalize object to make this operation simple.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004353 MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
4354 if (maybe_ok->IsFailure()) return maybe_ok;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004355
4356 // For the global object allocate a new map to invalidate the global inline
4357 // caches which have a global property cell reference directly in the code.
4358 if (IsGlobalObject()) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004359 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004360 MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
4361 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
4362
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004363 set_map(new_map);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004364 // When running crankshaft, changing the map is not enough. We
4365 // need to deoptimize all functions that rely on this global
4366 // object.
4367 Deoptimizer::DeoptimizeGlobalObject(this);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004368 }
4369
4370 // Update the dictionary with the new CALLBACKS property.
danno@chromium.org88aa0582012-03-23 15:11:57 +00004371 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004372 maybe_ok = SetNormalizedProperty(name, structure, details);
4373 if (maybe_ok->IsFailure()) return maybe_ok;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004374
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004375 return GetHeap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004376}
4377
danno@chromium.org88aa0582012-03-23 15:11:57 +00004378
4379void JSObject::DefineAccessor(Handle<JSObject> object,
4380 Handle<String> name,
4381 Handle<Object> getter,
4382 Handle<Object> setter,
4383 PropertyAttributes attributes) {
4384 CALL_HEAP_FUNCTION_VOID(
4385 object->GetIsolate(),
4386 object->DefineAccessor(*name, *getter, *setter, attributes));
4387}
4388
lrn@chromium.org303ada72010-10-27 09:33:13 +00004389MaybeObject* JSObject::DefineAccessor(String* name,
danno@chromium.org88aa0582012-03-23 15:11:57 +00004390 Object* getter,
4391 Object* setter,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004392 PropertyAttributes attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004393 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004394 // Check access rights if needed.
4395 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004396 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4397 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4398 return isolate->heap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004399 }
4400
4401 if (IsJSGlobalProxy()) {
4402 Object* proto = GetPrototype();
4403 if (proto->IsNull()) return this;
4404 ASSERT(proto->IsJSGlobalObject());
danno@chromium.org88aa0582012-03-23 15:11:57 +00004405 return JSObject::cast(proto)->DefineAccessor(
4406 name, getter, setter, attributes);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004407 }
4408
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004409 // Make sure that the top context does not change when doing callbacks or
4410 // interceptor calls.
4411 AssertNoContextChange ncc;
4412
4413 // Try to flatten before operating on the string.
4414 name->TryFlatten();
4415
4416 if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
4417
4418 uint32_t index = 0;
4419 return name->AsArrayIndex(&index) ?
danno@chromium.org88aa0582012-03-23 15:11:57 +00004420 DefineElementAccessor(index, getter, setter, attributes) :
4421 DefinePropertyAccessor(name, getter, setter, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422}
4423
4424
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004425static MaybeObject* TryAccessorTransition(JSObject* self,
4426 Map* transitioned_map,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004427 String* name,
4428 AccessorComponent component,
4429 Object* accessor,
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004430 PropertyAttributes attributes) {
4431 DescriptorArray* descs = transitioned_map->instance_descriptors();
4432 int number = descs->LastAdded();
4433 PropertyDetails details = descs->GetDetails(number);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004434
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004435 // If the transition target was not callbacks, fall back to the slow case.
4436 if (details.type() != CALLBACKS) return self->GetHeap()->null_value();
4437
4438 Object* target_accessor =
4439 AccessorPair::cast(descs->GetCallbacksObject(number))->get(component);
4440 PropertyAttributes target_attributes = details.attributes();
4441
4442 // Reuse transition if adding same accessor with same attributes.
4443 if (target_accessor == accessor && target_attributes == attributes) {
4444 self->set_map(transitioned_map);
4445 return self;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004446 }
4447
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004448 // If either not the same accessor, or not the same attributes, fall back to
4449 // the slow case.
4450 return self->GetHeap()->null_value();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004451}
4452
4453
4454MaybeObject* JSObject::DefineFastAccessor(String* name,
4455 AccessorComponent component,
4456 Object* accessor,
4457 PropertyAttributes attributes) {
4458 ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined());
4459 LookupResult result(GetIsolate());
4460 LocalLookup(name, &result);
4461
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004462 if (result.IsFound()
4463 && !result.IsPropertyCallbacks()
4464 && !result.IsTransition()) return GetHeap()->null_value();
4465
4466 // Return success if the same accessor with the same attributes already exist.
4467 AccessorPair* source_accessors = NULL;
4468 if (result.IsPropertyCallbacks()) {
4469 Object* callback_value = result.GetCallbackObject();
4470 if (callback_value->IsAccessorPair()) {
4471 source_accessors = AccessorPair::cast(callback_value);
4472 Object* entry = source_accessors->get(component);
4473 if (entry == accessor && result.GetAttributes() == attributes) {
4474 return this;
4475 }
4476 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004477 }
4478
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004479 // If not, lookup a transition.
4480 map()->LookupTransition(this, name, &result);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004481
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004482 // If there is a transition, try to follow it.
4483 if (result.IsFound()) {
4484 Map* target = result.GetTransitionTarget();
4485 return TryAccessorTransition(
4486 this, target, name, component, accessor, attributes);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004487 }
4488
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004489 // If there is no transition yet, add a transition to the a new accessor pair
4490 // containing the accessor.
4491 AccessorPair* accessors;
4492 MaybeObject* maybe_accessors;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004493
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004494 // Allocate a new pair if there were no source accessors. Otherwise, copy the
4495 // pair and modify the accessor.
4496 if (source_accessors != NULL) {
4497 maybe_accessors = source_accessors->Copy();
4498 } else {
4499 maybe_accessors = GetHeap()->AllocateAccessorPair();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004500 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004501 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4502 accessors->set(component, accessor);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004503
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004504 CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
4505
4506 Map* new_map;
4507 MaybeObject* maybe_new_map =
4508 map()->CopyInsertDescriptor(&new_accessors_desc, INSERT_TRANSITION);
4509 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
4510
4511 set_map(new_map);
4512 return this;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004513}
4514
4515
lrn@chromium.org303ada72010-10-27 09:33:13 +00004516MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004517 Isolate* isolate = GetIsolate();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004518 String* name = String::cast(info->name());
4519 // Check access rights if needed.
4520 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004521 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4522 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4523 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004524 }
4525
4526 if (IsJSGlobalProxy()) {
4527 Object* proto = GetPrototype();
4528 if (proto->IsNull()) return this;
4529 ASSERT(proto->IsJSGlobalObject());
4530 return JSObject::cast(proto)->DefineAccessor(info);
4531 }
4532
4533 // Make sure that the top context does not change when doing callbacks or
4534 // interceptor calls.
4535 AssertNoContextChange ncc;
4536
4537 // Try to flatten before operating on the string.
4538 name->TryFlatten();
4539
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004540 if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004541
4542 uint32_t index = 0;
4543 bool is_element = name->AsArrayIndex(&index);
4544
4545 if (is_element) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004546 if (IsJSArray()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004547
4548 // Accessors overwrite previous callbacks (cf. with getters/setters).
4549 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004550 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004551 case FAST_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00004552 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004553 case FAST_HOLEY_SMI_ELEMENTS:
4554 case FAST_HOLEY_ELEMENTS:
4555 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004556 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004557 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004558 case EXTERNAL_BYTE_ELEMENTS:
4559 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4560 case EXTERNAL_SHORT_ELEMENTS:
4561 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4562 case EXTERNAL_INT_ELEMENTS:
4563 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4564 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004565 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004566 // Ignore getters and setters on pixel and external array
4567 // elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004568 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004569 case DICTIONARY_ELEMENTS:
4570 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004571 case NON_STRICT_ARGUMENTS_ELEMENTS:
4572 UNIMPLEMENTED();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004573 break;
4574 }
4575
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004576 MaybeObject* maybe_ok =
4577 SetElementCallback(index, info, info->property_attributes());
4578 if (maybe_ok->IsFailure()) return maybe_ok;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004579 } else {
4580 // Lookup the name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004581 LookupResult result(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004582 LocalLookup(name, &result);
4583 // ES5 forbids turning a property into an accessor if it's not
4584 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004585 if (result.IsFound() && (result.IsReadOnly() || result.IsDontDelete())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004586 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004587 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004588
4589 MaybeObject* maybe_ok =
4590 SetPropertyCallback(name, info, info->property_attributes());
4591 if (maybe_ok->IsFailure()) return maybe_ok;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004592 }
4593
4594 return this;
4595}
4596
4597
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004598Object* JSObject::LookupAccessor(String* name, AccessorComponent component) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004599 Heap* heap = GetHeap();
4600
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601 // Make sure that the top context does not change when doing callbacks or
4602 // interceptor calls.
4603 AssertNoContextChange ncc;
4604
4605 // Check access rights if needed.
4606 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004607 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
4608 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4609 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610 }
4611
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004612 // Make the lookup and include prototypes.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00004613 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004614 if (name->AsArrayIndex(&index)) {
4615 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004616 obj != heap->null_value();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004617 obj = JSReceiver::cast(obj)->GetPrototype()) {
4618 if (obj->IsJSObject() && JSObject::cast(obj)->HasDictionaryElements()) {
4619 JSObject* js_object = JSObject::cast(obj);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004620 SeededNumberDictionary* dictionary = js_object->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004621 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004622 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004623 Object* element = dictionary->ValueAt(entry);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00004624 if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
4625 element->IsAccessorPair()) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00004626 return AccessorPair::cast(element)->GetComponent(component);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004627 }
4628 }
4629 }
4630 }
4631 } else {
4632 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004633 obj != heap->null_value();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004634 obj = JSReceiver::cast(obj)->GetPrototype()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004635 LookupResult result(heap->isolate());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004636 JSReceiver::cast(obj)->LocalLookup(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004637 if (result.IsFound()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004638 if (result.IsReadOnly()) return heap->undefined_value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004639 if (result.IsPropertyCallbacks()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004640 Object* obj = result.GetCallbackObject();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004641 if (obj->IsAccessorPair()) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00004642 return AccessorPair::cast(obj)->GetComponent(component);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004643 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004644 }
4645 }
4646 }
4647 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004648 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004649}
4650
4651
4652Object* JSObject::SlowReverseLookup(Object* value) {
4653 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004654 DescriptorArray* descs = map()->instance_descriptors();
4655 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4656 if (descs->GetType(i) == FIELD) {
4657 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
4658 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004659 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004660 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
4661 if (descs->GetConstantFunction(i) == value) {
4662 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004663 }
4664 }
4665 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004666 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004667 } else {
4668 return property_dictionary()->SlowReverseLookup(value);
4669 }
4670}
4671
4672
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004673MaybeObject* Map::RawCopy(int instance_size) {
4674 Map* result;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004675 { MaybeObject* maybe_result =
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004676 GetHeap()->AllocateMap(instance_type(), instance_size);
4677 if (!maybe_result->To(&result)) return maybe_result;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004678 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004679
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004680 result->set_prototype(prototype());
4681 result->set_constructor(constructor());
4682 result->set_bit_field(bit_field());
4683 result->set_bit_field2(bit_field2());
4684 result->set_bit_field3(bit_field3());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004685 return result;
4686}
4687
4688
lrn@chromium.org303ada72010-10-27 09:33:13 +00004689MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4690 NormalizedMapSharingMode sharing) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004691 int new_instance_size = instance_size();
4692 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4693 new_instance_size -= inobject_properties() * kPointerSize;
4694 }
4695
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004696 Map* result;
4697 { MaybeObject* maybe_result = RawCopy(new_instance_size);
4698 if (!maybe_result->To(&result)) return maybe_result;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004699 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004700
4701 if (mode != CLEAR_INOBJECT_PROPERTIES) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004702 result->set_inobject_properties(inobject_properties());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004703 }
4704
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004705 result->set_code_cache(code_cache());
4706 result->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004707
ricow@chromium.org65fae842010-08-25 15:26:24 +00004708#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004709 if (FLAG_verify_heap && Map::cast(result)->is_shared()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004710 result->SharedMapVerify();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004711 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004712#endif
4713
4714 return result;
4715}
4716
4717
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004718MaybeObject* Map::CopyDropDescriptors() {
4719 Map* result;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004720 MaybeObject* maybe_result = RawCopy(instance_size());
4721 if (!maybe_result->To(&result)) return maybe_result;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004722
4723 // Please note instance_type and instance_size are set when allocated.
4724 result->set_inobject_properties(inobject_properties());
4725 result->set_unused_property_fields(unused_property_fields());
4726
4727 result->set_pre_allocated_property_fields(pre_allocated_property_fields());
4728 result->set_is_shared(false);
4729 result->ClearCodeCache(GetHeap());
4730 return result;
4731}
4732
4733
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004734MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
4735 String* name,
4736 TransitionFlag flag) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004737 Map* result;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004738 MaybeObject* maybe_result = CopyDropDescriptors();
4739 if (!maybe_result->To(&result)) return maybe_result;
4740
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004741 result->set_instance_descriptors(descriptors);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004742
4743 if (flag == INSERT_TRANSITION) {
4744 TransitionArray* transitions;
4745 MaybeObject* maybe_transitions = AddTransition(name, result);
4746 if (!maybe_transitions->To(&transitions)) return maybe_transitions;
4747
4748 MaybeObject* maybe_set = set_transitions(transitions);
4749 if (maybe_set->IsFailure()) return maybe_set;
4750
4751 result->SetBackPointer(this);
4752 }
4753
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004754 return result;
4755}
4756
4757
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004758MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) {
4759 // Create a new free-floating map only if we are not allowed to store it.
4760 Map* new_map = NULL;
4761 MaybeObject* maybe_new_map = Copy(DescriptorArray::MAY_BE_SHARED);
4762 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
4763 new_map->set_elements_kind(kind);
4764
4765 if (flag == INSERT_TRANSITION) {
4766 ASSERT(!HasElementsTransition() ||
4767 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS ||
4768 IsExternalArrayElementsKind(
4769 elements_transition_map()->elements_kind())) &&
4770 (kind == DICTIONARY_ELEMENTS ||
4771 IsExternalArrayElementsKind(kind))));
4772 ASSERT(!IsFastElementsKind(kind) ||
4773 IsMoreGeneralElementsKindTransition(elements_kind(), kind));
4774 ASSERT(kind != elements_kind());
4775
4776 MaybeObject* added_elements = set_elements_transition_map(new_map);
4777 if (added_elements->IsFailure()) return added_elements;
4778
4779 new_map->SetBackPointer(this);
4780 }
4781
4782 return new_map;
4783}
4784
4785
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004786MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() {
4787 if (pre_allocated_property_fields() == 0) return CopyDropDescriptors();
4788
4789 // If the map has pre-allocated properties always start out with a descriptor
4790 // array describing these properties.
4791 ASSERT(constructor()->IsJSFunction());
4792 JSFunction* ctor = JSFunction::cast(constructor());
4793 DescriptorArray* descriptors;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004794 MaybeObject* maybe_descriptors =
4795 ctor->initial_map()->instance_descriptors()->Copy(
4796 DescriptorArray::MAY_BE_SHARED);
4797 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4798
4799 return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004800}
4801
4802
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004803MaybeObject* Map::Copy(DescriptorArray::SharedMode shared_mode) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004804 DescriptorArray* descriptors;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004805 MaybeObject* maybe_descriptors = instance_descriptors()->Copy(shared_mode);
4806 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4807
4808 return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
4809}
4810
4811
4812MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor,
4813 TransitionFlag flag) {
4814 DescriptorArray* descriptors;
4815 MaybeObject* maybe_descriptors = instance_descriptors()->CopyAdd(descriptor);
4816 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4817
4818 return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
4819}
4820
4821
4822MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor,
4823 TransitionFlag flag) {
4824 DescriptorArray* old_descriptors = instance_descriptors();
4825
4826 // Ensure the key is a symbol.
4827 MaybeObject* maybe_result = descriptor->KeyToSymbol();
4828 if (maybe_result->IsFailure()) return maybe_result;
4829
4830 DescriptorArray* descriptors;
4831 MaybeObject* maybe_descriptors;
4832
4833 // We replace the key if it is already present.
4834 int index = old_descriptors->SearchWithCache(descriptor->GetKey());
4835 if (index == DescriptorArray::kNotFound) {
4836 maybe_descriptors = old_descriptors->CopyAdd(descriptor);
4837 } else {
4838 maybe_descriptors = old_descriptors->CopyReplace(descriptor, index);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004839 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004840 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4841
4842 return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
4843}
4844
4845
4846MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor,
4847 int index,
4848 TransitionFlag flag) {
4849 DescriptorArray* descriptors;
4850 MaybeObject* maybe_descriptors =
4851 instance_descriptors()->CopyReplace(descriptor, index);
4852 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4853
4854 return CopyReplaceDescriptors(descriptors, descriptor->GetKey(), flag);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004855}
4856
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004857
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004858void Map::UpdateCodeCache(Handle<Map> map,
4859 Handle<String> name,
4860 Handle<Code> code) {
4861 Isolate* isolate = map->GetIsolate();
4862 CALL_HEAP_FUNCTION_VOID(isolate,
4863 map->UpdateCodeCache(*name, *code));
4864}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004865
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004866
lrn@chromium.org303ada72010-10-27 09:33:13 +00004867MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004868 ASSERT(!is_shared() || code->allowed_in_shared_map_code_cache());
4869
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004870 // Allocate the code cache if not present.
4871 if (code_cache()->IsFixedArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004872 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004873 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004874 if (!maybe_result->ToObject(&result)) return maybe_result;
4875 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004876 set_code_cache(result);
4877 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004879 // Update the code cache.
4880 return CodeCache::cast(code_cache())->Update(name, code);
4881}
4882
4883
4884Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4885 // Do a lookup if a code cache exists.
4886 if (!code_cache()->IsFixedArray()) {
4887 return CodeCache::cast(code_cache())->Lookup(name, flags);
4888 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004889 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004890 }
4891}
4892
4893
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004894int Map::IndexInCodeCache(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004895 // Get the internal index if a code cache exists.
4896 if (!code_cache()->IsFixedArray()) {
4897 return CodeCache::cast(code_cache())->GetIndex(name, code);
4898 }
4899 return -1;
4900}
4901
4902
4903void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4904 // No GC is supposed to happen between a call to IndexInCodeCache and
4905 // RemoveFromCodeCache so the code cache must be there.
4906 ASSERT(!code_cache()->IsFixedArray());
4907 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4908}
4909
4910
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004911// An iterator over all map transitions in an descriptor array, reusing the map
4912// field of the contens array while it is running.
4913class IntrusiveMapTransitionIterator {
4914 public:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004915 explicit IntrusiveMapTransitionIterator(TransitionArray* transition_array)
4916 : transition_array_(transition_array) { }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004917
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004918 void Start() {
4919 ASSERT(!IsIterating());
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004920 *TransitionArrayHeader() = Smi::FromInt(0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004921 }
4922
4923 bool IsIterating() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004924 return (*TransitionArrayHeader())->IsSmi();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004925 }
4926
4927 Map* Next() {
4928 ASSERT(IsIterating());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004929 int index = Smi::cast(*TransitionArrayHeader())->value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004930 int number_of_transitions = transition_array_->number_of_transitions();
4931 while (index < number_of_transitions) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004932 *TransitionArrayHeader() = Smi::FromInt(index + 1);
4933 return transition_array_->GetTarget(index);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004934 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004935
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004936 if (index == number_of_transitions &&
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004937 transition_array_->HasElementsTransition()) {
4938 Map* elements_transition = transition_array_->elements_transition();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004939 *TransitionArrayHeader() = Smi::FromInt(index + 1);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004940 return elements_transition;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004941 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004942 *TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004943 return NULL;
4944 }
4945
4946 private:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004947 Object** TransitionArrayHeader() {
4948 return HeapObject::RawField(transition_array_, TransitionArray::kMapOffset);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004949 }
4950
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004951 TransitionArray* transition_array_;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004952};
4953
4954
4955// An iterator over all prototype transitions, reusing the map field of the
4956// underlying array while it is running.
4957class IntrusivePrototypeTransitionIterator {
4958 public:
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00004959 explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans)
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004960 : proto_trans_(proto_trans) { }
4961
4962 void Start() {
4963 ASSERT(!IsIterating());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004964 *Header() = Smi::FromInt(0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004965 }
4966
4967 bool IsIterating() {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004968 return (*Header())->IsSmi();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004969 }
4970
4971 Map* Next() {
4972 ASSERT(IsIterating());
4973 int transitionNumber = Smi::cast(*Header())->value();
4974 if (transitionNumber < NumberOfTransitions()) {
4975 *Header() = Smi::FromInt(transitionNumber + 1);
4976 return GetTransition(transitionNumber);
4977 }
4978 *Header() = proto_trans_->GetHeap()->fixed_array_map();
4979 return NULL;
4980 }
4981
4982 private:
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004983 Object** Header() {
4984 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
4985 }
4986
4987 int NumberOfTransitions() {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00004988 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
4989 Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004990 return Smi::cast(num)->value();
4991 }
4992
4993 Map* GetTransition(int transitionNumber) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00004994 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
4995 return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004996 }
4997
4998 int IndexFor(int transitionNumber) {
4999 return Map::kProtoTransitionHeaderSize +
5000 Map::kProtoTransitionMapOffset +
5001 transitionNumber * Map::kProtoTransitionElementsPerEntry;
5002 }
5003
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00005004 HeapObject* proto_trans_;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00005005};
5006
5007
5008// To traverse the transition tree iteratively, we have to store two kinds of
5009// information in a map: The parent map in the traversal and which children of a
5010// node have already been visited. To do this without additional memory, we
5011// temporarily reuse two maps with known values:
5012//
5013// (1) The map of the map temporarily holds the parent, and is restored to the
5014// meta map afterwards.
5015//
5016// (2) The info which children have already been visited depends on which part
5017// of the map we currently iterate:
5018//
5019// (a) If we currently follow normal map transitions, we temporarily store
5020// the current index in the map of the FixedArray of the desciptor
5021// array's contents, and restore it to the fixed array map afterwards.
5022// Note that a single descriptor can have 0, 1, or 2 transitions.
5023//
5024// (b) If we currently follow prototype transitions, we temporarily store
5025// the current index in the map of the FixedArray holding the prototype
5026// transitions, and restore it to the fixed array map afterwards.
5027//
5028// Note that the child iterator is just a concatenation of two iterators: One
5029// iterating over map transitions and one iterating over prototype transisitons.
5030class TraversableMap : public Map {
5031 public:
5032 // Record the parent in the traversal within this map. Note that this destroys
5033 // this map's map!
5034 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
5035
5036 // Reset the current map's map, returning the parent previously stored in it.
5037 TraversableMap* GetAndResetParent() {
5038 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
5039 set_map_no_write_barrier(GetHeap()->meta_map());
5040 return old_parent;
5041 }
5042
5043 // Start iterating over this map's children, possibly destroying a FixedArray
5044 // map (see explanation above).
5045 void ChildIteratorStart() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005046 if (HasTransitionArray()) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005047 if (HasPrototypeTransitions()) {
5048 IntrusivePrototypeTransitionIterator(GetPrototypeTransitions()).Start();
5049 }
5050
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005051 IntrusiveMapTransitionIterator(transitions()).Start();
5052 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00005053 }
5054
5055 // If we have an unvisited child map, return that one and advance. If we have
5056 // none, return NULL and reset any destroyed FixedArray maps.
5057 TraversableMap* ChildIteratorNext() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005058 if (HasTransitionArray()) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005059 TransitionArray* transition_array = unchecked_transition_array();
5060
5061 if (transition_array->HasPrototypeTransitions()) {
5062 HeapObject* proto_transitions =
5063 transition_array->UncheckedPrototypeTransitions();
5064 IntrusivePrototypeTransitionIterator proto_iterator(proto_transitions);
5065 if (proto_iterator.IsIterating()) {
5066 Map* next = proto_iterator.Next();
5067 if (next != NULL) return static_cast<TraversableMap*>(next);
5068 }
5069 }
5070
5071 IntrusiveMapTransitionIterator transition_iterator(transition_array);
5072 if (transition_iterator.IsIterating()) {
5073 Map* next = transition_iterator.Next();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005074 if (next != NULL) return static_cast<TraversableMap*>(next);
5075 }
verwaest@chromium.org37141392012-05-31 13:27:02 +00005076 }
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005077
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00005078 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.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00005108 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005109 // 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) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00005199 if (Code::ExtractTypeFromFlags(flags) == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005200 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) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00005237 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005238 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) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00005253 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005254 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
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005627MaybeObject* DescriptorArray::Allocate(int number_of_descriptors,
5628 SharedMode shared_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005629 Heap* heap = Isolate::Current()->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005630 // Do not use DescriptorArray::cast on incomplete object.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005631 FixedArray* result;
verwaest@chromium.org50915592012-06-18 12:15:44 +00005632 if (number_of_descriptors == 0 && shared_mode == MAY_BE_SHARED) {
5633 return heap->empty_descriptor_array();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005634 }
verwaest@chromium.org50915592012-06-18 12:15:44 +00005635 // Allocate the array of keys.
5636 { MaybeObject* maybe_array =
5637 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
5638 if (!maybe_array->To(&result)) return maybe_array;
5639 }
5640
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005641 result->set(kLastAddedIndex, Smi::FromInt(kNoneAdded));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005642 result->set(kTransitionsIndex, Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005643 return result;
5644}
5645
5646
5647void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005648 FixedArray* new_cache,
5649 Object* new_index_cache) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005650 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005651 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005652 if (HasEnumCache()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005653 FixedArray::cast(get(kLastAddedIndex))->
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005654 set(kEnumCacheBridgeCacheIndex, new_cache);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005655 FixedArray::cast(get(kLastAddedIndex))->
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005656 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005657 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005658 if (IsEmpty()) return; // Do nothing for empty descriptor array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005659 FixedArray::cast(bridge_storage)->
5660 set(kEnumCacheBridgeCacheIndex, new_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005661 FixedArray::cast(bridge_storage)->
5662 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005663 NoWriteBarrierSet(FixedArray::cast(bridge_storage),
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005664 kEnumCacheBridgeLastAdded,
5665 get(kLastAddedIndex));
5666 set(kLastAddedIndex, bridge_storage);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005667 }
5668}
5669
5670
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00005671static bool InsertionPointFound(String* key1, String* key2) {
5672 return key1->Hash() > key2->Hash() || key1 == key2;
5673}
5674
5675
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005676void DescriptorArray::CopyFrom(int dst_index,
5677 DescriptorArray* src,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005678 int src_index,
5679 const WhitenessWitness& witness) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005680 Object* value = src->GetValue(src_index);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005681 PropertyDetails details = src->GetDetails(src_index);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005682 Descriptor desc(src->GetKey(src_index), value, details);
5683 Set(dst_index, &desc, witness);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005684}
5685
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005686MaybeObject* DescriptorArray::CopyReplace(Descriptor* descriptor,
5687 int insertion_index) {
5688 ASSERT(0 <= insertion_index && insertion_index < number_of_descriptors());
5689
5690 // Ensure the key is a symbol.
5691 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
5692 if (maybe_result->IsFailure()) return maybe_result;
5693 }
5694
5695 int size = number_of_descriptors();
5696
5697 DescriptorArray* new_descriptors;
5698 { MaybeObject* maybe_result = Allocate(size, MAY_BE_SHARED);
5699 if (!maybe_result->To(&new_descriptors)) return maybe_result;
5700 }
5701
5702 FixedArray::WhitenessWitness witness(new_descriptors);
5703
5704 // Copy the descriptors, replacing a descriptor.
5705 for (int index = 0; index < size; ++index) {
5706 if (index == insertion_index) continue;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005707 new_descriptors->CopyFrom(index, this, index, witness);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005708 }
5709
5710 descriptor->SetEnumerationIndex(GetDetails(insertion_index).index());
5711 new_descriptors->Set(insertion_index, descriptor, witness);
5712 new_descriptors->SetLastAdded(LastAdded());
5713
5714 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
5715
5716 return new_descriptors;
5717}
5718
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005719
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005720MaybeObject* DescriptorArray::CopyAdd(Descriptor* descriptor) {
5721 // Ensure the key is a symbol.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005722 MaybeObject* maybe_result = descriptor->KeyToSymbol();
5723 if (maybe_result->IsFailure()) return maybe_result;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005724
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005725 String* key = descriptor->GetKey();
5726 ASSERT(Search(key) == kNotFound);
5727
5728 int new_size = number_of_descriptors() + 1;
5729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005730 DescriptorArray* new_descriptors;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005731 MaybeObject* maybe_descriptors = Allocate(new_size, MAY_BE_SHARED);
5732 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005733
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005734 FixedArray::WhitenessWitness witness(new_descriptors);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005735
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005736 // Copy the descriptors, inserting a descriptor.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00005737 int insertion_index = -1;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005738 int to = 0;
5739 for (int from = 0; from < number_of_descriptors(); ++from) {
5740 if (insertion_index < 0 && InsertionPointFound(GetKey(from), key)) {
5741 insertion_index = to++;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005742 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005743 new_descriptors->CopyFrom(to++, this, from, witness);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005744 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005745 if (insertion_index < 0) insertion_index = to++;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005746
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005747 ASSERT(to == new_descriptors->number_of_descriptors());
5748
5749 ASSERT(new_size == NextEnumerationIndex());
5750 descriptor->SetEnumerationIndex(new_size);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00005751 new_descriptors->Set(insertion_index, descriptor, witness);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005752 new_descriptors->SetLastAdded(insertion_index);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005753
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005754 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005755
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005756 return new_descriptors;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005757}
5758
5759
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005760MaybeObject* DescriptorArray::Copy(SharedMode shared_mode) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005761 // Allocate the new descriptor array.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005762 int number_of_descriptors = this->number_of_descriptors();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005763 DescriptorArray* new_descriptors;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005764 MaybeObject* maybe_result = Allocate(number_of_descriptors, shared_mode);
5765 if (!maybe_result->To(&new_descriptors)) return maybe_result;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005766
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005767 // Copy the content.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005768 if (number_of_descriptors > 0) {
5769 FixedArray::WhitenessWitness witness(new_descriptors);
5770 for (int i = 0; i < number_of_descriptors; i++) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005771 new_descriptors->CopyFrom(i, this, i, witness);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005772 }
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005773 new_descriptors->SetLastAdded(LastAdded());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005774 }
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005775
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005776 return new_descriptors;
5777}
5778
verwaest@chromium.org37141392012-05-31 13:27:02 +00005779// We need the whiteness witness since sort will reshuffle the entries in the
5780// descriptor array. If the descriptor array were to be black, the shuffling
5781// would move a slot that was already recorded as pointing into an evacuation
5782// candidate. This would result in missing updates upon evacuation.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005783void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005784 // In-place heap sort.
5785 int len = number_of_descriptors();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005786 // Nothing to sort.
5787 if (len == 0) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005788
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005789 ASSERT(LastAdded() == kNoneAdded ||
5790 GetDetails(LastAdded()).index() == number_of_descriptors());
5791
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005792 // Bottom-up max-heap construction.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005793 // Index of the last node with children
5794 const int max_parent_index = (len / 2) - 1;
5795 for (int i = max_parent_index; i >= 0; --i) {
5796 int parent_index = i;
5797 const uint32_t parent_hash = GetKey(i)->Hash();
5798 while (parent_index <= max_parent_index) {
5799 int child_index = 2 * parent_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005800 uint32_t child_hash = GetKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005801 if (child_index + 1 < len) {
5802 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5803 if (right_child_hash > child_hash) {
5804 child_index++;
5805 child_hash = right_child_hash;
5806 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005807 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005808 if (child_hash <= parent_hash) break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005809 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005810 // Now element at child_index could be < its children.
5811 parent_index = child_index; // parent_hash remains correct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005812 }
5813 }
5814
5815 // Extract elements and create sorted array.
5816 for (int i = len - 1; i > 0; --i) {
5817 // Put max element at the back of the array.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005818 NoIncrementalWriteBarrierSwapDescriptors(0, i);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005819 // Shift down the new top element.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005820 int parent_index = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005821 const uint32_t parent_hash = GetKey(parent_index)->Hash();
5822 const int max_parent_index = (i / 2) - 1;
5823 while (parent_index <= max_parent_index) {
5824 int child_index = parent_index * 2 + 1;
5825 uint32_t child_hash = GetKey(child_index)->Hash();
5826 if (child_index + 1 < i) {
5827 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5828 if (right_child_hash > child_hash) {
5829 child_index++;
5830 child_hash = right_child_hash;
5831 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005832 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005833 if (child_hash <= parent_hash) break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005834 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005835 parent_index = child_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005836 }
5837 }
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005838
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005839#ifdef DEBUG
5840 // Ensure that all enumeration indexes between 1 and length occur uniquely in
5841 // the descriptor array.
5842 for (int i = 1; i <= len; ++i) {
5843 int j;
5844 for (j = 0; j < len; ++j) {
5845 if (GetDetails(j).index() == i) break;
5846 }
5847 ASSERT(j != len);
5848 for (j++; j < len; ++j) {
5849 ASSERT(GetDetails(j).index() != i);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005850 }
5851 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005852#endif
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005853
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00005854 for (int i = 0; i < len; ++i) {
5855 if (GetDetails(i).index() == len) {
5856 SetLastAdded(i);
5857 return;
5858 }
5859 }
5860
5861 UNREACHABLE();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00005862}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005863
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00005864
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005865void DescriptorArray::Sort(const WhitenessWitness& witness) {
5866 SortUnchecked(witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005867 SLOW_ASSERT(IsSortedNoDuplicates());
5868}
5869
5870
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005871MaybeObject* AccessorPair::Copy() {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005872 Heap* heap = GetHeap();
5873 AccessorPair* copy;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005874 MaybeObject* maybe_copy = heap->AllocateAccessorPair();
5875 if (!maybe_copy->To(&copy)) return maybe_copy;
5876
5877 copy->set_getter(getter());
5878 copy->set_setter(setter());
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005879 return copy;
5880}
5881
5882
danno@chromium.org88aa0582012-03-23 15:11:57 +00005883Object* AccessorPair::GetComponent(AccessorComponent component) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005884 Object* accessor = get(component);
5885 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00005886}
5887
5888
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005889MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5890 PretenureFlag pretenure) {
5891 ASSERT(deopt_entry_count > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005892 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005893 pretenure);
5894}
5895
5896
5897MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5898 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005899 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5900 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005901 pretenure);
5902}
5903
5904
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005905#ifdef DEBUG
5906bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5907 if (IsEmpty()) return other->IsEmpty();
5908 if (other->IsEmpty()) return false;
5909 if (length() != other->length()) return false;
5910 for (int i = 0; i < length(); ++i) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00005911 if (get(i) != other->get(i)) return false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005912 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +00005913 return true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005914}
5915#endif
5916
5917
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918bool String::LooksValid() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005919 if (!Isolate::Current()->heap()->Contains(this)) return false;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005920 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921}
5922
5923
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005924String::FlatContent String::GetFlatContent() {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005925 int length = this->length();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005926 StringShape shape(this);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005927 String* string = this;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00005928 int offset = 0;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005929 if (shape.representation_tag() == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005930 ConsString* cons = ConsString::cast(string);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005931 if (cons->second()->length() != 0) {
5932 return FlatContent();
5933 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005934 string = cons->first();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005935 shape = StringShape(string);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005936 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00005937 if (shape.representation_tag() == kSlicedStringTag) {
5938 SlicedString* slice = SlicedString::cast(string);
5939 offset = slice->offset();
5940 string = slice->parent();
5941 shape = StringShape(string);
5942 ASSERT(shape.representation_tag() != kConsStringTag &&
5943 shape.representation_tag() != kSlicedStringTag);
5944 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005945 if (shape.encoding_tag() == kAsciiStringTag) {
5946 const char* start;
5947 if (shape.representation_tag() == kSeqStringTag) {
5948 start = SeqAsciiString::cast(string)->GetChars();
5949 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00005950 start = ExternalAsciiString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005951 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00005952 return FlatContent(Vector<const char>(start + offset, length));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005953 } else {
5954 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
5955 const uc16* start;
5956 if (shape.representation_tag() == kSeqStringTag) {
5957 start = SeqTwoByteString::cast(string)->GetChars();
5958 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00005959 start = ExternalTwoByteString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005960 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00005961 return FlatContent(Vector<const uc16>(start + offset, length));
ager@chromium.org7c537e22008-10-16 08:43:32 +00005962 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005963}
5964
5965
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00005966SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5967 RobustnessFlag robust_flag,
5968 int offset,
5969 int length,
5970 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00005972 return SmartArrayPointer<char>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005974 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975
5976 // Negative length means the to the end of the string.
5977 if (length < 0) length = kMaxInt - offset;
5978
5979 // Compute the size of the UTF-8 string. Start at the specified offset.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005980 Access<StringInputBuffer> buffer(
5981 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982 buffer->Reset(offset, this);
5983 int character_position = offset;
5984 int utf8_bytes = 0;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005985 int last = unibrow::Utf16::kNoPreviousCharacter;
danno@chromium.orgc612e022011-11-10 11:38:15 +00005986 while (buffer->has_more() && character_position++ < offset + length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987 uint16_t character = buffer->GetNext();
yangguo@chromium.org154ff992012-03-13 08:09:54 +00005988 utf8_bytes += unibrow::Utf8::Length(character, last);
5989 last = character;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990 }
5991
5992 if (length_return) {
5993 *length_return = utf8_bytes;
5994 }
5995
5996 char* result = NewArray<char>(utf8_bytes + 1);
5997
5998 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
5999 buffer->Rewind();
6000 buffer->Seek(offset);
6001 character_position = offset;
6002 int utf8_byte_position = 0;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006003 last = unibrow::Utf16::kNoPreviousCharacter;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006004 while (buffer->has_more() && character_position++ < offset + length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006005 uint16_t character = buffer->GetNext();
danno@chromium.orgc612e022011-11-10 11:38:15 +00006006 if (allow_nulls == DISALLOW_NULLS && character == 0) {
6007 character = ' ';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00006009 utf8_byte_position +=
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006010 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
6011 last = character;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006012 }
6013 result[utf8_byte_position] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006014 return SmartArrayPointer<char>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015}
6016
6017
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006018SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6019 RobustnessFlag robust_flag,
6020 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006021 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
6022}
6023
6024
6025const uc16* String::GetTwoByteData() {
6026 return GetTwoByteData(0);
6027}
6028
6029
6030const uc16* String::GetTwoByteData(unsigned start) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006031 ASSERT(!IsAsciiRepresentationUnderneath());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006032 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006033 case kSeqStringTag:
ager@chromium.org7c537e22008-10-16 08:43:32 +00006034 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006035 case kExternalStringTag:
6036 return ExternalTwoByteString::cast(this)->
6037 ExternalTwoByteStringGetData(start);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006038 case kSlicedStringTag: {
6039 SlicedString* slice = SlicedString::cast(this);
6040 return slice->parent()->GetTwoByteData(start + slice->offset());
6041 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006042 case kConsStringTag:
6043 UNREACHABLE();
6044 return NULL;
6045 }
6046 UNREACHABLE();
6047 return NULL;
6048}
6049
6050
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006051SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006052 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006053 return SmartArrayPointer<uc16>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006054 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006055 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006056
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006057 Access<StringInputBuffer> buffer(
6058 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006059 buffer->Reset(this);
6060
6061 uc16* result = NewArray<uc16>(length() + 1);
6062
6063 int i = 0;
6064 while (buffer->has_more()) {
6065 uint16_t character = buffer->GetNext();
6066 result[i++] = character;
6067 }
6068 result[i] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006069 return SmartArrayPointer<uc16>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006070}
6071
6072
ager@chromium.org7c537e22008-10-16 08:43:32 +00006073const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006074 return reinterpret_cast<uc16*>(
6075 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
6076}
6077
6078
ager@chromium.org7c537e22008-10-16 08:43:32 +00006079void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00006080 unsigned* offset_ptr,
6081 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006082 unsigned chars_read = 0;
6083 unsigned offset = *offset_ptr;
6084 while (chars_read < max_chars) {
6085 uint16_t c = *reinterpret_cast<uint16_t*>(
6086 reinterpret_cast<char*>(this) -
6087 kHeapObjectTag + kHeaderSize + offset * kShortSize);
6088 if (c <= kMaxAsciiCharCode) {
6089 // Fast case for ASCII characters. Cursor is an input output argument.
6090 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6091 rbb->util_buffer,
6092 rbb->capacity,
6093 rbb->cursor)) {
6094 break;
6095 }
6096 } else {
6097 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6098 rbb->util_buffer,
6099 rbb->capacity,
6100 rbb->cursor)) {
6101 break;
6102 }
6103 }
6104 offset++;
6105 chars_read++;
6106 }
6107 *offset_ptr = offset;
6108 rbb->remaining += chars_read;
6109}
6110
6111
ager@chromium.org7c537e22008-10-16 08:43:32 +00006112const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
6113 unsigned* remaining,
6114 unsigned* offset_ptr,
6115 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006116 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
6117 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
6118 *remaining = max_chars;
6119 *offset_ptr += max_chars;
6120 return b;
6121}
6122
6123
6124// This will iterate unless the block of string data spans two 'halves' of
6125// a ConsString, in which case it will recurse. Since the block of string
6126// data to be read has a maximum size this limits the maximum recursion
6127// depth to something sane. Since C++ does not have tail call recursion
6128// elimination, the iteration must be explicit. Since this is not an
6129// -IntoBuffer method it can delegate to one of the efficient
6130// *AsciiStringReadBlock routines.
6131const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
6132 unsigned* offset_ptr,
6133 unsigned max_chars) {
6134 ConsString* current = this;
6135 unsigned offset = *offset_ptr;
6136 int offset_correction = 0;
6137
6138 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006139 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006140 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006141 if (left_length > offset &&
6142 (max_chars <= left_length - offset ||
6143 (rbb->capacity <= left_length - offset &&
6144 (max_chars = left_length - offset, true)))) { // comma operator!
6145 // Left hand side only - iterate unless we have reached the bottom of
6146 // the cons tree. The assignment on the left of the comma operator is
6147 // in order to make use of the fact that the -IntoBuffer routines can
6148 // produce at most 'capacity' characters. This enables us to postpone
6149 // the point where we switch to the -IntoBuffer routines (below) in order
6150 // to maximize the chances of delegating a big chunk of work to the
6151 // efficient *AsciiStringReadBlock routines.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006152 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006153 current = ConsString::cast(left);
6154 continue;
6155 } else {
6156 const unibrow::byte* answer =
6157 String::ReadBlock(left, rbb, &offset, max_chars);
6158 *offset_ptr = offset + offset_correction;
6159 return answer;
6160 }
6161 } else if (left_length <= offset) {
6162 // Right hand side only - iterate unless we have reached the bottom of
6163 // the cons tree.
ager@chromium.org870a0b62008-11-04 11:43:05 +00006164 String* right = current->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006165 offset -= left_length;
6166 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006167 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006168 current = ConsString::cast(right);
6169 continue;
6170 } else {
6171 const unibrow::byte* answer =
6172 String::ReadBlock(right, rbb, &offset, max_chars);
6173 *offset_ptr = offset + offset_correction;
6174 return answer;
6175 }
6176 } else {
6177 // The block to be read spans two sides of the ConsString, so we call the
6178 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
6179 // are able to assemble data from several part strings because they use
6180 // the util_buffer to store their data and never return direct pointers
6181 // to their storage. We don't try to read more than the buffer capacity
6182 // here or we can get too much recursion.
6183 ASSERT(rbb->remaining == 0);
6184 ASSERT(rbb->cursor == 0);
6185 current->ConsStringReadBlockIntoBuffer(
6186 rbb,
6187 &offset,
6188 max_chars > rbb->capacity ? rbb->capacity : max_chars);
6189 *offset_ptr = offset + offset_correction;
6190 return rbb->util_buffer;
6191 }
6192 }
6193}
6194
6195
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006196const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
6197 unsigned* remaining,
6198 unsigned* offset_ptr,
6199 unsigned max_chars) {
6200 // Cast const char* to unibrow::byte* (signedness difference).
6201 const unibrow::byte* b =
erikcorry0ad885c2011-11-21 13:51:57 +00006202 reinterpret_cast<const unibrow::byte*>(GetChars()) + *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203 *remaining = max_chars;
6204 *offset_ptr += max_chars;
6205 return b;
6206}
6207
6208
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006209void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
6210 ReadBlockBuffer* rbb,
6211 unsigned* offset_ptr,
6212 unsigned max_chars) {
6213 unsigned chars_read = 0;
6214 unsigned offset = *offset_ptr;
erikcorry0ad885c2011-11-21 13:51:57 +00006215 const uint16_t* data = GetChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006216 while (chars_read < max_chars) {
6217 uint16_t c = data[offset];
6218 if (c <= kMaxAsciiCharCode) {
ager@chromium.org80787b72009-04-17 10:24:24 +00006219 // Fast case for ASCII characters. Cursor is an input output argument.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6221 rbb->util_buffer,
6222 rbb->capacity,
6223 rbb->cursor))
6224 break;
6225 } else {
6226 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6227 rbb->util_buffer,
6228 rbb->capacity,
6229 rbb->cursor))
6230 break;
6231 }
6232 offset++;
6233 chars_read++;
6234 }
6235 *offset_ptr = offset;
6236 rbb->remaining += chars_read;
6237}
6238
6239
ager@chromium.org7c537e22008-10-16 08:43:32 +00006240void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006241 unsigned* offset_ptr,
6242 unsigned max_chars) {
6243 unsigned capacity = rbb->capacity - rbb->cursor;
6244 if (max_chars > capacity) max_chars = capacity;
6245 memcpy(rbb->util_buffer + rbb->cursor,
6246 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
6247 *offset_ptr * kCharSize,
6248 max_chars);
6249 rbb->remaining += max_chars;
6250 *offset_ptr += max_chars;
6251 rbb->cursor += max_chars;
6252}
6253
6254
6255void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
6256 ReadBlockBuffer* rbb,
6257 unsigned* offset_ptr,
6258 unsigned max_chars) {
6259 unsigned capacity = rbb->capacity - rbb->cursor;
6260 if (max_chars > capacity) max_chars = capacity;
erikcorry0ad885c2011-11-21 13:51:57 +00006261 memcpy(rbb->util_buffer + rbb->cursor, GetChars() + *offset_ptr, max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262 rbb->remaining += max_chars;
6263 *offset_ptr += max_chars;
6264 rbb->cursor += max_chars;
6265}
6266
6267
6268// This method determines the type of string involved and then copies
6269// a whole chunk of characters into a buffer, or returns a pointer to a buffer
6270// where they can be found. The pointer is not necessarily valid across a GC
6271// (see AsciiStringReadBlock).
6272const unibrow::byte* String::ReadBlock(String* input,
6273 ReadBlockBuffer* rbb,
6274 unsigned* offset_ptr,
6275 unsigned max_chars) {
6276 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
6277 if (max_chars == 0) {
6278 rbb->remaining = 0;
6279 return NULL;
6280 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006281 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006282 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006283 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006284 SeqAsciiString* str = SeqAsciiString::cast(input);
6285 return str->SeqAsciiStringReadBlock(&rbb->remaining,
6286 offset_ptr,
6287 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006288 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006289 SeqTwoByteString* str = SeqTwoByteString::cast(input);
6290 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6291 offset_ptr,
6292 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006293 return rbb->util_buffer;
6294 }
6295 case kConsStringTag:
6296 return ConsString::cast(input)->ConsStringReadBlock(rbb,
6297 offset_ptr,
6298 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006299 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006300 if (input->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006301 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
6302 &rbb->remaining,
6303 offset_ptr,
6304 max_chars);
6305 } else {
6306 ExternalTwoByteString::cast(input)->
6307 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6308 offset_ptr,
6309 max_chars);
6310 return rbb->util_buffer;
6311 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006312 case kSlicedStringTag:
6313 return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
6314 offset_ptr,
6315 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006316 default:
6317 break;
6318 }
6319
6320 UNREACHABLE();
6321 return 0;
6322}
6323
6324
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006325void Relocatable::PostGarbageCollectionProcessing() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006326 Isolate* isolate = Isolate::Current();
6327 Relocatable* current = isolate->relocatable_top();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006328 while (current != NULL) {
6329 current->PostGarbageCollection();
6330 current = current->prev_;
6331 }
6332}
6333
6334
6335// Reserve space for statics needing saving and restoring.
6336int Relocatable::ArchiveSpacePerThread() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006337 return sizeof(Isolate::Current()->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006338}
6339
6340
6341// Archive statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00006342char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006343 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
6344 isolate->set_relocatable_top(NULL);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006345 return to + ArchiveSpacePerThread();
6346}
6347
6348
6349// Restore statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00006350char* Relocatable::RestoreState(Isolate* isolate, char* from) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006351 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006352 return from + ArchiveSpacePerThread();
6353}
6354
6355
6356char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
6357 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
6358 Iterate(v, top);
6359 return thread_storage + ArchiveSpacePerThread();
6360}
6361
6362
6363void Relocatable::Iterate(ObjectVisitor* v) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006364 Isolate* isolate = Isolate::Current();
6365 Iterate(v, isolate->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006366}
6367
6368
6369void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
6370 Relocatable* current = top;
6371 while (current != NULL) {
6372 current->IterateInstance(v);
6373 current = current->prev_;
6374 }
6375}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006376
6377
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006378FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
6379 : Relocatable(isolate),
6380 str_(str.location()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006381 length_(str->length()) {
6382 PostGarbageCollection();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006383}
6384
6385
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006386FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
6387 : Relocatable(isolate),
6388 str_(0),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006389 is_ascii_(true),
6390 length_(input.length()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006391 start_(input.start()) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006392
6393
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006394void FlatStringReader::PostGarbageCollection() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006395 if (str_ == NULL) return;
6396 Handle<String> str(str_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006397 ASSERT(str->IsFlat());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006398 String::FlatContent content = str->GetFlatContent();
6399 ASSERT(content.IsFlat());
6400 is_ascii_ = content.IsAscii();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006401 if (is_ascii_) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006402 start_ = content.ToAsciiVector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006403 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006404 start_ = content.ToUC16Vector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006405 }
6406}
6407
6408
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006409void StringInputBuffer::Seek(unsigned pos) {
6410 Reset(pos, input_);
6411}
6412
6413
6414void SafeStringInputBuffer::Seek(unsigned pos) {
6415 Reset(pos, input_);
6416}
6417
6418
6419// This method determines the type of string involved and then copies
6420// a whole chunk of characters into a buffer. It can be used with strings
6421// that have been glued together to form a ConsString and which must cooperate
6422// to fill up a buffer.
6423void String::ReadBlockIntoBuffer(String* input,
6424 ReadBlockBuffer* rbb,
6425 unsigned* offset_ptr,
6426 unsigned max_chars) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006427 ASSERT(*offset_ptr <= (unsigned)input->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006428 if (max_chars == 0) return;
6429
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006430 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006431 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006432 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006433 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434 offset_ptr,
6435 max_chars);
6436 return;
6437 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006438 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006439 offset_ptr,
6440 max_chars);
6441 return;
6442 }
6443 case kConsStringTag:
6444 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
6445 offset_ptr,
6446 max_chars);
6447 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006448 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006449 if (input->IsAsciiRepresentation()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006450 ExternalAsciiString::cast(input)->
6451 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
6452 } else {
6453 ExternalTwoByteString::cast(input)->
6454 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6455 offset_ptr,
6456 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457 }
6458 return;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006459 case kSlicedStringTag:
6460 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
6461 offset_ptr,
6462 max_chars);
6463 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006464 default:
6465 break;
6466 }
6467
6468 UNREACHABLE();
6469 return;
6470}
6471
6472
6473const unibrow::byte* String::ReadBlock(String* input,
6474 unibrow::byte* util_buffer,
6475 unsigned capacity,
6476 unsigned* remaining,
6477 unsigned* offset_ptr) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006478 ASSERT(*offset_ptr <= (unsigned)input->length());
6479 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006480 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6481 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006482 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006483 *remaining = rbb.remaining;
6484 return answer;
6485}
6486
6487
6488const unibrow::byte* String::ReadBlock(String** raw_input,
6489 unibrow::byte* util_buffer,
6490 unsigned capacity,
6491 unsigned* remaining,
6492 unsigned* offset_ptr) {
6493 Handle<String> input(raw_input);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006494 ASSERT(*offset_ptr <= (unsigned)input->length());
6495 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006496 if (chars > capacity) chars = capacity;
6497 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6498 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006499 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500 *remaining = rbb.remaining;
6501 return rbb.util_buffer;
6502}
6503
6504
6505// This will iterate unless the block of string data spans two 'halves' of
6506// a ConsString, in which case it will recurse. Since the block of string
6507// data to be read has a maximum size this limits the maximum recursion
6508// depth to something sane. Since C++ does not have tail call recursion
6509// elimination, the iteration must be explicit.
6510void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6511 unsigned* offset_ptr,
6512 unsigned max_chars) {
6513 ConsString* current = this;
6514 unsigned offset = *offset_ptr;
6515 int offset_correction = 0;
6516
6517 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006518 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006519 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006520 if (left_length > offset &&
6521 max_chars <= left_length - offset) {
6522 // Left hand side only - iterate unless we have reached the bottom of
6523 // the cons tree.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006524 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525 current = ConsString::cast(left);
6526 continue;
6527 } else {
6528 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
6529 *offset_ptr = offset + offset_correction;
6530 return;
6531 }
6532 } else if (left_length <= offset) {
6533 // Right hand side only - iterate unless we have reached the bottom of
6534 // the cons tree.
6535 offset -= left_length;
6536 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006537 String* right = current->second();
6538 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006539 current = ConsString::cast(right);
6540 continue;
6541 } else {
6542 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6543 *offset_ptr = offset + offset_correction;
6544 return;
6545 }
6546 } else {
6547 // The block to be read spans two sides of the ConsString, so we recurse.
6548 // First recurse on the left.
6549 max_chars -= left_length - offset;
6550 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
6551 // We may have reached the max or there may not have been enough space
6552 // in the buffer for the characters in the left hand side.
6553 if (offset == left_length) {
6554 // Recurse on the right.
6555 String* right = String::cast(current->second());
6556 offset -= left_length;
6557 offset_correction += left_length;
6558 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6559 }
6560 *offset_ptr = offset + offset_correction;
6561 return;
6562 }
6563 }
6564}
6565
6566
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567uint16_t ConsString::ConsStringGet(int index) {
6568 ASSERT(index >= 0 && index < this->length());
6569
6570 // Check for a flattened cons string
ager@chromium.org870a0b62008-11-04 11:43:05 +00006571 if (second()->length() == 0) {
6572 String* left = first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006573 return left->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006574 }
6575
6576 String* string = String::cast(this);
6577
6578 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006579 if (StringShape(string).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006580 ConsString* cons_string = ConsString::cast(string);
ager@chromium.org870a0b62008-11-04 11:43:05 +00006581 String* left = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006582 if (left->length() > index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583 string = left;
6584 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006585 index -= left->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006586 string = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587 }
6588 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006589 return string->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006590 }
6591 }
6592
6593 UNREACHABLE();
6594 return 0;
6595}
6596
6597
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006598uint16_t SlicedString::SlicedStringGet(int index) {
6599 return parent()->Get(offset() + index);
6600}
6601
6602
6603const unibrow::byte* SlicedString::SlicedStringReadBlock(
6604 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6605 unsigned offset = this->offset();
6606 *offset_ptr += offset;
6607 const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
6608 buffer, offset_ptr, chars);
6609 *offset_ptr -= offset;
6610 return answer;
6611}
6612
6613
6614void SlicedString::SlicedStringReadBlockIntoBuffer(
6615 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6616 unsigned offset = this->offset();
6617 *offset_ptr += offset;
6618 String::ReadBlockIntoBuffer(String::cast(parent()),
6619 buffer, offset_ptr, chars);
6620 *offset_ptr -= offset;
6621}
6622
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006623template <typename sinkchar>
6624void String::WriteToFlat(String* src,
6625 sinkchar* sink,
6626 int f,
6627 int t) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006628 String* source = src;
6629 int from = f;
6630 int to = t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006631 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006632 ASSERT(0 <= from && from <= to && to <= source->length());
6633 switch (StringShape(source).full_representation_tag()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006634 case kAsciiStringTag | kExternalStringTag: {
6635 CopyChars(sink,
erikcorry0ad885c2011-11-21 13:51:57 +00006636 ExternalAsciiString::cast(source)->GetChars() + from,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006637 to - from);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638 return;
6639 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006640 case kTwoByteStringTag | kExternalStringTag: {
6641 const uc16* data =
erikcorry0ad885c2011-11-21 13:51:57 +00006642 ExternalTwoByteString::cast(source)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006643 CopyChars(sink,
6644 data + from,
6645 to - from);
6646 return;
6647 }
6648 case kAsciiStringTag | kSeqStringTag: {
6649 CopyChars(sink,
6650 SeqAsciiString::cast(source)->GetChars() + from,
6651 to - from);
6652 return;
6653 }
6654 case kTwoByteStringTag | kSeqStringTag: {
6655 CopyChars(sink,
6656 SeqTwoByteString::cast(source)->GetChars() + from,
6657 to - from);
6658 return;
6659 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006660 case kAsciiStringTag | kConsStringTag:
6661 case kTwoByteStringTag | kConsStringTag: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006662 ConsString* cons_string = ConsString::cast(source);
ager@chromium.org870a0b62008-11-04 11:43:05 +00006663 String* first = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006664 int boundary = first->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006665 if (to - boundary >= boundary - from) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006666 // Right hand side is longer. Recurse over left.
6667 if (from < boundary) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006668 WriteToFlat(first, sink, from, boundary);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006669 sink += boundary - from;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006670 from = 0;
6671 } else {
6672 from -= boundary;
6673 }
6674 to -= boundary;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006675 source = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006676 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006677 // Left hand side is longer. Recurse over right.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006678 if (to > boundary) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006679 String* second = cons_string->second();
ulan@chromium.org812308e2012-02-29 15:58:45 +00006680 // When repeatedly appending to a string, we get a cons string that
6681 // is unbalanced to the left, a list, essentially. We inline the
6682 // common case of sequential ascii right child.
6683 if (to - boundary == 1) {
6684 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
6685 } else if (second->IsSeqAsciiString()) {
6686 CopyChars(sink + boundary - from,
6687 SeqAsciiString::cast(second)->GetChars(),
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006688 to - boundary);
ulan@chromium.org812308e2012-02-29 15:58:45 +00006689 } else {
6690 WriteToFlat(second,
6691 sink + boundary - from,
6692 0,
6693 to - boundary);
6694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006695 to = boundary;
6696 }
6697 source = first;
6698 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006699 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006700 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006701 case kAsciiStringTag | kSlicedStringTag:
6702 case kTwoByteStringTag | kSlicedStringTag: {
6703 SlicedString* slice = SlicedString::cast(source);
6704 unsigned offset = slice->offset();
6705 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
6706 return;
6707 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006708 }
6709 }
6710}
6711
6712
ager@chromium.org7c537e22008-10-16 08:43:32 +00006713template <typename IteratorA, typename IteratorB>
6714static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
6715 // General slow case check. We know that the ia and ib iterators
6716 // have the same length.
6717 while (ia->has_more()) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006718 uint32_t ca = ia->GetNext();
6719 uint32_t cb = ib->GetNext();
6720 ASSERT(ca <= unibrow::Utf16::kMaxNonSurrogateCharCode);
6721 ASSERT(cb <= unibrow::Utf16::kMaxNonSurrogateCharCode);
ager@chromium.org7c537e22008-10-16 08:43:32 +00006722 if (ca != cb)
6723 return false;
6724 }
6725 return true;
6726}
6727
6728
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006729// Compares the contents of two strings by reading and comparing
6730// int-sized blocks of characters.
6731template <typename Char>
6732static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
6733 int length = a.length();
6734 ASSERT_EQ(length, b.length());
6735 const Char* pa = a.start();
6736 const Char* pb = b.start();
6737 int i = 0;
ager@chromium.org9085a012009-05-11 19:22:57 +00006738#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006739 // If this architecture isn't comfortable reading unaligned ints
6740 // then we have to check that the strings are aligned before
6741 // comparing them blockwise.
6742 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
6743 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
6744 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006745 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006746#endif
6747 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
6748 int endpoint = length - kStepSize;
6749 // Compare blocks until we reach near the end of the string.
6750 for (; i <= endpoint; i += kStepSize) {
6751 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
6752 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
6753 if (wa != wb) {
6754 return false;
6755 }
6756 }
ager@chromium.org9085a012009-05-11 19:22:57 +00006757#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006758 }
6759#endif
6760 // Compare the remaining characters that didn't fit into a block.
6761 for (; i < length; i++) {
6762 if (a[i] != b[i]) {
6763 return false;
6764 }
6765 }
6766 return true;
6767}
6768
6769
ager@chromium.org7c537e22008-10-16 08:43:32 +00006770template <typename IteratorA>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006771static inline bool CompareStringContentsPartial(Isolate* isolate,
6772 IteratorA* ia,
6773 String* b) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006774 String::FlatContent content = b->GetFlatContent();
6775 if (content.IsFlat()) {
6776 if (content.IsAscii()) {
6777 VectorIterator<char> ib(content.ToAsciiVector());
ager@chromium.org7c537e22008-10-16 08:43:32 +00006778 return CompareStringContents(ia, &ib);
6779 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006780 VectorIterator<uc16> ib(content.ToUC16Vector());
ager@chromium.org7c537e22008-10-16 08:43:32 +00006781 return CompareStringContents(ia, &ib);
6782 }
6783 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006784 isolate->objects_string_compare_buffer_b()->Reset(0, b);
6785 return CompareStringContents(ia,
6786 isolate->objects_string_compare_buffer_b());
ager@chromium.org7c537e22008-10-16 08:43:32 +00006787 }
6788}
6789
6790
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006791bool String::SlowEquals(String* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006792 // Fast check: negative check with lengths.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006793 int len = length();
6794 if (len != other->length()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795 if (len == 0) return true;
6796
6797 // Fast check: if hash code is computed for both strings
6798 // a fast negative check can be performed.
6799 if (HasHashCode() && other->HasHashCode()) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006800#ifdef DEBUG
6801 if (FLAG_enable_slow_asserts) {
6802 if (Hash() != other->Hash()) {
6803 bool found_difference = false;
6804 for (int i = 0; i < len; i++) {
6805 if (Get(i) != other->Get(i)) {
6806 found_difference = true;
6807 break;
6808 }
6809 }
6810 ASSERT(found_difference);
6811 }
6812 }
6813#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006814 if (Hash() != other->Hash()) return false;
6815 }
6816
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006817 // We know the strings are both non-empty. Compare the first chars
6818 // before we try to flatten the strings.
6819 if (this->Get(0) != other->Get(0)) return false;
6820
6821 String* lhs = this->TryFlattenGetString();
6822 String* rhs = other->TryFlattenGetString();
6823
6824 if (StringShape(lhs).IsSequentialAscii() &&
6825 StringShape(rhs).IsSequentialAscii()) {
6826 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
6827 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006828 return CompareRawStringContents(Vector<const char>(str1, len),
6829 Vector<const char>(str2, len));
6830 }
6831
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006832 Isolate* isolate = GetIsolate();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006833 String::FlatContent lhs_content = lhs->GetFlatContent();
6834 String::FlatContent rhs_content = rhs->GetFlatContent();
6835 if (lhs_content.IsFlat()) {
6836 if (lhs_content.IsAscii()) {
6837 Vector<const char> vec1 = lhs_content.ToAsciiVector();
6838 if (rhs_content.IsFlat()) {
6839 if (rhs_content.IsAscii()) {
6840 Vector<const char> vec2 = rhs_content.ToAsciiVector();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006841 return CompareRawStringContents(vec1, vec2);
6842 } else {
6843 VectorIterator<char> buf1(vec1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006844 VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006845 return CompareStringContents(&buf1, &ib);
6846 }
6847 } else {
6848 VectorIterator<char> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006849 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6850 return CompareStringContents(&buf1,
6851 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006852 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006853 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006854 Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
6855 if (rhs_content.IsFlat()) {
6856 if (rhs_content.IsAscii()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006857 VectorIterator<uc16> buf1(vec1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006858 VectorIterator<char> ib(rhs_content.ToAsciiVector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006859 return CompareStringContents(&buf1, &ib);
6860 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006861 Vector<const uc16> vec2(rhs_content.ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006862 return CompareRawStringContents(vec1, vec2);
6863 }
6864 } else {
6865 VectorIterator<uc16> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006866 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6867 return CompareStringContents(&buf1,
6868 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006869 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006870 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006871 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006872 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
6873 return CompareStringContentsPartial(isolate,
6874 isolate->objects_string_compare_buffer_a(), rhs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006875 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006876}
6877
6878
6879bool String::MarkAsUndetectable() {
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00006880 if (StringShape(this).IsSymbol()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006881
6882 Map* map = this->map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006883 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006884 if (map == heap->string_map()) {
6885 this->set_map(heap->undetectable_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006886 return true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006887 } else if (map == heap->ascii_string_map()) {
6888 this->set_map(heap->undetectable_ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006889 return true;
6890 }
6891 // Rest cannot be marked as undetectable
6892 return false;
6893}
6894
6895
6896bool String::IsEqualTo(Vector<const char> str) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006897 Isolate* isolate = GetIsolate();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006898 int slen = length();
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006899 Access<UnicodeCache::Utf8Decoder>
6900 decoder(isolate->unicode_cache()->utf8_decoder());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006901 decoder->Reset(str.start(), str.length());
6902 int i;
6903 for (i = 0; i < slen && decoder->has_more(); i++) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00006904 uint32_t r = decoder->GetNext();
6905 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
6906 if (i > slen - 1) return false;
6907 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
6908 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
6909 } else {
6910 if (Get(i) != r) return false;
6911 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006912 }
6913 return i == slen && !decoder->has_more();
6914}
6915
6916
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00006917bool String::IsAsciiEqualTo(Vector<const char> str) {
6918 int slen = length();
6919 if (str.length() != slen) return false;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006920 FlatContent content = GetFlatContent();
6921 if (content.IsAscii()) {
6922 return CompareChars(content.ToAsciiVector().start(),
6923 str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006924 }
6925 for (int i = 0; i < slen; i++) {
6926 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00006927 }
6928 return true;
6929}
6930
6931
6932bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
6933 int slen = length();
6934 if (str.length() != slen) return false;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006935 FlatContent content = GetFlatContent();
6936 if (content.IsTwoByte()) {
6937 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006938 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00006939 for (int i = 0; i < slen; i++) {
6940 if (Get(i) != str[i]) return false;
6941 }
6942 return true;
6943}
6944
6945
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006946uint32_t String::ComputeAndSetHash() {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00006947 // Should only be called if hash code has not yet been computed.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006948 ASSERT(!HasHashCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006949
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00006950 const int len = length();
6951
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006952 // Compute the hash code.
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00006953 uint32_t field = 0;
6954 if (StringShape(this).IsSequentialAscii()) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006955 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(),
6956 len,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006957 GetHeap()->HashSeed());
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00006958 } else if (StringShape(this).IsSequentialTwoByte()) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006959 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(),
6960 len,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006961 GetHeap()->HashSeed());
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00006962 } else {
6963 StringInputBuffer buffer(this);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006964 field = ComputeHashField(&buffer, len, GetHeap()->HashSeed());
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00006965 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006966
6967 // Store the hash code in the object.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006968 set_hash_field(field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006969
6970 // Check the hash code is there.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006971 ASSERT(HasHashCode());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00006972 uint32_t result = field >> kHashShift;
6973 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
6974 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006975}
6976
6977
6978bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
6979 uint32_t* index,
6980 int length) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006981 if (length == 0 || length > kMaxArrayIndexSize) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006982 uc32 ch = buffer->GetNext();
6983
6984 // If the string begins with a '0' character, it must only consist
6985 // of it to be a legal array index.
6986 if (ch == '0') {
6987 *index = 0;
6988 return length == 1;
6989 }
6990
6991 // Convert string to uint32 array index; character by character.
6992 int d = ch - '0';
6993 if (d < 0 || d > 9) return false;
6994 uint32_t result = d;
6995 while (buffer->has_more()) {
6996 d = buffer->GetNext() - '0';
6997 if (d < 0 || d > 9) return false;
6998 // Check that the new result is below the 32 bit limit.
6999 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
7000 result = (result * 10) + d;
7001 }
7002
7003 *index = result;
7004 return true;
7005}
7006
7007
7008bool String::SlowAsArrayIndex(uint32_t* index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007009 if (length() <= kMaxCachedArrayIndexLength) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007010 Hash(); // force computation of hash code
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007011 uint32_t field = hash_field();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007012 if ((field & kIsNotArrayIndexMask) != 0) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007013 // Isolate the array index form the full hash field.
7014 *index = (kArrayIndexHashMask & field) >> kHashShift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007015 return true;
7016 } else {
7017 StringInputBuffer buffer(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007018 return ComputeArrayIndex(&buffer, index, length());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007020}
7021
7022
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007023uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007024 // For array indexes mix the length into the hash as an array index could
7025 // be zero.
7026 ASSERT(length > 0);
7027 ASSERT(length <= String::kMaxArrayIndexSize);
7028 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
7029 (1 << String::kArrayIndexValueBits));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007030
7031 value <<= String::kHashShift;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007032 value |= length << String::kArrayIndexHashLengthShift;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007033
7034 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
7035 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
7036 (value & String::kContainsCachedArrayIndexMask) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007037 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007038}
7039
7040
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007041void StringHasher::AddSurrogatePair(uc32 c) {
7042 uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
7043 AddCharacter(lead);
7044 uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
7045 AddCharacter(trail);
7046}
7047
7048
7049void StringHasher::AddSurrogatePairNoIndex(uc32 c) {
7050 uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
7051 AddCharacterNoIndex(lead);
7052 uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
7053 AddCharacterNoIndex(trail);
7054}
7055
7056
ager@chromium.org7c537e22008-10-16 08:43:32 +00007057uint32_t StringHasher::GetHashField() {
7058 ASSERT(is_valid());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007059 if (length_ <= String::kMaxHashCalcLength) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007060 if (is_array_index()) {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007061 return MakeArrayIndexHash(array_index(), length_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00007062 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007063 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
ager@chromium.org7c537e22008-10-16 08:43:32 +00007064 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007065 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007066 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007067}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007069
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007070uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00007071 int length,
7072 uint32_t seed) {
7073 StringHasher hasher(length, seed);
ager@chromium.org7c537e22008-10-16 08:43:32 +00007074
7075 // Very long strings have a trivial hash that doesn't inspect the
7076 // string contents.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007077 if (hasher.has_trivial_hash()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007078 return hasher.GetHashField();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007079 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007080
7081 // Do the iterative array index computation as long as there is a
7082 // chance this is an array index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007083 while (buffer->has_more() && hasher.is_array_index()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007084 hasher.AddCharacter(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007085 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007086
7087 // Process the remaining characters without updating the array
7088 // index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007089 while (buffer->has_more()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007090 hasher.AddCharacterNoIndex(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007091 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007092
7093 return hasher.GetHashField();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007094}
7095
7096
lrn@chromium.org303ada72010-10-27 09:33:13 +00007097MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007098 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007099 if (start == 0 && end == length()) return this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007100 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007101 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007102}
7103
7104
7105void String::PrintOn(FILE* file) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007106 int length = this->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107 for (int i = 0; i < length; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007108 fprintf(file, "%c", Get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007109 }
7110}
7111
7112
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007113// This function should only be called from within the GC, since it uses
7114// IncrementLiveBytesFromGC. If called from anywhere else, this results in an
7115// inconsistent live-bytes count.
7116static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
7117 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
7118 // For now this trick is only applied to fixed arrays in new and paged space.
7119 // In large object space the object's start must coincide with chunk
7120 // and thus the trick is just not applicable.
7121 ASSERT(!HEAP->lo_space()->Contains(elms));
7122
7123 const int len = elms->length();
7124
7125 ASSERT(to_trim < len);
7126
7127 Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim);
7128
7129#ifdef DEBUG
7130 // If we are doing a big trim in old space then we zap the space.
7131 Object** zap = reinterpret_cast<Object**>(new_end);
7132 for (int i = 1; i < to_trim; i++) {
7133 *zap++ = Smi::FromInt(0);
7134 }
7135#endif
7136
7137 int size_delta = to_trim * kPointerSize;
7138
7139 // Technically in new space this write might be omitted (except for
7140 // debug mode which iterates through the heap), but to play safer
7141 // we still do it.
7142 heap->CreateFillerObjectAt(new_end, size_delta);
7143
7144 elms->set_length(len - to_trim);
7145
7146 // Maintain marking consistency for IncrementalMarking.
7147 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) {
7148 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta);
7149 }
7150}
7151
7152
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007153// Clear a possible back pointer in case the transition leads to a dead map.
7154// Return true in case a back pointer has been cleared and false otherwise.
7155static bool ClearBackPointer(Heap* heap, Object* target) {
7156 ASSERT(target->IsMap());
7157 Map* map = Map::cast(target);
7158 if (Marking::MarkBitFrom(map).Get()) return false;
7159 map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007160 return true;
7161}
7162
7163
7164// TODO(mstarzinger): This method should be moved into MarkCompactCollector,
7165// because it cannot be called from outside the GC and we already have methods
7166// depending on the transitions layout in the GC anyways.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00007167void Map::ClearNonLiveTransitions(Heap* heap) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007168 // If there are no transitions to be cleared, return.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007169 // TODO(verwaest) Should be an assert, otherwise back pointers are not
7170 // properly cleared.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007171 if (!HasTransitionArray()) return;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007172
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007173 TransitionArray* t = transitions();
7174
7175 int transition_index = 0;
7176
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007177 // Compact all live descriptors to the left.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007178 for (int i = 0; i < t->number_of_transitions(); ++i) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007179 if (!ClearBackPointer(heap, t->GetTarget(i))) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007180 if (i != transition_index) {
7181 String* key = t->GetKey(i);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007182 Map* target = t->GetTarget(i);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007183 t->SetKey(transition_index, key);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007184 t->SetTarget(transition_index, target);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007185 MarkCompactCollector* collector = heap->mark_compact_collector();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007186 Object** key_slot = t->GetKeySlot(transition_index);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007187 collector->RecordSlot(key_slot, key_slot, key);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007188 Object** target_slot = t->GetTargetSlot(transition_index);
7189 collector->RecordSlot(target_slot, target_slot, target);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007190 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007191 transition_index++;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007192 }
7193 }
7194
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007195 if (t->HasElementsTransition() &&
7196 ClearBackPointer(heap, t->elements_transition())) {
7197 t->ClearElementsTransition();
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007198 } else {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007199 // If there are no transitions to be cleared, return.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007200 // TODO(verwaest) Should be an assert, otherwise back pointers are not
7201 // properly cleared.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007202 if (transition_index == t->number_of_transitions()) return;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00007203 }
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007204
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007205 // If the final transition array does not contain any live transitions, remove
7206 // the transition array from the map.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00007207 if (transition_index == 0 &&
7208 !t->HasElementsTransition() &&
7209 !t->HasPrototypeTransitions()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00007210 return ClearTransitions(heap);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007211 }
7212
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007213 int trim = t->number_of_transitions() - transition_index;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007214 if (trim > 0) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007215 RightTrimFixedArray(heap, t, trim * TransitionArray::kTransitionSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007216 }
7217}
7218
7219
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007220int Map::Hash() {
7221 // For performance reasons we only hash the 3 most variable fields of a map:
7222 // constructor, prototype and bit_field2.
7223
7224 // Shift away the tag.
7225 int hash = (static_cast<uint32_t>(
7226 reinterpret_cast<uintptr_t>(constructor())) >> 2);
7227
7228 // XOR-ing the prototype and constructor directly yields too many zero bits
7229 // when the two pointers are close (which is fairly common).
7230 // To avoid this we shift the prototype 4 bits relatively to the constructor.
7231 hash ^= (static_cast<uint32_t>(
7232 reinterpret_cast<uintptr_t>(prototype())) << 2);
7233
7234 return hash ^ (hash >> 16) ^ bit_field2();
7235}
7236
7237
7238bool Map::EquivalentToForNormalization(Map* other,
7239 PropertyNormalizationMode mode) {
7240 return
7241 constructor() == other->constructor() &&
7242 prototype() == other->prototype() &&
7243 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
7244 0 :
7245 other->inobject_properties()) &&
7246 instance_type() == other->instance_type() &&
7247 bit_field() == other->bit_field() &&
7248 bit_field2() == other->bit_field2() &&
7249 (bit_field3() & ~(1<<Map::kIsShared)) ==
7250 (other->bit_field3() & ~(1<<Map::kIsShared));
7251}
7252
7253
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00007254void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
7255 // Iterate over all fields in the body but take care in dealing with
7256 // the code entry.
7257 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
7258 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
7259 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
7260}
7261
7262
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007263void JSFunction::MarkForLazyRecompilation() {
7264 ASSERT(is_compiled() && !IsOptimized());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007265 ASSERT(shared()->allows_lazy_compilation() ||
7266 code()->optimizable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007267 Builtins* builtins = GetIsolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007268 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007269}
7270
7271
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007272static bool CompileLazyHelper(CompilationInfo* info,
7273 ClearExceptionFlag flag) {
7274 // Compile the source information to a code object.
7275 ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
7276 ASSERT(!info->isolate()->has_pending_exception());
7277 bool result = Compiler::CompileLazy(info);
7278 ASSERT(result != Isolate::Current()->has_pending_exception());
7279 if (!result && flag == CLEAR_EXCEPTION) {
7280 info->isolate()->clear_pending_exception();
7281 }
7282 return result;
7283}
7284
7285
7286bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
7287 ClearExceptionFlag flag) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00007288 ASSERT(shared->allows_lazy_compilation_without_context());
7289 CompilationInfoWithZone info(shared);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007290 return CompileLazyHelper(&info, flag);
7291}
7292
7293
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00007294void SharedFunctionInfo::ClearOptimizedCodeMap() {
7295 set_optimized_code_map(Smi::FromInt(0));
7296}
7297
7298
7299void SharedFunctionInfo::AddToOptimizedCodeMap(
7300 Handle<SharedFunctionInfo> shared,
7301 Handle<Context> global_context,
7302 Handle<Code> code,
7303 Handle<FixedArray> literals) {
7304 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
7305 ASSERT(global_context->IsGlobalContext());
7306 STATIC_ASSERT(kEntryLength == 3);
7307 Object* value = shared->optimized_code_map();
7308 Handle<FixedArray> new_code_map;
7309 if (value->IsSmi()) {
7310 // No optimized code map.
7311 ASSERT_EQ(0, Smi::cast(value)->value());
7312 // Crate 3 entries per context {context, code, literals}.
7313 new_code_map = FACTORY->NewFixedArray(kEntryLength);
7314 new_code_map->set(0, *global_context);
7315 new_code_map->set(1, *code);
7316 new_code_map->set(2, *literals);
7317 } else {
7318 // Copy old map and append one new entry.
7319 Handle<FixedArray> old_code_map(FixedArray::cast(value));
7320 ASSERT_EQ(-1, shared->SearchOptimizedCodeMap(*global_context));
7321 int old_length = old_code_map->length();
7322 int new_length = old_length + kEntryLength;
7323 new_code_map = FACTORY->NewFixedArray(new_length);
7324 old_code_map->CopyTo(0, *new_code_map, 0, old_length);
7325 new_code_map->set(old_length, *global_context);
7326 new_code_map->set(old_length + 1, *code);
7327 new_code_map->set(old_length + 2, *literals);
7328 }
7329#ifdef DEBUG
7330 for (int i = 0; i < new_code_map->length(); i += kEntryLength) {
7331 ASSERT(new_code_map->get(i)->IsGlobalContext());
7332 ASSERT(new_code_map->get(i + 1)->IsCode());
7333 ASSERT(Code::cast(new_code_map->get(i + 1))->kind() ==
7334 Code::OPTIMIZED_FUNCTION);
7335 ASSERT(new_code_map->get(i + 2)->IsFixedArray());
7336 }
7337#endif
7338 shared->set_optimized_code_map(*new_code_map);
7339}
7340
7341
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00007342void SharedFunctionInfo::InstallFromOptimizedCodeMap(JSFunction* function,
7343 int index) {
7344 ASSERT(index > 0);
7345 ASSERT(optimized_code_map()->IsFixedArray());
7346 FixedArray* code_map = FixedArray::cast(optimized_code_map());
7347 if (!bound()) {
7348 FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
7349 ASSERT(cached_literals != NULL);
7350 function->set_literals(cached_literals);
7351 }
7352 Code* code = Code::cast(code_map->get(index));
7353 ASSERT(code != NULL);
7354 ASSERT(function->context()->global_context() == code_map->get(index - 1));
7355 function->ReplaceCode(code);
7356}
7357
7358
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007359bool JSFunction::CompileLazy(Handle<JSFunction> function,
7360 ClearExceptionFlag flag) {
7361 bool result = true;
7362 if (function->shared()->is_compiled()) {
7363 function->ReplaceCode(function->shared()->code());
7364 function->shared()->set_code_age(0);
7365 } else {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00007366 ASSERT(function->shared()->allows_lazy_compilation());
7367 CompilationInfoWithZone info(function);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007368 result = CompileLazyHelper(&info, flag);
7369 ASSERT(!result || function->is_compiled());
7370 }
7371 return result;
7372}
7373
7374
7375bool JSFunction::CompileOptimized(Handle<JSFunction> function,
7376 int osr_ast_id,
7377 ClearExceptionFlag flag) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00007378 CompilationInfoWithZone info(function);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007379 info.SetOptimizing(osr_ast_id);
7380 return CompileLazyHelper(&info, flag);
7381}
7382
7383
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00007384bool JSFunction::EnsureCompiled(Handle<JSFunction> function,
7385 ClearExceptionFlag flag) {
7386 return function->is_compiled() || CompileLazy(function, flag);
7387}
7388
7389
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007390bool JSFunction::IsInlineable() {
7391 if (IsBuiltin()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007392 SharedFunctionInfo* shared_info = shared();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007393 // Check that the function has a script associated with it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007394 if (!shared_info->script()->IsScript()) return false;
7395 if (shared_info->optimization_disabled()) return false;
7396 Code* code = shared_info->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007397 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
7398 // If we never ran this (unlikely) then lets try to optimize it.
7399 if (code->kind() != Code::FUNCTION) return true;
7400 return code->optimizable();
7401}
7402
7403
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007404MaybeObject* JSObject::OptimizeAsPrototype() {
7405 if (IsGlobalObject()) return this;
7406
7407 // Make sure prototypes are fast objects and their maps have the bit set
7408 // so they remain fast.
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00007409 if (!HasFastProperties()) {
7410 MaybeObject* new_proto = TransformToFastProperties(0);
7411 if (new_proto->IsFailure()) return new_proto;
7412 ASSERT(new_proto == this);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007413 }
7414 return this;
7415}
7416
7417
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007418MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00007419 ASSERT(value->IsJSReceiver());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007420 Heap* heap = GetHeap();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007421
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00007422 // First some logic for the map of the prototype to make sure it is in fast
7423 // mode.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007424 if (value->IsJSObject()) {
7425 MaybeObject* ok = JSObject::cast(value)->OptimizeAsPrototype();
7426 if (ok->IsFailure()) return ok;
7427 }
7428
7429 // Now some logic for the maps of the objects that are created by using this
7430 // function as a constructor.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007431 if (has_initial_map()) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007432 // If the function has allocated the initial map
7433 // replace it with a copy containing the new prototype.
7434 Map* new_map;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007435 MaybeObject* maybe_new_map =
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007436 initial_map()->Copy(DescriptorArray::MAY_BE_SHARED);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007437 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
7438 new_map->set_prototype(value);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007439 MaybeObject* maybe_object = set_initial_map_and_cache_transitions(new_map);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007440 if (maybe_object->IsFailure()) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007441 } else {
7442 // Put the value in the initial map field until an initial map is
7443 // needed. At that point, a new initial map is created and the
7444 // prototype is put into the initial map where it belongs.
7445 set_prototype_or_initial_map(value);
7446 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007447 heap->ClearInstanceofCache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007448 return value;
7449}
7450
7451
lrn@chromium.org303ada72010-10-27 09:33:13 +00007452MaybeObject* JSFunction::SetPrototype(Object* value) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007453 ASSERT(should_have_prototype());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454 Object* construct_prototype = value;
7455
danno@chromium.org88aa0582012-03-23 15:11:57 +00007456 // If the value is not a JSReceiver, store the value in the map's
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007457 // constructor field so it can be accessed. Also, set the prototype
7458 // used for constructing objects to the original object prototype.
7459 // See ECMA-262 13.2.2.
danno@chromium.org88aa0582012-03-23 15:11:57 +00007460 if (!value->IsJSReceiver()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007461 // Copy the map so this does not affect unrelated functions.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007462 // Remove map transitions because they point to maps with a
7463 // different prototype.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007464 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007465 MaybeObject* maybe_new_map = map()->Copy(DescriptorArray::MAY_BE_SHARED);
7466 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
7467
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007468 Heap* heap = new_map->GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007469 set_map(new_map);
7470 new_map->set_constructor(value);
7471 new_map->set_non_instance_prototype(true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007472 construct_prototype =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007473 heap->isolate()->context()->global_context()->
7474 initial_object_prototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007475 } else {
7476 map()->set_non_instance_prototype(false);
7477 }
7478
7479 return SetInstancePrototype(construct_prototype);
7480}
7481
7482
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007483Object* JSFunction::RemovePrototype() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007484 Context* global_context = context()->global_context();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007485 Map* no_prototype_map = shared()->is_classic_mode()
7486 ? global_context->function_without_prototype_map()
7487 : global_context->strict_mode_function_without_prototype_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007488
7489 if (map() == no_prototype_map) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007490 // Be idempotent.
7491 return this;
7492 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007493
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007494 ASSERT(map() == (shared()->is_classic_mode()
7495 ? global_context->function_map()
7496 : global_context->strict_mode_function_map()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007497
7498 set_map(no_prototype_map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007499 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007500 return this;
7501}
7502
7503
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007504Object* JSFunction::SetInstanceClassName(String* name) {
7505 shared()->set_instance_class_name(name);
7506 return this;
7507}
7508
7509
whesse@chromium.org023421e2010-12-21 12:19:12 +00007510void JSFunction::PrintName(FILE* out) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007511 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
whesse@chromium.org023421e2010-12-21 12:19:12 +00007512 PrintF(out, "%s", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007513}
7514
7515
ager@chromium.org236ad962008-09-25 09:45:57 +00007516Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
7517 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
7518}
7519
7520
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007521MaybeObject* Oddball::Initialize(const char* to_string,
7522 Object* to_number,
7523 byte kind) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007524 String* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007525 { MaybeObject* maybe_symbol =
7526 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007527 if (!maybe_symbol->To(&symbol)) return maybe_symbol;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007528 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007529 set_to_string(symbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007530 set_to_number(to_number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007531 set_kind(kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532 return this;
7533}
7534
7535
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00007536String* SharedFunctionInfo::DebugName() {
7537 Object* n = name();
7538 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
7539 return String::cast(n);
7540}
7541
7542
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007543bool SharedFunctionInfo::HasSourceCode() {
7544 return !script()->IsUndefined() &&
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007545 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007546}
7547
7548
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00007549Handle<Object> SharedFunctionInfo::GetSourceCode() {
7550 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
7551 Handle<String> source(String::cast(Script::cast(script())->source()));
7552 return SubString(source, start_position(), end_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007553}
7554
7555
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007556int SharedFunctionInfo::SourceSize() {
7557 return end_position() - start_position();
7558}
7559
7560
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007561int SharedFunctionInfo::CalculateInstanceSize() {
7562 int instance_size =
7563 JSObject::kHeaderSize +
7564 expected_nof_properties() * kPointerSize;
7565 if (instance_size > JSObject::kMaxInstanceSize) {
7566 instance_size = JSObject::kMaxInstanceSize;
7567 }
7568 return instance_size;
7569}
7570
7571
7572int SharedFunctionInfo::CalculateInObjectProperties() {
7573 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
7574}
7575
7576
ager@chromium.org5c838252010-02-19 08:53:10 +00007577bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
7578 // Check the basic conditions for generating inline constructor code.
7579 if (!FLAG_inline_new
7580 || !has_only_simple_this_property_assignments()
7581 || this_property_assignments_count() == 0) {
7582 return false;
7583 }
7584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007585 Heap* heap = GetHeap();
7586
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00007587 // Traverse the proposed prototype chain looking for properties of the
7588 // same names as are set by the inline constructor.
ager@chromium.org5c838252010-02-19 08:53:10 +00007589 for (Object* obj = prototype;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007590 obj != heap->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007591 obj = obj->GetPrototype()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00007592 JSReceiver* receiver = JSReceiver::cast(obj);
ager@chromium.org5c838252010-02-19 08:53:10 +00007593 for (int i = 0; i < this_property_assignments_count(); i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007594 LookupResult result(heap->isolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00007595 String* name = GetThisPropertyAssignmentName(i);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00007596 receiver->LocalLookup(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007597 if (result.IsFound()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00007598 switch (result.type()) {
7599 case NORMAL:
7600 case FIELD:
7601 case CONSTANT_FUNCTION:
7602 break;
7603 case INTERCEPTOR:
7604 case CALLBACKS:
7605 case HANDLER:
7606 return false;
7607 case TRANSITION:
7608 case NONEXISTENT:
7609 UNREACHABLE();
7610 break;
7611 }
7612 }
ager@chromium.org5c838252010-02-19 08:53:10 +00007613 }
7614 }
7615
7616 return true;
7617}
7618
7619
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00007620void SharedFunctionInfo::ForbidInlineConstructor() {
7621 set_compiler_hints(BooleanBit::set(compiler_hints(),
7622 kHasOnlySimpleThisPropertyAssignments,
7623 false));
7624}
7625
7626
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007627void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007628 bool only_simple_this_property_assignments,
7629 FixedArray* assignments) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007630 set_compiler_hints(BooleanBit::set(compiler_hints(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007631 kHasOnlySimpleThisPropertyAssignments,
7632 only_simple_this_property_assignments));
7633 set_this_property_assignments(assignments);
7634 set_this_property_assignments_count(assignments->length() / 3);
7635}
7636
7637
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007638void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007639 Heap* heap = GetHeap();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007640 set_compiler_hints(BooleanBit::set(compiler_hints(),
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007641 kHasOnlySimpleThisPropertyAssignments,
7642 false));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007643 set_this_property_assignments(heap->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007644 set_this_property_assignments_count(0);
7645}
7646
7647
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007648String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
7649 Object* obj = this_property_assignments();
7650 ASSERT(obj->IsFixedArray());
7651 ASSERT(index < this_property_assignments_count());
7652 obj = FixedArray::cast(obj)->get(index * 3);
7653 ASSERT(obj->IsString());
7654 return String::cast(obj);
7655}
7656
7657
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007658bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
7659 Object* obj = this_property_assignments();
7660 ASSERT(obj->IsFixedArray());
7661 ASSERT(index < this_property_assignments_count());
7662 obj = FixedArray::cast(obj)->get(index * 3 + 1);
7663 return Smi::cast(obj)->value() != -1;
7664}
7665
7666
7667int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
7668 ASSERT(IsThisPropertyAssignmentArgument(index));
7669 Object* obj =
7670 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
7671 return Smi::cast(obj)->value();
7672}
7673
7674
7675Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
7676 ASSERT(!IsThisPropertyAssignmentArgument(index));
7677 Object* obj =
7678 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
7679 return obj;
7680}
7681
7682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007683// Support function for printing the source code to a StringStream
7684// without any allocation in the heap.
7685void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
7686 int max_length) {
7687 // For some native functions there is no source.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007688 if (!HasSourceCode()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007689 accumulator->Add("<No Source>");
7690 return;
7691 }
7692
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007693 // Get the source for the script which this function came from.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007694 // Don't use String::cast because we don't want more assertion errors while
7695 // we are already creating a stack dump.
7696 String* script_source =
7697 reinterpret_cast<String*>(Script::cast(script())->source());
7698
7699 if (!script_source->LooksValid()) {
7700 accumulator->Add("<Invalid Source>");
7701 return;
7702 }
7703
7704 if (!is_toplevel()) {
7705 accumulator->Add("function ");
7706 Object* name = this->name();
7707 if (name->IsString() && String::cast(name)->length() > 0) {
7708 accumulator->PrintName(name);
7709 }
7710 }
7711
7712 int len = end_position() - start_position();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007713 if (len <= max_length || max_length < 0) {
7714 accumulator->Put(script_source, start_position(), end_position());
7715 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007716 accumulator->Put(script_source,
7717 start_position(),
7718 start_position() + max_length);
7719 accumulator->Add("...\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007720 }
7721}
7722
7723
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007724static bool IsCodeEquivalent(Code* code, Code* recompiled) {
7725 if (code->instruction_size() != recompiled->instruction_size()) return false;
7726 ByteArray* code_relocation = code->relocation_info();
7727 ByteArray* recompiled_relocation = recompiled->relocation_info();
7728 int length = code_relocation->length();
7729 if (length != recompiled_relocation->length()) return false;
7730 int compare = memcmp(code_relocation->GetDataStartAddress(),
7731 recompiled_relocation->GetDataStartAddress(),
7732 length);
7733 return compare == 0;
7734}
7735
7736
7737void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
7738 ASSERT(!has_deoptimization_support());
7739 AssertNoAllocation no_allocation;
7740 Code* code = this->code();
7741 if (IsCodeEquivalent(code, recompiled)) {
7742 // Copy the deoptimization data from the recompiled code.
7743 code->set_deoptimization_data(recompiled->deoptimization_data());
7744 code->set_has_deoptimization_support(true);
7745 } else {
7746 // TODO(3025757): In case the recompiled isn't equivalent to the
7747 // old code, we have to replace it. We should try to avoid this
7748 // altogether because it flushes valuable type feedback by
7749 // effectively resetting all IC state.
7750 set_code(recompiled);
7751 }
7752 ASSERT(has_deoptimization_support());
7753}
7754
7755
yangguo@chromium.org56454712012-02-16 15:33:53 +00007756void SharedFunctionInfo::DisableOptimization() {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00007757 // Disable optimization for the shared function info and mark the
7758 // code as non-optimizable. The marker on the shared function info
7759 // is there because we flush non-optimized code thereby loosing the
7760 // non-optimizable information for the code. When the code is
7761 // regenerated and set on the shared function info it is marked as
7762 // non-optimizable if optimization is disabled for the shared
7763 // function info.
7764 set_optimization_disabled(true);
7765 // Code should be the lazy compilation stub or else unoptimized. If the
7766 // latter, disable optimization for the code too.
7767 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
7768 if (code()->kind() == Code::FUNCTION) {
7769 code()->set_optimizable(false);
7770 }
7771 if (FLAG_trace_opt) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007772 PrintF("[disabled optimization for %s]\n", *DebugName()->ToCString());
ager@chromium.orgea91cc52011-05-23 06:06:11 +00007773 }
7774}
7775
7776
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007777bool SharedFunctionInfo::VerifyBailoutId(int id) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007778 ASSERT(id != AstNode::kNoNumber);
7779 Code* unoptimized = code();
7780 DeoptimizationOutputData* data =
7781 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
7782 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
7783 USE(ignore);
7784 return true; // Return true if there was no ASSERT.
7785}
7786
7787
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007788void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
7789 ASSERT(!IsInobjectSlackTrackingInProgress());
7790
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00007791 if (!FLAG_clever_optimizations) return;
7792
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007793 // Only initiate the tracking the first time.
7794 if (live_objects_may_exist()) return;
7795 set_live_objects_may_exist(true);
7796
7797 // No tracking during the snapshot construction phase.
7798 if (Serializer::enabled()) return;
7799
7800 if (map->unused_property_fields() == 0) return;
7801
7802 // Nonzero counter is a leftover from the previous attempt interrupted
7803 // by GC, keep it.
7804 if (construction_count() == 0) {
7805 set_construction_count(kGenerousAllocationCount);
7806 }
7807 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007808 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007809 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007810 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007811 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007812}
7813
7814
7815// Called from GC, hence reinterpret_cast and unchecked accessors.
7816void SharedFunctionInfo::DetachInitialMap() {
7817 Map* map = reinterpret_cast<Map*>(initial_map());
7818
7819 // Make the map remember to restore the link if it survives the GC.
7820 map->set_bit_field2(
7821 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
7822
7823 // Undo state changes made by StartInobjectTracking (except the
7824 // construction_count). This way if the initial map does not survive the GC
7825 // then StartInobjectTracking will be called again the next time the
7826 // constructor is called. The countdown will continue and (possibly after
7827 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007828 Heap* heap = map->GetHeap();
7829 set_initial_map(heap->raw_unchecked_undefined_value());
7830 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007831 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007832 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007833 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007834 // It is safe to clear the flag: it will be set again if the map is live.
7835 set_live_objects_may_exist(false);
7836}
7837
7838
7839// Called from GC, hence reinterpret_cast and unchecked accessors.
7840void SharedFunctionInfo::AttachInitialMap(Map* map) {
7841 map->set_bit_field2(
7842 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
7843
7844 // Resume inobject slack tracking.
7845 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007846 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007847 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007848 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007849 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007850 // The map survived the gc, so there may be objects referencing it.
7851 set_live_objects_may_exist(true);
7852}
7853
7854
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007855void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
7856 code()->ClearInlineCaches();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007857 set_ic_age(new_ic_age);
ulan@chromium.org6b9c2a02012-04-02 14:52:24 +00007858 if (code()->kind() == Code::FUNCTION) {
7859 code()->set_profiler_ticks(0);
7860 if (optimization_disabled() &&
7861 opt_count() >= Compiler::kDefaultMaxOptCount) {
7862 // Re-enable optimizations if they were disabled due to opt_count limit.
7863 set_optimization_disabled(false);
7864 code()->set_optimizable(true);
7865 }
7866 set_opt_count(0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007867 set_deopt_count(0);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007868 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007869}
7870
7871
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007872static void GetMinInobjectSlack(Map* map, void* data) {
7873 int slack = map->unused_property_fields();
7874 if (*reinterpret_cast<int*>(data) > slack) {
7875 *reinterpret_cast<int*>(data) = slack;
7876 }
7877}
7878
7879
7880static void ShrinkInstanceSize(Map* map, void* data) {
7881 int slack = *reinterpret_cast<int*>(data);
7882 map->set_inobject_properties(map->inobject_properties() - slack);
7883 map->set_unused_property_fields(map->unused_property_fields() - slack);
7884 map->set_instance_size(map->instance_size() - slack * kPointerSize);
7885
7886 // Visitor id might depend on the instance size, recalculate it.
7887 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
7888}
7889
7890
7891void SharedFunctionInfo::CompleteInobjectSlackTracking() {
7892 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
7893 Map* map = Map::cast(initial_map());
7894
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007895 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007896 set_initial_map(heap->undefined_value());
7897 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007898 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007899 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007900 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007901
7902 int slack = map->unused_property_fields();
7903 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
7904 if (slack != 0) {
7905 // Resize the initial map and all maps in its transition tree.
7906 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007907
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007908 // Give the correct expected_nof_properties to initial maps created later.
7909 ASSERT(expected_nof_properties() >= slack);
7910 set_expected_nof_properties(expected_nof_properties() - slack);
7911 }
7912}
7913
7914
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00007915int SharedFunctionInfo::SearchOptimizedCodeMap(Context* global_context) {
7916 ASSERT(global_context->IsGlobalContext());
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00007917 if (!FLAG_cache_optimized_code) return -1;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00007918 Object* value = optimized_code_map();
7919 if (!value->IsSmi()) {
7920 FixedArray* optimized_code_map = FixedArray::cast(value);
7921 int length = optimized_code_map->length();
7922 for (int i = 0; i < length; i += 3) {
7923 if (optimized_code_map->get(i) == global_context) {
7924 return i + 1;
7925 }
7926 }
7927 }
7928 return -1;
7929}
7930
7931
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00007932void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
7933 v->VisitSharedFunctionInfo(this);
7934 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
7935}
7936
7937
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007938#define DECLARE_TAG(ignore1, name, ignore2) name,
7939const char* const VisitorSynchronization::kTags[
7940 VisitorSynchronization::kNumberOfSyncTags] = {
7941 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7942};
7943#undef DECLARE_TAG
7944
7945
7946#define DECLARE_TAG(ignore1, ignore2, name) name,
7947const char* const VisitorSynchronization::kTagNames[
7948 VisitorSynchronization::kNumberOfSyncTags] = {
7949 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7950};
7951#undef DECLARE_TAG
7952
7953
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ager@chromium.org236ad962008-09-25 09:45:57 +00007955 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007956 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
7957 Object* old_target = target;
7958 VisitPointer(&target);
7959 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007960}
7961
7962
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00007963void ObjectVisitor::VisitCodeEntry(Address entry_address) {
7964 Object* code = Code::GetObjectFromEntryAddress(entry_address);
7965 Object* old_code = code;
7966 VisitPointer(&code);
7967 if (code != old_code) {
7968 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
7969 }
7970}
7971
7972
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007973void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
7974 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
7975 Object* cell = rinfo->target_cell();
7976 Object* old_cell = cell;
7977 VisitPointer(&cell);
7978 if (cell != old_cell) {
7979 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
7980 }
7981}
7982
7983
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007984void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00007985 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
7986 rinfo->IsPatchedReturnSequence()) ||
7987 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
7988 rinfo->IsPatchedDebugBreakSlotSequence()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007989 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
7990 Object* old_target = target;
7991 VisitPointer(&target);
7992 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007993}
7994
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00007995void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
7996 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
7997 VisitPointer(rinfo->target_object_address());
7998}
7999
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00008000void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
8001 Address* p = rinfo->target_reference_address();
8002 VisitExternalReferences(p, p + 1);
8003}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008004
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008005void Code::InvalidateRelocation() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008006 set_relocation_info(GetHeap()->empty_byte_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008007}
8008
8009
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008010void Code::Relocate(intptr_t delta) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008011 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
8012 it.rinfo()->apply(delta);
8013 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008014 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008015}
8016
8017
8018void Code::CopyFrom(const CodeDesc& desc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008019 ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
8020
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008021 // copy code
8022 memmove(instruction_start(), desc.buffer, desc.instr_size);
8023
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008024 // copy reloc info
8025 memmove(relocation_start(),
8026 desc.buffer + desc.buffer_size - desc.reloc_size,
8027 desc.reloc_size);
8028
8029 // unbox handles and relocate
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00008030 intptr_t delta = instruction_start() - desc.buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008031 int mode_mask = RelocInfo::kCodeTargetMask |
ager@chromium.org236ad962008-09-25 09:45:57 +00008032 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008033 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008034 RelocInfo::kApplyMask;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008035 Assembler* origin = desc.origin; // Needed to find target_object on X64.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00008037 RelocInfo::Mode mode = it.rinfo()->rmode();
8038 if (mode == RelocInfo::EMBEDDED_OBJECT) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008039 Handle<Object> p = it.rinfo()->target_object_handle(origin);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008040 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008041 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008042 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008043 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
ager@chromium.org236ad962008-09-25 09:45:57 +00008044 } else if (RelocInfo::IsCodeTarget(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008045 // rewrite code handles in inline cache targets to direct
8046 // pointers to the first instruction in the code object
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008047 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008048 Code* code = Code::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008049 it.rinfo()->set_target_address(code->instruction_start(),
8050 SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008051 } else {
8052 it.rinfo()->apply(delta);
8053 }
8054 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008055 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008056}
8057
8058
8059// Locate the source position which is closest to the address in the code. This
8060// is using the source position information embedded in the relocation info.
8061// The position returned is relative to the beginning of the script where the
8062// source for this function is found.
8063int Code::SourcePosition(Address pc) {
8064 int distance = kMaxInt;
ager@chromium.org236ad962008-09-25 09:45:57 +00008065 int position = RelocInfo::kNoPosition; // Initially no position found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008066 // Run through all the relocation info to find the best matching source
8067 // position. All the code needs to be considered as the sequence of the
8068 // instructions in the code does not necessarily follow the same order as the
8069 // source.
8070 RelocIterator it(this, RelocInfo::kPositionMask);
8071 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00008072 // Only look at positions after the current pc.
8073 if (it.rinfo()->pc() < pc) {
8074 // Get position and distance.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008075
8076 int dist = static_cast<int>(pc - it.rinfo()->pc());
8077 int pos = static_cast<int>(it.rinfo()->data());
ager@chromium.org236ad962008-09-25 09:45:57 +00008078 // If this position is closer than the current candidate or if it has the
8079 // same distance as the current candidate and the position is higher then
8080 // this position is the new candidate.
8081 if ((dist < distance) ||
8082 (dist == distance && pos > position)) {
8083 position = pos;
8084 distance = dist;
8085 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008086 }
8087 it.next();
8088 }
8089 return position;
8090}
8091
8092
8093// Same as Code::SourcePosition above except it only looks for statement
8094// positions.
8095int Code::SourceStatementPosition(Address pc) {
8096 // First find the position as close as possible using all position
8097 // information.
8098 int position = SourcePosition(pc);
8099 // Now find the closest statement position before the position.
8100 int statement_position = 0;
8101 RelocIterator it(this, RelocInfo::kPositionMask);
8102 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00008103 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008104 int p = static_cast<int>(it.rinfo()->data());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008105 if (statement_position < p && p <= position) {
8106 statement_position = p;
8107 }
8108 }
8109 it.next();
8110 }
8111 return statement_position;
8112}
8113
8114
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008115SafepointEntry Code::GetSafepointEntry(Address pc) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008116 SafepointTable table(this);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008117 return table.FindEntry(pc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008118}
8119
8120
8121void Code::SetNoStackCheckTable() {
8122 // Indicate the absence of a stack-check table by a table start after the
8123 // end of the instructions. Table start must be aligned, so round up.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008124 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008125}
8126
8127
8128Map* Code::FindFirstMap() {
8129 ASSERT(is_inline_cache_stub());
8130 AssertNoAllocation no_allocation;
8131 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
8132 for (RelocIterator it(this, mask); !it.done(); it.next()) {
8133 RelocInfo* info = it.rinfo();
8134 Object* object = info->target_object();
8135 if (object->IsMap()) return Map::cast(object);
8136 }
8137 return NULL;
8138}
8139
8140
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00008141void Code::ClearInlineCaches() {
8142 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
8143 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
8144 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
8145 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
8146 for (RelocIterator it(this, mask); !it.done(); it.next()) {
8147 RelocInfo* info = it.rinfo();
8148 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
8149 if (target->is_inline_cache_stub()) {
8150 IC::Clear(info->pc());
8151 }
8152 }
8153}
8154
8155
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00008156void Code::ClearTypeFeedbackCells(Heap* heap) {
8157 Object* raw_info = type_feedback_info();
8158 if (raw_info->IsTypeFeedbackInfo()) {
8159 TypeFeedbackCells* type_feedback_cells =
8160 TypeFeedbackInfo::cast(raw_info)->type_feedback_cells();
8161 for (int i = 0; i < type_feedback_cells->CellCount(); i++) {
8162 ASSERT(type_feedback_cells->AstId(i)->IsSmi());
8163 JSGlobalPropertyCell* cell = type_feedback_cells->Cell(i);
8164 cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap));
8165 }
8166 }
8167}
8168
8169
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008170bool Code::allowed_in_shared_map_code_cache() {
mstarzinger@chromium.org06e015b2012-06-14 15:34:20 +00008171 return is_keyed_load_stub() || is_keyed_store_stub() ||
8172 (is_compare_ic_stub() && compare_state() == CompareIC::KNOWN_OBJECTS);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008173}
8174
8175
ricow@chromium.org4f693d62011-07-04 14:01:31 +00008176#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008177
whesse@chromium.org023421e2010-12-21 12:19:12 +00008178void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008179 disasm::NameConverter converter;
8180 int deopt_count = DeoptCount();
whesse@chromium.org023421e2010-12-21 12:19:12 +00008181 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008182 if (0 == deopt_count) return;
8183
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008184 PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc",
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008185 FLAG_print_code_verbose ? "commands" : "");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008186 for (int i = 0; i < deopt_count; i++) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008187 PrintF(out, "%6d %6d %6d %6d",
8188 i,
8189 AstId(i)->value(),
8190 ArgumentsStackHeight(i)->value(),
8191 Pc(i)->value());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008192
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008193 if (!FLAG_print_code_verbose) {
8194 PrintF(out, "\n");
8195 continue;
8196 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008197 // Print details of the frame translation.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008198 int translation_index = TranslationIndex(i)->value();
8199 TranslationIterator iterator(TranslationByteArray(), translation_index);
8200 Translation::Opcode opcode =
8201 static_cast<Translation::Opcode>(iterator.Next());
8202 ASSERT(Translation::BEGIN == opcode);
8203 int frame_count = iterator.Next();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008204 int jsframe_count = iterator.Next();
8205 PrintF(out, " %s {frame count=%d, js frame count=%d}\n",
8206 Translation::StringFor(opcode),
8207 frame_count,
8208 jsframe_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008209
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008210 while (iterator.HasNext() &&
8211 Translation::BEGIN !=
8212 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
8213 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
8214
8215 switch (opcode) {
8216 case Translation::BEGIN:
8217 UNREACHABLE();
8218 break;
8219
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008220 case Translation::JS_FRAME: {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008221 int ast_id = iterator.Next();
8222 int function_id = iterator.Next();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008223 unsigned height = iterator.Next();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008224 PrintF(out, "{ast_id=%d, function=", ast_id);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008225 if (function_id != Translation::kSelfLiteralId) {
8226 Object* function = LiteralArray()->get(function_id);
8227 JSFunction::cast(function)->PrintName(out);
8228 } else {
8229 PrintF(out, "<self>");
8230 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008231 PrintF(out, ", height=%u}", height);
8232 break;
8233 }
8234
ulan@chromium.org967e2702012-02-28 09:49:15 +00008235 case Translation::ARGUMENTS_ADAPTOR_FRAME:
8236 case Translation::CONSTRUCT_STUB_FRAME: {
8237 int function_id = iterator.Next();
8238 JSFunction* function =
8239 JSFunction::cast(LiteralArray()->get(function_id));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008240 unsigned height = iterator.Next();
ulan@chromium.org967e2702012-02-28 09:49:15 +00008241 PrintF(out, "{function=");
8242 function->PrintName(out);
8243 PrintF(out, ", height=%u}", height);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008244 break;
8245 }
8246
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008247 case Translation::DUPLICATE:
8248 break;
8249
8250 case Translation::REGISTER: {
8251 int reg_code = iterator.Next();
8252 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8253 break;
8254 }
8255
8256 case Translation::INT32_REGISTER: {
8257 int reg_code = iterator.Next();
8258 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8259 break;
8260 }
8261
8262 case Translation::DOUBLE_REGISTER: {
8263 int reg_code = iterator.Next();
8264 PrintF(out, "{input=%s}",
8265 DoubleRegister::AllocationIndexToString(reg_code));
8266 break;
8267 }
8268
8269 case Translation::STACK_SLOT: {
8270 int input_slot_index = iterator.Next();
8271 PrintF(out, "{input=%d}", input_slot_index);
8272 break;
8273 }
8274
8275 case Translation::INT32_STACK_SLOT: {
8276 int input_slot_index = iterator.Next();
8277 PrintF(out, "{input=%d}", input_slot_index);
8278 break;
8279 }
8280
8281 case Translation::DOUBLE_STACK_SLOT: {
8282 int input_slot_index = iterator.Next();
8283 PrintF(out, "{input=%d}", input_slot_index);
8284 break;
8285 }
8286
8287 case Translation::LITERAL: {
8288 unsigned literal_index = iterator.Next();
8289 PrintF(out, "{literal_id=%u}", literal_index);
8290 break;
8291 }
8292
8293 case Translation::ARGUMENTS_OBJECT:
8294 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008295 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008296 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008297 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008298 }
8299}
8300
8301
whesse@chromium.org023421e2010-12-21 12:19:12 +00008302void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
8303 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008304 this->DeoptPoints());
8305 if (this->DeoptPoints() == 0) return;
8306
8307 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
8308 for (int i = 0; i < this->DeoptPoints(); i++) {
8309 int pc_and_state = this->PcAndState(i)->value();
8310 PrintF("%6d %8d %s\n",
8311 this->AstId(i)->value(),
8312 FullCodeGenerator::PcField::decode(pc_and_state),
8313 FullCodeGenerator::State2String(
8314 FullCodeGenerator::StateField::decode(pc_and_state)));
8315 }
8316}
8317
whesse@chromium.org7b260152011-06-20 15:33:18 +00008318
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008319// Identify kind of code.
8320const char* Code::Kind2String(Kind kind) {
8321 switch (kind) {
8322 case FUNCTION: return "FUNCTION";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008323 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008324 case STUB: return "STUB";
8325 case BUILTIN: return "BUILTIN";
8326 case LOAD_IC: return "LOAD_IC";
8327 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
8328 case STORE_IC: return "STORE_IC";
8329 case KEYED_STORE_IC: return "KEYED_STORE_IC";
8330 case CALL_IC: return "CALL_IC";
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008331 case KEYED_CALL_IC: return "KEYED_CALL_IC";
danno@chromium.org40cb8782011-05-25 07:58:50 +00008332 case UNARY_OP_IC: return "UNARY_OP_IC";
8333 case BINARY_OP_IC: return "BINARY_OP_IC";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008334 case COMPARE_IC: return "COMPARE_IC";
ricow@chromium.org9fa09672011-07-25 11:05:35 +00008335 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008336 }
8337 UNREACHABLE();
8338 return NULL;
8339}
mads.s.ager31e71382008-08-13 09:32:07 +00008340
8341
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008342const char* Code::ICState2String(InlineCacheState state) {
8343 switch (state) {
8344 case UNINITIALIZED: return "UNINITIALIZED";
8345 case PREMONOMORPHIC: return "PREMONOMORPHIC";
8346 case MONOMORPHIC: return "MONOMORPHIC";
8347 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
8348 case MEGAMORPHIC: return "MEGAMORPHIC";
8349 case DEBUG_BREAK: return "DEBUG_BREAK";
8350 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
8351 }
8352 UNREACHABLE();
8353 return NULL;
8354}
8355
8356
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008357const char* Code::StubType2String(StubType type) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008358 switch (type) {
8359 case NORMAL: return "NORMAL";
8360 case FIELD: return "FIELD";
8361 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
8362 case CALLBACKS: return "CALLBACKS";
8363 case INTERCEPTOR: return "INTERCEPTOR";
8364 case MAP_TRANSITION: return "MAP_TRANSITION";
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008365 case NONEXISTENT: return "NONEXISTENT";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008366 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00008367 UNREACHABLE(); // keep the compiler happy
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008368 return NULL;
8369}
8370
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008371
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008372void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
8373 const char* name = NULL;
8374 switch (kind) {
8375 case CALL_IC:
8376 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
8377 name = "STRING_INDEX_OUT_OF_BOUNDS";
8378 }
8379 break;
8380 case STORE_IC:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008381 case KEYED_STORE_IC:
8382 if (extra == kStrictMode) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008383 name = "STRICT";
8384 }
8385 break;
8386 default:
8387 break;
8388 }
8389 if (name != NULL) {
8390 PrintF(out, "extra_ic_state = %s\n", name);
8391 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008392 PrintF(out, "extra_ic_state = %d\n", extra);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008393 }
8394}
8395
8396
whesse@chromium.org023421e2010-12-21 12:19:12 +00008397void Code::Disassemble(const char* name, FILE* out) {
8398 PrintF(out, "kind = %s\n", Kind2String(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008399 if (is_inline_cache_stub()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008400 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008401 PrintExtraICState(out, kind(), extra_ic_state());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008402 if (ic_state() == MONOMORPHIC) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008403 PrintF(out, "type = %s\n", StubType2String(type()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008404 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00008405 if (is_call_stub() || is_keyed_call_stub()) {
8406 PrintF(out, "argc = %d\n", arguments_count());
8407 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +00008408 if (is_compare_ic_stub()) {
8409 CompareIC::State state = CompareIC::ComputeState(this);
8410 PrintF(out, "compare_state = %s\n", CompareIC::GetStateName(state));
8411 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00008412 if (is_compare_ic_stub() && major_key() == CodeStub::CompareIC) {
8413 Token::Value op = CompareIC::ComputeOperation(this);
8414 PrintF(out, "compare_operation = %s\n", Token::Name(op));
8415 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008416 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008417 if ((name != NULL) && (name[0] != '\0')) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008418 PrintF(out, "name = %s\n", name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008419 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008420 if (kind() == OPTIMIZED_FUNCTION) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008421 PrintF(out, "stack_slots = %d\n", stack_slots());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008422 }
mads.s.ager31e71382008-08-13 09:32:07 +00008423
whesse@chromium.org023421e2010-12-21 12:19:12 +00008424 PrintF(out, "Instructions (size = %d)\n", instruction_size());
8425 Disassembler::Decode(out, this);
8426 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00008427
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008428 if (kind() == FUNCTION) {
8429 DeoptimizationOutputData* data =
8430 DeoptimizationOutputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00008431 data->DeoptimizationOutputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008432 } else if (kind() == OPTIMIZED_FUNCTION) {
8433 DeoptimizationInputData* data =
8434 DeoptimizationInputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00008435 data->DeoptimizationInputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008436 }
8437 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008438
8439 if (kind() == OPTIMIZED_FUNCTION) {
8440 SafepointTable table(this);
whesse@chromium.org023421e2010-12-21 12:19:12 +00008441 PrintF(out, "Safepoints (size = %u)\n", table.size());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008442 for (unsigned i = 0; i < table.length(); i++) {
8443 unsigned pc_offset = table.GetPcOffset(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00008444 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008445 table.PrintEntry(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00008446 PrintF(out, " (sp -> fp)");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008447 SafepointEntry entry = table.GetEntry(i);
8448 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
8449 PrintF(out, " %6d", entry.deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008450 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008451 PrintF(out, " <none>");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008452 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008453 if (entry.argument_count() > 0) {
8454 PrintF(out, " argc: %d", entry.argument_count());
8455 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008456 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008457 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008458 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008459 } else if (kind() == FUNCTION) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008460 unsigned offset = stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008461 // If there is no stack check table, the "table start" will at or after
8462 // (due to alignment) the end of the instruction stream.
8463 if (static_cast<int>(offset) < instruction_size()) {
8464 unsigned* address =
8465 reinterpret_cast<unsigned*>(instruction_start() + offset);
8466 unsigned length = address[0];
whesse@chromium.org023421e2010-12-21 12:19:12 +00008467 PrintF(out, "Stack checks (size = %u)\n", length);
8468 PrintF(out, "ast_id pc_offset\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008469 for (unsigned i = 0; i < length; ++i) {
8470 unsigned index = (2 * i) + 1;
whesse@chromium.org023421e2010-12-21 12:19:12 +00008471 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008472 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008473 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008474 }
8475 }
8476
mads.s.ager31e71382008-08-13 09:32:07 +00008477 PrintF("RelocInfo (size = %d)\n", relocation_size());
whesse@chromium.org023421e2010-12-21 12:19:12 +00008478 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
8479 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00008480}
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008481#endif // ENABLE_DISASSEMBLER
8482
8483
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008484MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8485 int capacity,
8486 int length,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008487 SetFastElementsCapacitySmiMode smi_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008488 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +00008489 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008490 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008491
whesse@chromium.org7b260152011-06-20 15:33:18 +00008492 // Allocate a new fast elements backing store.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008493 FixedArray* new_elements;
8494 { MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
8495 if (!maybe->To(&new_elements)) return maybe;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008496 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008497
jkummerow@chromium.orgf3eae902012-05-24 16:42:53 +00008498 ElementsKind elements_kind = GetElementsKind();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008499 ElementsKind new_elements_kind;
8500 // The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it,
8501 // or if it's allowed and the old elements array contained only SMIs.
8502 bool has_fast_smi_elements =
8503 (smi_mode == kForceSmiElements) ||
8504 ((smi_mode == kAllowSmiElements) && HasFastSmiElements());
8505 if (has_fast_smi_elements) {
8506 if (IsHoleyElementsKind(elements_kind)) {
8507 new_elements_kind = FAST_HOLEY_SMI_ELEMENTS;
8508 } else {
8509 new_elements_kind = FAST_SMI_ELEMENTS;
8510 }
8511 } else {
8512 if (IsHoleyElementsKind(elements_kind)) {
8513 new_elements_kind = FAST_HOLEY_ELEMENTS;
8514 } else {
8515 new_elements_kind = FAST_ELEMENTS;
8516 }
8517 }
8518 FixedArrayBase* old_elements = elements();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00008519 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00008520 { MaybeObject* maybe_obj =
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008521 accessor->CopyElements(this, new_elements, new_elements_kind);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00008522 if (maybe_obj->IsFailure()) return maybe_obj;
8523 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00008524 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008525 Map* new_map = map();
8526 if (new_elements_kind != elements_kind) {
8527 MaybeObject* maybe =
8528 GetElementsTransitionMap(GetIsolate(), new_elements_kind);
8529 if (!maybe->To(&new_map)) return maybe;
8530 }
8531 ValidateElements();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00008532 set_map_and_elements(new_map, new_elements);
8533 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00008534 FixedArray* parameter_map = FixedArray::cast(old_elements);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00008535 parameter_map->set(1, new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008536 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008537
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008538 if (FLAG_trace_elements_transitions) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00008539 PrintElementsTransition(stdout, elements_kind, old_elements,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00008540 GetElementsKind(), new_elements);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008541 }
8542
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008543 if (IsJSArray()) {
8544 JSArray::cast(this)->set_length(Smi::FromInt(length));
8545 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008546 return new_elements;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008547}
8548
8549
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008550MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
8551 int capacity,
8552 int length) {
8553 Heap* heap = GetHeap();
8554 // We should never end in here with a pixel or external array.
8555 ASSERT(!HasExternalArrayElements());
8556
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00008557 FixedArrayBase* elems;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008558 { MaybeObject* maybe_obj =
8559 heap->AllocateUninitializedFixedDoubleArray(capacity);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008560 if (!maybe_obj->To(&elems)) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008561 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008562
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008563 ElementsKind elements_kind = GetElementsKind();
8564 ElementsKind new_elements_kind = elements_kind;
8565 if (IsHoleyElementsKind(elements_kind)) {
8566 new_elements_kind = FAST_HOLEY_DOUBLE_ELEMENTS;
8567 } else {
8568 new_elements_kind = FAST_DOUBLE_ELEMENTS;
8569 }
8570
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008571 Map* new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008572 { MaybeObject* maybe_obj =
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008573 GetElementsTransitionMap(heap->isolate(), new_elements_kind);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008574 if (!maybe_obj->To(&new_map)) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008575 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008576
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008577 FixedArrayBase* old_elements = elements();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00008578 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00008579 { MaybeObject* maybe_obj =
8580 accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS);
8581 if (maybe_obj->IsFailure()) return maybe_obj;
8582 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00008583 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008584 ValidateElements();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00008585 set_map_and_elements(new_map, elems);
8586 } else {
8587 FixedArray* parameter_map = FixedArray::cast(old_elements);
8588 parameter_map->set(1, elems);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008589 }
8590
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008591 if (FLAG_trace_elements_transitions) {
8592 PrintElementsTransition(stdout, elements_kind, old_elements,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008593 GetElementsKind(), elems);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008594 }
8595
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008596 if (IsJSArray()) {
8597 JSArray::cast(this)->set_length(Smi::FromInt(length));
8598 }
8599
8600 return this;
8601}
8602
8603
lrn@chromium.org303ada72010-10-27 09:33:13 +00008604MaybeObject* JSArray::Initialize(int capacity) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008605 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008606 ASSERT(capacity >= 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008607 set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008608 FixedArray* new_elements;
8609 if (capacity == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008610 new_elements = heap->empty_fixed_array();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008611 } else {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008612 MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
8613 if (!maybe_obj->To(&new_elements)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008614 }
8615 set_elements(new_elements);
8616 return this;
8617}
8618
8619
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008620void JSArray::Expand(int required_size) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008621 GetIsolate()->factory()->SetElementsCapacityAndLength(
8622 Handle<JSArray>(this), required_size, required_size);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008623}
8624
8625
ricow@chromium.org7ad65222011-12-19 12:13:11 +00008626MaybeObject* JSArray::SetElementsLength(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +00008627 // We should never end in here with a pixel or external array.
ager@chromium.org5c838252010-02-19 08:53:10 +00008628 ASSERT(AllowsSetElementsLength());
danno@chromium.orgc612e022011-11-10 11:38:15 +00008629 return GetElementsAccessor()->SetLength(this, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008630}
8631
8632
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008633Map* Map::GetPrototypeTransition(Object* prototype) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008634 FixedArray* cache = GetPrototypeTransitions();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008635 int number_of_transitions = NumberOfProtoTransitions();
8636 const int proto_offset =
8637 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
8638 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
8639 const int step = kProtoTransitionElementsPerEntry;
8640 for (int i = 0; i < number_of_transitions; i++) {
8641 if (cache->get(proto_offset + i * step) == prototype) {
8642 Object* map = cache->get(map_offset + i * step);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008643 return Map::cast(map);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008644 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008645 }
8646 return NULL;
8647}
8648
8649
8650MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008651 ASSERT(map->IsMap());
8652 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008653 // Don't cache prototype transition if this map is shared.
8654 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
8655
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008656 FixedArray* cache = GetPrototypeTransitions();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008657
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008658 const int step = kProtoTransitionElementsPerEntry;
8659 const int header = kProtoTransitionHeaderSize;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008660
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008661 int capacity = (cache->length() - header) / step;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008662
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008663 int transitions = NumberOfProtoTransitions() + 1;
8664
8665 if (transitions > capacity) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008666 if (capacity > kMaxCachedPrototypeTransitions) return this;
8667
8668 FixedArray* new_cache;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008669 // Grow array by factor 2 over and above what we need.
8670 { MaybeObject* maybe_cache =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008671 GetHeap()->AllocateFixedArray(transitions * 2 * step + header);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008672 if (!maybe_cache->To(&new_cache)) return maybe_cache;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008673 }
8674
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008675 for (int i = 0; i < capacity * step; i++) {
8676 new_cache->set(i + header, cache->get(i + header));
8677 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008678 cache = new_cache;
danno@chromium.org81cac2b2012-07-10 11:28:27 +00008679 MaybeObject* set_result = SetPrototypeTransitions(cache);
8680 if (set_result->IsFailure()) return set_result;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008681 }
8682
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008683 int last = transitions - 1;
8684
8685 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
8686 cache->set(header + last * step + kProtoTransitionMapOffset, map);
8687 SetNumberOfProtoTransitions(transitions);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008688
8689 return cache;
8690}
8691
8692
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008693MaybeObject* JSReceiver::SetPrototype(Object* value,
8694 bool skip_hidden_prototypes) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008695#ifdef DEBUG
8696 int size = Size();
8697#endif
8698
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008699 Heap* heap = GetHeap();
ager@chromium.org5c838252010-02-19 08:53:10 +00008700 // Silently ignore the change if value is not a JSObject or null.
8701 // SpiderMonkey behaves this way.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008702 if (!value->IsJSReceiver() && !value->IsNull()) return value;
ager@chromium.org5c838252010-02-19 08:53:10 +00008703
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008704 // From 8.6.2 Object Internal Methods
8705 // ...
8706 // In addition, if [[Extensible]] is false the value of the [[Class]] and
8707 // [[Prototype]] internal properties of the object may not be modified.
8708 // ...
8709 // Implementation specific extensions that modify [[Class]], [[Prototype]]
8710 // or [[Extensible]] must not violate the invariants defined in the preceding
8711 // paragraph.
8712 if (!this->map()->is_extensible()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008713 HandleScope scope(heap->isolate());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008714 Handle<Object> handle(this, heap->isolate());
8715 return heap->isolate()->Throw(
8716 *FACTORY->NewTypeError("non_extensible_proto",
8717 HandleVector<Object>(&handle, 1)));
8718 }
8719
ager@chromium.org5c838252010-02-19 08:53:10 +00008720 // Before we can set the prototype we need to be sure
8721 // prototype cycles are prevented.
8722 // It is sufficient to validate that the receiver is not in the new prototype
8723 // chain.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008724 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008725 if (JSReceiver::cast(pt) == this) {
ager@chromium.org5c838252010-02-19 08:53:10 +00008726 // Cycle detected.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008727 HandleScope scope(heap->isolate());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008728 return heap->isolate()->Throw(
8729 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
ager@chromium.org5c838252010-02-19 08:53:10 +00008730 }
8731 }
8732
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008733 JSReceiver* real_receiver = this;
ager@chromium.org5c838252010-02-19 08:53:10 +00008734
8735 if (skip_hidden_prototypes) {
8736 // Find the first object in the chain whose prototype object is not
8737 // hidden and set the new prototype on that object.
8738 Object* current_proto = real_receiver->GetPrototype();
8739 while (current_proto->IsJSObject() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008740 JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) {
8741 real_receiver = JSReceiver::cast(current_proto);
ager@chromium.org5c838252010-02-19 08:53:10 +00008742 current_proto = current_proto->GetPrototype();
8743 }
8744 }
8745
8746 // Set the new prototype of the object.
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008747 Map* map = real_receiver->map();
8748
8749 // Nothing to do if prototype is already set.
8750 if (map->prototype() == value) return value;
8751
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008752 if (value->IsJSObject()) {
8753 MaybeObject* ok = JSObject::cast(value)->OptimizeAsPrototype();
8754 if (ok->IsFailure()) return ok;
8755 }
8756
8757 Map* new_map = map->GetPrototypeTransition(value);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008758 if (new_map == NULL) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00008759 MaybeObject* maybe_new_map = map->Copy(DescriptorArray::MAY_BE_SHARED);
8760 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008761
verwaest@chromium.org753aee42012-07-17 16:15:42 +00008762 MaybeObject* maybe_new_cache =
8763 map->PutPrototypeTransition(value, new_map);
8764 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008765
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008766 new_map->set_prototype(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008767 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00008768 ASSERT(new_map->prototype() == value);
8769 real_receiver->set_map(new_map);
ager@chromium.org5c838252010-02-19 08:53:10 +00008770
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008771 heap->ClearInstanceofCache();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008772 ASSERT(size == Size());
ager@chromium.org5c838252010-02-19 08:53:10 +00008773 return value;
8774}
8775
8776
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008777MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
8778 uint32_t first_arg,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008779 uint32_t arg_count,
8780 EnsureElementsMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008781 // Elements in |Arguments| are ordered backwards (because they're on the
8782 // stack), but the method that's called here iterates over them in forward
8783 // direction.
8784 return EnsureCanContainElements(
8785 args->arguments() - first_arg - (arg_count - 1),
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008786 arg_count, mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008787}
8788
8789
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008790bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008791 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008792 // Make sure that the top context does not change when doing
8793 // callbacks or interceptor calls.
8794 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008795 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008796 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008797 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008798 Handle<JSObject> holder_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008799 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008800 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008801 if (!interceptor->query()->IsUndefined()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00008802 v8::IndexedPropertyQuery query =
8803 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008804 LOG(isolate,
8805 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00008806 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008807 {
8808 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008809 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008810 result = query(index, info);
8811 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008812 if (!result.IsEmpty()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00008813 ASSERT(result->IsInt32());
8814 return true; // absence of property is signaled by empty handle.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008815 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008816 } else if (!interceptor->getter()->IsUndefined()) {
8817 v8::IndexedPropertyGetter getter =
8818 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008819 LOG(isolate,
8820 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008821 v8::Handle<v8::Value> result;
8822 {
8823 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008824 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825 result = getter(index, info);
8826 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008827 if (!result.IsEmpty()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00008829
8830 if (holder_handle->GetElementsAccessor()->HasElement(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008831 *receiver_handle, *holder_handle, index)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00008832 return true;
8833 }
8834
8835 if (holder_handle->IsStringObjectWithCharacterAt(index)) return true;
8836 Object* pt = holder_handle->GetPrototype();
8837 if (pt->IsJSProxy()) {
8838 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8839 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8840 receiver, index) != ABSENT;
8841 }
8842 if (pt->IsNull()) return false;
8843 return JSObject::cast(pt)->HasElementWithReceiver(*receiver_handle, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008844}
8845
8846
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008847JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008849 if (IsAccessCheckNeeded()) {
8850 Heap* heap = GetHeap();
8851 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8852 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8853 return UNDEFINED_ELEMENT;
8854 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008855 }
8856
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008857 if (IsJSGlobalProxy()) {
8858 Object* proto = GetPrototype();
8859 if (proto->IsNull()) return UNDEFINED_ELEMENT;
8860 ASSERT(proto->IsJSGlobalObject());
8861 return JSObject::cast(proto)->HasLocalElement(index);
8862 }
8863
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008864 // Check for lookup interceptor
8865 if (HasIndexedInterceptor()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008866 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
8867 : UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008868 }
8869
8870 // Handle [] on String objects.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008871 if (this->IsStringObjectWithCharacterAt(index)) {
8872 return STRING_CHARACTER_ELEMENT;
8873 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008874
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008875 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008876 case FAST_SMI_ELEMENTS:
8877 case FAST_ELEMENTS:
8878 case FAST_HOLEY_SMI_ELEMENTS:
8879 case FAST_HOLEY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008880 uint32_t length = IsJSArray() ?
8881 static_cast<uint32_t>
8882 (Smi::cast(JSArray::cast(this)->length())->value()) :
8883 static_cast<uint32_t>(FixedArray::cast(elements())->length());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008884 if ((index < length) &&
8885 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8886 return FAST_ELEMENT;
8887 }
8888 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008889 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008890 case FAST_DOUBLE_ELEMENTS:
8891 case FAST_HOLEY_DOUBLE_ELEMENTS: {
ricow@chromium.org9fa09672011-07-25 11:05:35 +00008892 uint32_t length = IsJSArray() ?
8893 static_cast<uint32_t>
8894 (Smi::cast(JSArray::cast(this)->length())->value()) :
8895 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8896 if ((index < length) &&
8897 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
8898 return FAST_ELEMENT;
8899 }
8900 break;
8901 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008902 case EXTERNAL_PIXEL_ELEMENTS: {
8903 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008904 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
8905 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008906 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008907 case EXTERNAL_BYTE_ELEMENTS:
8908 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8909 case EXTERNAL_SHORT_ELEMENTS:
8910 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8911 case EXTERNAL_INT_ELEMENTS:
8912 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008913 case EXTERNAL_FLOAT_ELEMENTS:
8914 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00008915 ExternalArray* array = ExternalArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008916 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
8917 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00008918 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008919 case DICTIONARY_ELEMENTS: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008920 if (element_dictionary()->FindEntry(index) !=
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008921 SeededNumberDictionary::kNotFound) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008922 return DICTIONARY_ELEMENT;
8923 }
8924 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008925 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008926 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8927 // Aliased parameters and non-aliased elements in a fast backing store
8928 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
8929 // backing store behave as DICTIONARY_ELEMENT.
8930 FixedArray* parameter_map = FixedArray::cast(elements());
8931 uint32_t length = parameter_map->length();
8932 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00008933 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008934 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8935 // If not aliased, check the arguments.
8936 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8937 if (arguments->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008938 SeededNumberDictionary* dictionary =
8939 SeededNumberDictionary::cast(arguments);
8940 if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008941 return DICTIONARY_ELEMENT;
8942 }
8943 } else {
8944 length = arguments->length();
8945 probe = (index < length) ? arguments->get(index) : NULL;
8946 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8947 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008948 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008949 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008950 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008951
8952 return UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008953}
8954
8955
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008956bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008957 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008958 if (IsAccessCheckNeeded()) {
8959 Heap* heap = GetHeap();
8960 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8961 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8962 return false;
8963 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008964 }
8965
8966 // Check for lookup interceptor
8967 if (HasIndexedInterceptor()) {
8968 return HasElementWithInterceptor(receiver, index);
8969 }
8970
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00008971 ElementsAccessor* accessor = GetElementsAccessor();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008972 if (accessor->HasElement(receiver, this, index)) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00008973 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008974 }
8975
8976 // Handle [] on String objects.
8977 if (this->IsStringObjectWithCharacterAt(index)) return true;
8978
8979 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008980 if (pt->IsNull()) return false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008981 if (pt->IsJSProxy()) {
8982 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8983 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8984 receiver, index) != ABSENT;
8985 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008986 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8987}
8988
8989
lrn@chromium.org303ada72010-10-27 09:33:13 +00008990MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008991 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00008992 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008993 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00008994 bool check_prototype,
8995 SetPropertyMode set_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008996 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008997 // Make sure that the top context does not change when doing
8998 // callbacks or interceptor calls.
8999 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009000 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
9002 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009003 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009004 if (!interceptor->setter()->IsUndefined()) {
9005 v8::IndexedPropertySetter setter =
9006 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009007 LOG(isolate,
9008 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
9009 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009010 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011 v8::Handle<v8::Value> result;
9012 {
9013 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009014 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009015 result = setter(index, v8::Utils::ToLocal(value_handle), info);
9016 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009017 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009018 if (!result.IsEmpty()) return *value_handle;
9019 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009020 MaybeObject* raw_result =
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009021 this_handle->SetElementWithoutInterceptor(index,
9022 *value_handle,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009023 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009024 strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009025 check_prototype,
9026 set_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009027 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009028 return raw_result;
9029}
9030
9031
lrn@chromium.org303ada72010-10-27 09:33:13 +00009032MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
9033 Object* structure,
9034 uint32_t index,
9035 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009036 Isolate* isolate = GetIsolate();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009037 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009038
9039 // api style callbacks.
9040 if (structure->IsAccessorInfo()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009041 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009042 Object* fun_obj = data->getter();
9043 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009044 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009045 Handle<JSObject> self(JSObject::cast(receiver));
9046 Handle<JSObject> holder_handle(JSObject::cast(holder));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009047 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009048 Handle<String> key = isolate->factory()->NumberToString(number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009049 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
9050 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009051 v8::AccessorInfo info(args.end());
9052 v8::Handle<v8::Value> result;
9053 {
9054 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009055 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009056 result = call_fun(v8::Utils::ToLocal(key), info);
9057 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009058 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9059 if (result.IsEmpty()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009060 return *v8::Utils::OpenHandle(*result);
9061 }
9062
9063 // __defineGetter__ callback
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009064 if (structure->IsAccessorPair()) {
9065 Object* getter = AccessorPair::cast(structure)->getter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009066 if (getter->IsSpecFunction()) {
9067 // TODO(rossberg): nicer would be to cast to some JSCallable here...
9068 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009069 }
9070 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009071 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009072 }
9073
9074 UNREACHABLE();
9075 return NULL;
9076}
9077
9078
lrn@chromium.org303ada72010-10-27 09:33:13 +00009079MaybeObject* JSObject::SetElementWithCallback(Object* structure,
9080 uint32_t index,
9081 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009082 JSObject* holder,
9083 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009084 Isolate* isolate = GetIsolate();
9085 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009086
9087 // We should never get here to initialize a const with the hole
9088 // value since a const declaration would conflict with the setter.
9089 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009090 Handle<Object> value_handle(value, isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009091
9092 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009093 // data structure used to store the callbacks. Eventually foreign
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009094 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009095 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009096
9097 if (structure->IsAccessorInfo()) {
9098 // api style callbacks
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009099 Handle<JSObject> self(this);
9100 Handle<JSObject> holder_handle(JSObject::cast(holder));
9101 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009102 Object* call_obj = data->setter();
9103 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
9104 if (call_fun == NULL) return value;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009105 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9106 Handle<String> key(isolate->factory()->NumberToString(number));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009107 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
9108 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009109 v8::AccessorInfo info(args.end());
9110 {
9111 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009112 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009113 call_fun(v8::Utils::ToLocal(key),
9114 v8::Utils::ToLocal(value_handle),
9115 info);
9116 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009117 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009118 return *value_handle;
9119 }
9120
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009121 if (structure->IsAccessorPair()) {
9122 Handle<Object> setter(AccessorPair::cast(structure)->setter());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009123 if (setter->IsSpecFunction()) {
9124 // TODO(rossberg): nicer would be to cast to some JSCallable here...
9125 return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009126 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009127 if (strict_mode == kNonStrictMode) {
9128 return value;
9129 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009130 Handle<Object> holder_handle(holder, isolate);
9131 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009132 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009133 return isolate->Throw(
9134 *isolate->factory()->NewTypeError("no_setter_in_callback",
9135 HandleVector(args, 2)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009136 }
9137 }
9138
9139 UNREACHABLE();
9140 return NULL;
9141}
9142
9143
whesse@chromium.org7b260152011-06-20 15:33:18 +00009144bool JSObject::HasFastArgumentsElements() {
9145 Heap* heap = GetHeap();
9146 if (!elements()->IsFixedArray()) return false;
9147 FixedArray* elements = FixedArray::cast(this->elements());
9148 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9149 return false;
9150 }
9151 FixedArray* arguments = FixedArray::cast(elements->get(1));
9152 return !arguments->IsDictionary();
9153}
9154
9155
9156bool JSObject::HasDictionaryArgumentsElements() {
9157 Heap* heap = GetHeap();
9158 if (!elements()->IsFixedArray()) return false;
9159 FixedArray* elements = FixedArray::cast(this->elements());
9160 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9161 return false;
9162 }
9163 FixedArray* arguments = FixedArray::cast(elements->get(1));
9164 return arguments->IsDictionary();
9165}
9166
9167
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009168// Adding n elements in fast case is O(n*n).
9169// Note: revisit design to have dual undefined values to capture absent
9170// elements.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009171MaybeObject* JSObject::SetFastElement(uint32_t index,
9172 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009173 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009174 bool check_prototype) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009175 ASSERT(HasFastSmiOrObjectElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009176 HasFastArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009177
whesse@chromium.org7b260152011-06-20 15:33:18 +00009178 FixedArray* backing_store = FixedArray::cast(elements());
9179 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
9180 backing_store = FixedArray::cast(backing_store->get(1));
9181 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009182 MaybeObject* maybe = EnsureWritableFastElements();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009183 if (!maybe->To(&backing_store)) return maybe;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009184 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009185 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009186
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009187 if (check_prototype &&
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009188 (index >= capacity || backing_store->get(index)->IsTheHole())) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00009189 bool found;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009190 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9191 value,
9192 &found,
9193 strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00009194 if (found) return result;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009195 }
9196
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009197 uint32_t new_capacity = capacity;
9198 // Check if the length property of this object needs to be updated.
9199 uint32_t array_length = 0;
9200 bool must_update_array_length = false;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009201 bool introduces_holes = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009202 if (IsJSArray()) {
9203 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009204 introduces_holes = index > array_length;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009205 if (index >= array_length) {
9206 must_update_array_length = true;
9207 array_length = index + 1;
9208 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009209 } else {
9210 introduces_holes = index >= capacity;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009211 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009212
9213 // If the array is growing, and it's not growth by a single element at the
9214 // end, make sure that the ElementsKind is HOLEY.
9215 ElementsKind elements_kind = GetElementsKind();
9216 if (introduces_holes &&
9217 IsFastElementsKind(elements_kind) &&
9218 !IsFastHoleyElementsKind(elements_kind)) {
9219 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
9220 MaybeObject* maybe = TransitionElementsKind(transitioned_kind);
9221 if (maybe->IsFailure()) return maybe;
9222 }
9223
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009224 // Check if the capacity of the backing store needs to be increased, or if
9225 // a transition to slow elements is necessary.
9226 if (index >= capacity) {
9227 bool convert_to_slow = true;
9228 if ((index - capacity) < kMaxGap) {
9229 new_capacity = NewElementsCapacity(index + 1);
9230 ASSERT(new_capacity > index);
9231 if (!ShouldConvertToSlowElements(new_capacity)) {
9232 convert_to_slow = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009233 }
9234 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009235 if (convert_to_slow) {
9236 MaybeObject* result = NormalizeElements();
9237 if (result->IsFailure()) return result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009238 return SetDictionaryElement(index, value, NONE, strict_mode,
9239 check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009240 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009241 }
9242 // Convert to fast double elements if appropriate.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009243 if (HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009244 MaybeObject* maybe =
9245 SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
9246 if (maybe->IsFailure()) return maybe;
9247 FixedDoubleArray::cast(elements())->set(index, value->Number());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009248 ValidateElements();
ager@chromium.orgbdf2f942008-10-17 07:23:00 +00009249 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009250 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009251 // Change elements kind from Smi-only to generic FAST if necessary.
9252 if (HasFastSmiElements() && !value->IsSmi()) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009253 Map* new_map;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009254 ElementsKind kind = HasFastHoleyElements()
9255 ? FAST_HOLEY_ELEMENTS
9256 : FAST_ELEMENTS;
9257 MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
9258 kind);
9259 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9260
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009261 set_map(new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009262 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009263 // Increase backing store capacity if that's been decided previously.
9264 if (new_capacity != capacity) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009265 FixedArray* new_elements;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009266 SetFastElementsCapacitySmiMode smi_mode =
9267 value->IsSmi() && HasFastSmiElements()
9268 ? kAllowSmiElements
9269 : kDontAllowSmiElements;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009270 { MaybeObject* maybe =
9271 SetFastElementsCapacityAndLength(new_capacity,
9272 array_length,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009273 smi_mode);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009274 if (!maybe->To(&new_elements)) return maybe;
9275 }
9276 new_elements->set(index, value);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009277 ValidateElements();
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009278 return value;
9279 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009280
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009281 // Finally, set the new element and length.
9282 ASSERT(elements()->IsFixedArray());
9283 backing_store->set(index, value);
9284 if (must_update_array_length) {
9285 JSArray::cast(this)->set_length(Smi::FromInt(array_length));
9286 }
9287 return value;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009288}
9289
9290
9291MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
9292 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009293 PropertyAttributes attributes,
whesse@chromium.org7b260152011-06-20 15:33:18 +00009294 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009295 bool check_prototype,
9296 SetPropertyMode set_mode) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009297 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9298 Isolate* isolate = GetIsolate();
9299 Heap* heap = isolate->heap();
9300
9301 // Insert element in the dictionary.
9302 FixedArray* elements = FixedArray::cast(this->elements());
9303 bool is_arguments =
9304 (elements->map() == heap->non_strict_arguments_elements_map());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009305 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009306 if (is_arguments) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009307 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00009308 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009309 dictionary = SeededNumberDictionary::cast(elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009310 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009311
9312 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009313 if (entry != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009314 Object* element = dictionary->ValueAt(entry);
9315 PropertyDetails details = dictionary->DetailsAt(entry);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009316 if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009317 return SetElementWithCallback(element, index, value, this, strict_mode);
9318 } else {
9319 dictionary->UpdateMaxNumberKey(index);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009320 // If a value has not been initialized we allow writing to it even if it
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009321 // is read-only (a declared const that has not been initialized). If a
9322 // value is being defined we skip attribute checks completely.
9323 if (set_mode == DEFINE_PROPERTY) {
9324 details = PropertyDetails(attributes, NORMAL, details.index());
9325 dictionary->DetailsAtPut(entry, details);
9326 } else if (details.IsReadOnly() && !element->IsTheHole()) {
9327 if (strict_mode == kNonStrictMode) {
9328 return isolate->heap()->undefined_value();
9329 } else {
9330 Handle<Object> holder(this);
9331 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9332 Handle<Object> args[2] = { number, holder };
9333 Handle<Object> error =
9334 isolate->factory()->NewTypeError("strict_read_only_property",
9335 HandleVector(args, 2));
9336 return isolate->Throw(*error);
9337 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009338 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009339 // Elements of the arguments object in slow mode might be slow aliases.
9340 if (is_arguments && element->IsAliasedArgumentsEntry()) {
9341 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(element);
9342 Context* context = Context::cast(elements->get(0));
9343 int context_index = entry->aliased_context_slot();
9344 ASSERT(!context->get(context_index)->IsTheHole());
9345 context->set(context_index, value);
9346 // For elements that are still writable we keep slow aliasing.
9347 if (!details.IsReadOnly()) value = element;
9348 }
9349 dictionary->ValueAtPut(entry, value);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009350 }
9351 } else {
9352 // Index not already used. Look for an accessor in the prototype chain.
9353 if (check_prototype) {
9354 bool found;
9355 MaybeObject* result =
9356 SetElementWithCallbackSetterInPrototypes(
9357 index, value, &found, strict_mode);
9358 if (found) return result;
9359 }
9360 // When we set the is_extensible flag to false we always force the
9361 // element into dictionary mode (and force them to stay there).
9362 if (!map()->is_extensible()) {
9363 if (strict_mode == kNonStrictMode) {
9364 return isolate->heap()->undefined_value();
9365 } else {
9366 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9367 Handle<String> name = isolate->factory()->NumberToString(number);
9368 Handle<Object> args[1] = { name };
9369 Handle<Object> error =
9370 isolate->factory()->NewTypeError("object_not_extensible",
9371 HandleVector(args, 1));
9372 return isolate->Throw(*error);
9373 }
9374 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009375 FixedArrayBase* new_dictionary;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009376 PropertyDetails details = PropertyDetails(attributes, NORMAL);
9377 MaybeObject* maybe = dictionary->AddNumberEntry(index, value, details);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009378 if (!maybe->To(&new_dictionary)) return maybe;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009379 if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009380 if (is_arguments) {
9381 elements->set(1, new_dictionary);
9382 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009383 set_elements(new_dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009384 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009385 dictionary = SeededNumberDictionary::cast(new_dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009386 }
9387 }
9388
9389 // Update the array length if this JSObject is an array.
9390 if (IsJSArray()) {
9391 MaybeObject* result =
9392 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
9393 if (result->IsFailure()) return result;
9394 }
9395
9396 // Attempt to put this object back in fast case.
9397 if (ShouldConvertToFastElements()) {
9398 uint32_t new_length = 0;
9399 if (IsJSArray()) {
9400 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
9401 } else {
9402 new_length = dictionary->max_number_key() + 1;
9403 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009404 SetFastElementsCapacitySmiMode smi_mode = FLAG_smi_only_arrays
9405 ? kAllowSmiElements
9406 : kDontAllowSmiElements;
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00009407 bool has_smi_only_elements = false;
9408 bool should_convert_to_fast_double_elements =
9409 ShouldConvertToFastDoubleElements(&has_smi_only_elements);
9410 if (has_smi_only_elements) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009411 smi_mode = kForceSmiElements;
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00009412 }
9413 MaybeObject* result = should_convert_to_fast_double_elements
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009414 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009415 : SetFastElementsCapacityAndLength(new_length,
9416 new_length,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009417 smi_mode);
9418 ValidateElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +00009419 if (result->IsFailure()) return result;
9420#ifdef DEBUG
9421 if (FLAG_trace_normalization) {
9422 PrintF("Object elements are fast case again:\n");
9423 Print();
9424 }
9425#endif
9426 }
9427 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009428}
9429
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00009430
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009431MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
9432 uint32_t index,
9433 Object* value,
9434 StrictModeFlag strict_mode,
9435 bool check_prototype) {
9436 ASSERT(HasFastDoubleElements());
9437
yangguo@chromium.org56454712012-02-16 15:33:53 +00009438 FixedArrayBase* base_elms = FixedArrayBase::cast(elements());
9439 uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009440
9441 // If storing to an element that isn't in the array, pass the store request
9442 // up the prototype chain before storing in the receiver's elements.
9443 if (check_prototype &&
yangguo@chromium.org56454712012-02-16 15:33:53 +00009444 (index >= elms_length ||
9445 FixedDoubleArray::cast(base_elms)->is_the_hole(index))) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009446 bool found;
9447 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9448 value,
9449 &found,
9450 strict_mode);
9451 if (found) return result;
9452 }
9453
9454 // If the value object is not a heap number, switch to fast elements and try
9455 // again.
9456 bool value_is_smi = value->IsSmi();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009457 bool introduces_holes = true;
9458 uint32_t length = elms_length;
9459 if (IsJSArray()) {
9460 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9461 introduces_holes = index > length;
9462 } else {
9463 introduces_holes = index >= elms_length;
9464 }
9465
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009466 if (!value->IsNumber()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009467 MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
9468 elms_length,
9469 length,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009470 kDontAllowSmiElements);
9471 if (maybe_obj->IsFailure()) return maybe_obj;
9472 maybe_obj = SetFastElement(index, value, strict_mode, check_prototype);
9473 if (maybe_obj->IsFailure()) return maybe_obj;
9474 ValidateElements();
9475 return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009476 }
9477
9478 double double_value = value_is_smi
9479 ? static_cast<double>(Smi::cast(value)->value())
9480 : HeapNumber::cast(value)->value();
9481
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009482 // If the array is growing, and it's not growth by a single element at the
9483 // end, make sure that the ElementsKind is HOLEY.
9484 ElementsKind elements_kind = GetElementsKind();
9485 if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) {
9486 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
9487 MaybeObject* maybe = TransitionElementsKind(transitioned_kind);
9488 if (maybe->IsFailure()) return maybe;
9489 }
9490
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009491 // Check whether there is extra space in the fixed array.
9492 if (index < elms_length) {
yangguo@chromium.org56454712012-02-16 15:33:53 +00009493 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009494 elms->set(index, double_value);
9495 if (IsJSArray()) {
9496 // Update the length of the array if needed.
9497 uint32_t array_length = 0;
9498 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9499 if (index >= array_length) {
9500 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
9501 }
9502 }
9503 return value;
9504 }
9505
9506 // Allow gap in fast case.
9507 if ((index - elms_length) < kMaxGap) {
9508 // Try allocating extra space.
9509 int new_capacity = NewElementsCapacity(index+1);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00009510 if (!ShouldConvertToSlowElements(new_capacity)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009511 ASSERT(static_cast<uint32_t>(new_capacity) > index);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009512 MaybeObject* maybe_obj =
9513 SetFastDoubleElementsCapacityAndLength(new_capacity, index + 1);
9514 if (maybe_obj->IsFailure()) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009515 FixedDoubleArray::cast(elements())->set(index, double_value);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009516 ValidateElements();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009517 return value;
9518 }
9519 }
9520
9521 // Otherwise default to slow case.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009522 ASSERT(HasFastDoubleElements());
9523 ASSERT(map()->has_fast_double_elements());
9524 ASSERT(elements()->IsFixedDoubleArray());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009525 Object* obj;
9526 { MaybeObject* maybe_obj = NormalizeElements();
9527 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9528 }
9529 ASSERT(HasDictionaryElements());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009530 return SetElement(index, value, NONE, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009531}
9532
9533
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009534MaybeObject* JSReceiver::SetElement(uint32_t index,
9535 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009536 PropertyAttributes attributes,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009537 StrictModeFlag strict_mode,
9538 bool check_proto) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009539 if (IsJSProxy()) {
9540 return JSProxy::cast(this)->SetElementWithHandler(
verwaest@chromium.org37141392012-05-31 13:27:02 +00009541 this, index, value, strict_mode);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009542 } else {
9543 return JSObject::cast(this)->SetElement(
9544 index, value, attributes, strict_mode, check_proto);
9545 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009546}
9547
9548
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009549Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
9550 uint32_t index,
9551 Handle<Object> value,
9552 StrictModeFlag strict_mode) {
9553 ASSERT(!object->HasExternalArrayElements());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009554 CALL_HEAP_FUNCTION(
9555 object->GetIsolate(),
9556 object->SetElement(index, *value, NONE, strict_mode, false),
9557 Object);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009558}
9559
9560
9561Handle<Object> JSObject::SetElement(Handle<JSObject> object,
9562 uint32_t index,
9563 Handle<Object> value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009564 PropertyAttributes attr,
9565 StrictModeFlag strict_mode,
9566 SetPropertyMode set_mode) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009567 if (object->HasExternalArrayElements()) {
9568 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
9569 bool has_exception;
9570 Handle<Object> number = Execution::ToNumber(value, &has_exception);
9571 if (has_exception) return Handle<Object>();
9572 value = number;
9573 }
9574 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009575 CALL_HEAP_FUNCTION(
9576 object->GetIsolate(),
9577 object->SetElement(index, *value, attr, strict_mode, true, set_mode),
9578 Object);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009579}
9580
9581
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009582MaybeObject* JSObject::SetElement(uint32_t index,
9583 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009584 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009585 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009586 bool check_prototype,
9587 SetPropertyMode set_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009588 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009589 if (IsAccessCheckNeeded()) {
9590 Heap* heap = GetHeap();
9591 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009592 HandleScope scope(heap->isolate());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009593 Handle<Object> value_handle(value);
9594 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
9595 return *value_handle;
9596 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009597 }
9598
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009599 if (IsJSGlobalProxy()) {
9600 Object* proto = GetPrototype();
9601 if (proto->IsNull()) return value;
9602 ASSERT(proto->IsJSGlobalObject());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009603 return JSObject::cast(proto)->SetElement(index,
9604 value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009605 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009606 strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009607 check_prototype,
9608 set_mode);
9609 }
9610
9611 // Don't allow element properties to be redefined for external arrays.
9612 if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) {
9613 Isolate* isolate = GetHeap()->isolate();
9614 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9615 Handle<Object> args[] = { Handle<Object>(this), number };
9616 Handle<Object> error = isolate->factory()->NewTypeError(
9617 "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args)));
9618 return isolate->Throw(*error);
9619 }
9620
9621 // Normalize the elements to enable attributes on the property.
9622 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
9623 SeededNumberDictionary* dictionary;
9624 MaybeObject* maybe_object = NormalizeElements();
9625 if (!maybe_object->To(&dictionary)) return maybe_object;
9626 // Make sure that we never go back to fast case.
9627 dictionary->set_requires_slow_elements();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009628 }
9629
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009630 // Check for lookup interceptor
9631 if (HasIndexedInterceptor()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009632 return SetElementWithInterceptor(index,
9633 value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009634 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009635 strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009636 check_prototype,
9637 set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009638 }
9639
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009640 return SetElementWithoutInterceptor(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);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009646}
9647
9648
lrn@chromium.org303ada72010-10-27 09:33:13 +00009649MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009650 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009651 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009652 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009653 bool check_prototype,
9654 SetPropertyMode set_mode) {
9655 ASSERT(HasDictionaryElements() ||
9656 HasDictionaryArgumentsElements() ||
9657 (attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009658 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009659 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009660 case FAST_SMI_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009661 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009662 case FAST_HOLEY_SMI_ELEMENTS:
9663 case FAST_HOLEY_ELEMENTS:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009664 return SetFastElement(index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009665 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009666 case FAST_HOLEY_DOUBLE_ELEMENTS:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009667 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009668 case EXTERNAL_PIXEL_ELEMENTS: {
9669 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009670 return pixels->SetValue(index, value);
9671 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009672 case EXTERNAL_BYTE_ELEMENTS: {
9673 ExternalByteArray* array = ExternalByteArray::cast(elements());
9674 return array->SetValue(index, value);
9675 }
9676 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9677 ExternalUnsignedByteArray* array =
9678 ExternalUnsignedByteArray::cast(elements());
9679 return array->SetValue(index, value);
9680 }
9681 case EXTERNAL_SHORT_ELEMENTS: {
9682 ExternalShortArray* array = ExternalShortArray::cast(elements());
9683 return array->SetValue(index, value);
9684 }
9685 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9686 ExternalUnsignedShortArray* array =
9687 ExternalUnsignedShortArray::cast(elements());
9688 return array->SetValue(index, value);
9689 }
9690 case EXTERNAL_INT_ELEMENTS: {
9691 ExternalIntArray* array = ExternalIntArray::cast(elements());
9692 return array->SetValue(index, value);
9693 }
9694 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9695 ExternalUnsignedIntArray* array =
9696 ExternalUnsignedIntArray::cast(elements());
9697 return array->SetValue(index, value);
9698 }
9699 case EXTERNAL_FLOAT_ELEMENTS: {
9700 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
9701 return array->SetValue(index, value);
9702 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009703 case EXTERNAL_DOUBLE_ELEMENTS: {
9704 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
9705 return array->SetValue(index, value);
9706 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009707 case DICTIONARY_ELEMENTS:
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009708 return SetDictionaryElement(index, value, attr, strict_mode,
9709 check_prototype, set_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009710 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9711 FixedArray* parameter_map = FixedArray::cast(elements());
9712 uint32_t length = parameter_map->length();
9713 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00009714 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009715 if (probe != NULL && !probe->IsTheHole()) {
9716 Context* context = Context::cast(parameter_map->get(0));
9717 int context_index = Smi::cast(probe)->value();
9718 ASSERT(!context->get(context_index)->IsTheHole());
9719 context->set(context_index, value);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009720 // Redefining attributes of an aliased element destroys fast aliasing.
9721 if (set_mode == SET_PROPERTY || attr == NONE) return value;
9722 parameter_map->set_the_hole(index + 2);
9723 // For elements that are still writable we re-establish slow aliasing.
9724 if ((attr & READ_ONLY) == 0) {
9725 MaybeObject* maybe_entry =
9726 isolate->heap()->AllocateAliasedArgumentsEntry(context_index);
9727 if (!maybe_entry->ToObject(&value)) return maybe_entry;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009728 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009729 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009730 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9731 if (arguments->IsDictionary()) {
9732 return SetDictionaryElement(index, value, attr, strict_mode,
9733 check_prototype, set_mode);
9734 } else {
9735 return SetFastElement(index, value, strict_mode, check_prototype);
9736 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009737 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009738 }
9739 // All possible cases have been handled above. Add a return to avoid the
9740 // complaints from the compiler.
9741 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009742 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009743}
9744
9745
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009746Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
9747 ElementsKind to_kind) {
9748 CALL_HEAP_FUNCTION(object->GetIsolate(),
9749 object->TransitionElementsKind(to_kind),
9750 Object);
9751}
9752
9753
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009754MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009755 ElementsKind from_kind = map()->elements_kind();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009756
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009757 if (IsFastHoleyElementsKind(from_kind)) {
9758 to_kind = GetHoleyElementsKind(to_kind);
9759 }
9760
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009761 Isolate* isolate = GetIsolate();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009762 if (elements() == isolate->heap()->empty_fixed_array() ||
9763 (IsFastSmiOrObjectElementsKind(from_kind) &&
9764 IsFastSmiOrObjectElementsKind(to_kind)) ||
9765 (from_kind == FAST_DOUBLE_ELEMENTS &&
9766 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) {
9767 ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND);
9768 // No change is needed to the elements() buffer, the transition
9769 // only requires a map change.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009770 MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
9771 Map* new_map;
9772 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9773 set_map(new_map);
9774 if (FLAG_trace_elements_transitions) {
9775 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9776 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
9777 }
9778 return this;
9779 }
9780
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009781 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9782 uint32_t capacity = static_cast<uint32_t>(elms->length());
9783 uint32_t length = capacity;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009784
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009785 if (IsJSArray()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009786 Object* raw_length = JSArray::cast(this)->length();
9787 if (raw_length->IsUndefined()) {
9788 // If length is undefined, then JSArray is being initialized and has no
9789 // elements, assume a length of zero.
9790 length = 0;
9791 } else {
9792 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009793 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009794 }
9795
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009796 if (IsFastSmiElementsKind(from_kind) &&
9797 IsFastDoubleElementsKind(to_kind)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009798 MaybeObject* maybe_result =
9799 SetFastDoubleElementsCapacityAndLength(capacity, length);
9800 if (maybe_result->IsFailure()) return maybe_result;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009801 ValidateElements();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009802 return this;
9803 }
9804
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009805 if (IsFastDoubleElementsKind(from_kind) &&
9806 IsFastObjectElementsKind(to_kind)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009807 MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009808 capacity, length, kDontAllowSmiElements);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009809 if (maybe_result->IsFailure()) return maybe_result;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009810 ValidateElements();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009811 return this;
9812 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009813
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009814 // This method should never be called for any other case than the ones
9815 // handled above.
9816 UNREACHABLE();
9817 return GetIsolate()->heap()->null_value();
9818}
9819
9820
9821// static
9822bool Map::IsValidElementsTransition(ElementsKind from_kind,
9823 ElementsKind to_kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009824 // Transitions can't go backwards.
9825 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
9826 return false;
9827 }
9828
9829 // Transitions from HOLEY -> PACKED are not allowed.
9830 return !IsFastHoleyElementsKind(from_kind) ||
9831 IsFastHoleyElementsKind(to_kind);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009832}
9833
9834
lrn@chromium.org303ada72010-10-27 09:33:13 +00009835MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
9836 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009837 uint32_t old_len = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009838 CHECK(length()->ToArrayIndex(&old_len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009839 // Check to see if we need to update the length. For now, we make
9840 // sure that the length stays within 32-bits (unsigned).
9841 if (index >= old_len && index != 0xffffffff) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009842 Object* len;
9843 { MaybeObject* maybe_len =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009844 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009845 if (!maybe_len->ToObject(&len)) return maybe_len;
9846 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009847 set_length(len);
9848 }
9849 return value;
9850}
9851
9852
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00009853MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009854 uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009855 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009856 // Make sure that the top context does not change when doing
9857 // callbacks or interceptor calls.
9858 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009859 HandleScope scope(isolate);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009860 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
9861 Handle<Object> this_handle(receiver, isolate);
9862 Handle<JSObject> holder_handle(this, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009863 if (!interceptor->getter()->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009864 v8::IndexedPropertyGetter getter =
9865 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009866 LOG(isolate,
9867 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
9868 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009869 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009870 v8::Handle<v8::Value> result;
9871 {
9872 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009873 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009874 result = getter(index, info);
9875 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009876 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009877 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
9878 }
9879
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009880 Heap* heap = holder_handle->GetHeap();
9881 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009882 MaybeObject* raw_result = handler->Get(*this_handle,
rossberg@chromium.org28a37082011-08-22 11:03:23 +00009883 *holder_handle,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009884 index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009885 if (raw_result != heap->the_hole_value()) return raw_result;
9886
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009887 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009888
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009889 Object* pt = holder_handle->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009890 if (pt == heap->null_value()) return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009891 return pt->GetElementWithReceiver(*this_handle, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009892}
9893
9894
9895bool JSObject::HasDenseElements() {
9896 int capacity = 0;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009897 int used = 0;
9898 GetElementsCapacityAndUsage(&capacity, &used);
9899 return (capacity == 0) || (used > (capacity / 2));
9900}
9901
9902
9903void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
9904 *capacity = 0;
9905 *used = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009906
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009907 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
9908 FixedArray* backing_store = NULL;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009909 switch (GetElementsKind()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009910 case NON_STRICT_ARGUMENTS_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009911 backing_store_base =
9912 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
9913 backing_store = FixedArray::cast(backing_store_base);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009914 if (backing_store->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009915 SeededNumberDictionary* dictionary =
9916 SeededNumberDictionary::cast(backing_store);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009917 *capacity = dictionary->Capacity();
9918 *used = dictionary->NumberOfElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +00009919 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009920 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009921 // Fall through.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009922 case FAST_SMI_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +00009923 case FAST_ELEMENTS:
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009924 if (IsJSArray()) {
9925 *capacity = backing_store_base->length();
9926 *used = Smi::cast(JSArray::cast(this)->length())->value();
9927 break;
9928 }
9929 // Fall through if packing is not guaranteed.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009930 case FAST_HOLEY_SMI_ELEMENTS:
9931 case FAST_HOLEY_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009932 backing_store = FixedArray::cast(backing_store_base);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009933 *capacity = backing_store->length();
9934 for (int i = 0; i < *capacity; ++i) {
9935 if (!backing_store->get(i)->IsTheHole()) ++(*used);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009936 }
9937 break;
9938 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009939 SeededNumberDictionary* dictionary =
9940 SeededNumberDictionary::cast(FixedArray::cast(elements()));
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009941 *capacity = dictionary->Capacity();
9942 *used = dictionary->NumberOfElements();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009943 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009944 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009945 case FAST_DOUBLE_ELEMENTS:
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009946 if (IsJSArray()) {
9947 *capacity = backing_store_base->length();
9948 *used = Smi::cast(JSArray::cast(this)->length())->value();
9949 break;
9950 }
9951 // Fall through if packing is not guaranteed.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00009952 case FAST_HOLEY_DOUBLE_ELEMENTS: {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009953 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009954 *capacity = elms->length();
9955 for (int i = 0; i < *capacity; i++) {
9956 if (!elms->is_the_hole(i)) ++(*used);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009957 }
9958 break;
9959 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009960 case EXTERNAL_BYTE_ELEMENTS:
9961 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9962 case EXTERNAL_SHORT_ELEMENTS:
9963 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9964 case EXTERNAL_INT_ELEMENTS:
9965 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009966 case EXTERNAL_FLOAT_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009967 case EXTERNAL_DOUBLE_ELEMENTS:
9968 case EXTERNAL_PIXEL_ELEMENTS:
9969 // External arrays are considered 100% used.
9970 ExternalArray* external_array = ExternalArray::cast(elements());
9971 *capacity = external_array->length();
9972 *used = external_array->length();
9973 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009974 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009975}
9976
9977
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009978bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009979 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
9980 kMaxUncheckedFastElementsLength);
9981 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
9982 (new_capacity <= kMaxUncheckedFastElementsLength &&
9983 GetHeap()->InNewSpace(this))) {
9984 return false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009985 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009986 // If the fast-case backing storage takes up roughly three times as
9987 // much space (in machine words) as a dictionary backing storage
9988 // would, the object should have slow elements.
9989 int old_capacity = 0;
9990 int used_elements = 0;
9991 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009992 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
9993 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009994 return 3 * dictionary_size <= new_capacity;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995}
9996
9997
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009998bool JSObject::ShouldConvertToFastElements() {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009999 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010000 // If the elements are sparse, we should not go back to fast case.
10001 if (!HasDenseElements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010002 // An object requiring access checks is never allowed to have fast
10003 // elements. If it had fast elements we would skip security checks.
10004 if (IsAccessCheckNeeded()) return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010005
10006 FixedArray* elements = FixedArray::cast(this->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010007 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010008 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010009 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +000010010 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010011 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +000010012 }
10013 // If an element has been added at a very high index in the elements
10014 // dictionary, we cannot go back to fast case.
10015 if (dictionary->requires_slow_elements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010016 // If the dictionary backing storage takes up roughly half as much
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010017 // space (in machine words) as a fast-case backing storage would,
10018 // the object should have fast elements.
10019 uint32_t array_size = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010020 if (IsJSArray()) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010021 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010022 } else {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010023 array_size = dictionary->max_number_key();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010024 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010025 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010026 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010027 return 2 * dictionary_size >= array_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010028}
10029
10030
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010031bool JSObject::ShouldConvertToFastDoubleElements(
10032 bool* has_smi_only_elements) {
10033 *has_smi_only_elements = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010034 if (FLAG_unbox_double_arrays) {
10035 ASSERT(HasDictionaryElements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010036 SeededNumberDictionary* dictionary =
10037 SeededNumberDictionary::cast(elements());
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010038 bool found_double = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010039 for (int i = 0; i < dictionary->Capacity(); i++) {
10040 Object* key = dictionary->KeyAt(i);
10041 if (key->IsNumber()) {
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010042 Object* value = dictionary->ValueAt(i);
10043 if (!value->IsNumber()) return false;
10044 if (!value->IsSmi()) {
10045 found_double = true;
10046 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010047 }
10048 }
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010049 *has_smi_only_elements = !found_double;
10050 return found_double;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010051 } else {
10052 return false;
10053 }
10054}
10055
10056
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010057// Certain compilers request function template instantiation when they
10058// see the definition of the other template functions in the
10059// class. This requires us to have the template functions put
10060// together, so even though this function belongs in objects-debug.cc,
10061// we keep it here instead to satisfy certain compilers.
whesse@chromium.org023421e2010-12-21 12:19:12 +000010062#ifdef OBJECT_PRINT
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010063template<typename Shape, typename Key>
whesse@chromium.org023421e2010-12-21 12:19:12 +000010064void Dictionary<Shape, Key>::Print(FILE* out) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010065 int capacity = HashTable<Shape, Key>::Capacity();
10066 for (int i = 0; i < capacity; i++) {
10067 Object* k = HashTable<Shape, Key>::KeyAt(i);
10068 if (HashTable<Shape, Key>::IsKey(k)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010069 PrintF(out, " ");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010070 if (k->IsString()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010071 String::cast(k)->StringPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010072 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010073 k->ShortPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010074 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000010075 PrintF(out, ": ");
10076 ValueAt(i)->ShortPrint(out);
10077 PrintF(out, "\n");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010078 }
10079 }
10080}
10081#endif
10082
10083
10084template<typename Shape, typename Key>
10085void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010086 int pos = 0;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010087 int capacity = HashTable<Shape, Key>::Capacity();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010088 AssertNoAllocation no_gc;
10089 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010090 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010091 Object* k = Dictionary<Shape, Key>::KeyAt(i);
10092 if (Dictionary<Shape, Key>::IsKey(k)) {
10093 elements->set(pos++, ValueAt(i), mode);
10094 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010095 }
10096 ASSERT(pos == elements->length());
10097}
10098
10099
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010100InterceptorInfo* JSObject::GetNamedInterceptor() {
10101 ASSERT(map()->has_named_interceptor());
10102 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010103 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010104 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010105 constructor->shared()->get_api_func_data()->named_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010106 return InterceptorInfo::cast(result);
10107}
10108
10109
10110InterceptorInfo* JSObject::GetIndexedInterceptor() {
10111 ASSERT(map()->has_indexed_interceptor());
10112 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010113 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010114 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010115 constructor->shared()->get_api_func_data()->indexed_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010116 return InterceptorInfo::cast(result);
10117}
10118
10119
lrn@chromium.org303ada72010-10-27 09:33:13 +000010120MaybeObject* JSObject::GetPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010121 JSReceiver* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010122 String* name,
10123 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010124 // Check local property in holder, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010125 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010126 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010127 if (result.IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +000010128 return GetProperty(receiver, &result, name, attributes);
10129 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010130 // Continue searching via the prototype chain.
10131 Object* pt = GetPrototype();
10132 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010133 if (pt->IsNull()) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010134 return pt->GetPropertyWithReceiver(receiver, name, attributes);
10135}
10136
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010137
lrn@chromium.org303ada72010-10-27 09:33:13 +000010138MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010139 JSReceiver* receiver,
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010140 String* name,
10141 PropertyAttributes* attributes) {
10142 // Check local property in holder, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010143 LookupResult result(GetIsolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010144 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010145 if (result.IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +000010146 return GetProperty(receiver, &result, name, attributes);
10147 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010148 return GetHeap()->undefined_value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010149}
10150
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010151
lrn@chromium.org303ada72010-10-27 09:33:13 +000010152MaybeObject* JSObject::GetPropertyWithInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010153 JSReceiver* receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +000010154 String* name,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010155 PropertyAttributes* attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010156 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010157 InterceptorInfo* interceptor = GetNamedInterceptor();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010158 HandleScope scope(isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010159 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010160 Handle<JSObject> holder_handle(this);
10161 Handle<String> name_handle(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010162
10163 if (!interceptor->getter()->IsUndefined()) {
10164 v8::NamedPropertyGetter getter =
10165 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010166 LOG(isolate,
10167 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
10168 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010169 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010170 v8::Handle<v8::Value> result;
10171 {
10172 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010173 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010174 result = getter(v8::Utils::ToLocal(name_handle), info);
10175 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010176 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010177 if (!result.IsEmpty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010178 *attributes = NONE;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010179 return *v8::Utils::OpenHandle(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010180 }
10181 }
10182
lrn@chromium.org303ada72010-10-27 09:33:13 +000010183 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010184 *receiver_handle,
10185 *name_handle,
10186 attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010187 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +000010188 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010189}
10190
10191
10192bool JSObject::HasRealNamedProperty(String* key) {
10193 // Check access rights if needed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010194 Isolate* isolate = GetIsolate();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010195 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010196 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10197 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010198 return false;
10199 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200 }
10201
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010202 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010203 LocalLookupRealNamedProperty(key, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010204 return result.IsFound() && !result.IsInterceptor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010205}
10206
10207
10208bool JSObject::HasRealElementProperty(uint32_t index) {
10209 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010210 if (IsAccessCheckNeeded()) {
10211 Heap* heap = GetHeap();
10212 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
10213 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10214 return false;
10215 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010216 }
10217
10218 // Handle [] on String objects.
10219 if (this->IsStringObjectWithCharacterAt(index)) return true;
10220
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010221 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010222 case FAST_SMI_ELEMENTS:
10223 case FAST_ELEMENTS:
10224 case FAST_HOLEY_SMI_ELEMENTS:
10225 case FAST_HOLEY_ELEMENTS: {
10226 uint32_t length = IsJSArray() ?
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010227 static_cast<uint32_t>(
10228 Smi::cast(JSArray::cast(this)->length())->value()) :
10229 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10230 return (index < length) &&
10231 !FixedArray::cast(elements())->get(index)->IsTheHole();
10232 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010233 case FAST_DOUBLE_ELEMENTS:
10234 case FAST_HOLEY_DOUBLE_ELEMENTS: {
ricow@chromium.org9fa09672011-07-25 11:05:35 +000010235 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);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010284 return result.IsPropertyCallbacks();
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();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010415 ASSERT(storage->length() >= index + descs->number_of_descriptors());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010416 for (int i = 0; i < descs->number_of_descriptors(); i++) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000010417 storage->set(index + i, descs->GetKey(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010418 }
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.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010434 if (!IsJSValue() && HasFastObjectElements()) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010435 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()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010450 case FAST_SMI_ELEMENTS:
10451 case FAST_ELEMENTS:
10452 case FAST_HOLEY_SMI_ELEMENTS:
10453 case FAST_HOLEY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010454 int length = IsJSArray() ?
10455 Smi::cast(JSArray::cast(this)->length())->value() :
10456 FixedArray::cast(elements())->length();
10457 for (int i = 0; i < length; i++) {
10458 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
10459 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010460 storage->set(counter, Smi::FromInt(i));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010461 }
10462 counter++;
10463 }
10464 }
10465 ASSERT(!storage || storage->length() >= counter);
10466 break;
10467 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010468 case FAST_DOUBLE_ELEMENTS:
10469 case FAST_HOLEY_DOUBLE_ELEMENTS: {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010470 int length = IsJSArray() ?
10471 Smi::cast(JSArray::cast(this)->length())->value() :
10472 FixedDoubleArray::cast(elements())->length();
10473 for (int i = 0; i < length; i++) {
10474 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
10475 if (storage != NULL) {
10476 storage->set(counter, Smi::FromInt(i));
10477 }
10478 counter++;
10479 }
10480 }
10481 ASSERT(!storage || storage->length() >= counter);
10482 break;
10483 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010484 case EXTERNAL_PIXEL_ELEMENTS: {
10485 int length = ExternalPixelArray::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010486 while (counter < length) {
10487 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010488 storage->set(counter, Smi::FromInt(counter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010489 }
10490 counter++;
10491 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010492 ASSERT(!storage || storage->length() >= counter);
10493 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010494 }
ager@chromium.org3811b432009-10-28 14:53:37 +000010495 case EXTERNAL_BYTE_ELEMENTS:
10496 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10497 case EXTERNAL_SHORT_ELEMENTS:
10498 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10499 case EXTERNAL_INT_ELEMENTS:
10500 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010501 case EXTERNAL_FLOAT_ELEMENTS:
10502 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +000010503 int length = ExternalArray::cast(elements())->length();
10504 while (counter < length) {
10505 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010506 storage->set(counter, Smi::FromInt(counter));
ager@chromium.org3811b432009-10-28 14:53:37 +000010507 }
10508 counter++;
10509 }
10510 ASSERT(!storage || storage->length() >= counter);
10511 break;
10512 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010513 case DICTIONARY_ELEMENTS: {
10514 if (storage != NULL) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010515 element_dictionary()->CopyKeysTo(storage,
10516 filter,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010517 SeededNumberDictionary::SORTED);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010518 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010519 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010520 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010521 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010522 case NON_STRICT_ARGUMENTS_ELEMENTS: {
10523 FixedArray* parameter_map = FixedArray::cast(elements());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010524 int mapped_length = parameter_map->length() - 2;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010525 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
10526 if (arguments->IsDictionary()) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010527 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
10528 // will insert in storage starting at index 0.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010529 SeededNumberDictionary* dictionary =
10530 SeededNumberDictionary::cast(arguments);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010531 if (storage != NULL) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010532 dictionary->CopyKeysTo(
10533 storage, filter, SeededNumberDictionary::UNSORTED);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010534 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010535 counter += dictionary->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010536 for (int i = 0; i < mapped_length; ++i) {
10537 if (!parameter_map->get(i + 2)->IsTheHole()) {
10538 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
whesse@chromium.org7b260152011-06-20 15:33:18 +000010539 ++counter;
10540 }
10541 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010542 if (storage != NULL) storage->SortPairs(storage, counter);
10543
10544 } else {
10545 int backing_length = arguments->length();
10546 int i = 0;
10547 for (; i < mapped_length; ++i) {
10548 if (!parameter_map->get(i + 2)->IsTheHole()) {
10549 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10550 ++counter;
10551 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
10552 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10553 ++counter;
10554 }
10555 }
10556 for (; i < backing_length; ++i) {
10557 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10558 ++counter;
10559 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010560 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010561 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010562 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010563 }
10564
10565 if (this->IsJSValue()) {
10566 Object* val = JSValue::cast(this)->value();
10567 if (val->IsString()) {
10568 String* str = String::cast(val);
10569 if (storage) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010570 for (int i = 0; i < str->length(); i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010571 storage->set(counter + i, Smi::FromInt(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010572 }
10573 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010574 counter += str->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010575 }
10576 }
10577 ASSERT(!storage || storage->length() == counter);
10578 return counter;
10579}
10580
10581
10582int JSObject::GetEnumElementKeys(FixedArray* storage) {
10583 return GetLocalElementKeys(storage,
10584 static_cast<PropertyAttributes>(DONT_ENUM));
10585}
10586
10587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010588// StringKey simply carries a string object as key.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010589class StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010590 public:
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010591 explicit StringKey(String* string) :
10592 string_(string),
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010593 hash_(HashForObject(string)) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010595 bool IsMatch(Object* string) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010596 // We know that all entries in a hash table had their hash keys created.
10597 // Use that knowledge to have fast failure.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010598 if (hash_ != HashForObject(string)) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010599 return false;
10600 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010601 return string_->Equals(String::cast(string));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010602 }
10603
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010604 uint32_t Hash() { return hash_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010605
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010606 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010608 Object* AsObject() { return string_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609
10610 String* string_;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010611 uint32_t hash_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612};
10613
ager@chromium.org381abbb2009-02-25 13:23:22 +000010614
10615// StringSharedKeys are used as keys in the eval cache.
10616class StringSharedKey : public HashTableKey {
10617 public:
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010618 StringSharedKey(String* source,
10619 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010620 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010621 int scope_position)
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010622 : source_(source),
10623 shared_(shared),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010624 language_mode_(language_mode),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010625 scope_position_(scope_position) { }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010626
10627 bool IsMatch(Object* other) {
10628 if (!other->IsFixedArray()) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010629 FixedArray* other_array = FixedArray::cast(other);
10630 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
ager@chromium.org381abbb2009-02-25 13:23:22 +000010631 if (shared != shared_) return false;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010632 int language_unchecked = Smi::cast(other_array->get(2))->value();
10633 ASSERT(language_unchecked == CLASSIC_MODE ||
10634 language_unchecked == STRICT_MODE ||
10635 language_unchecked == EXTENDED_MODE);
10636 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10637 if (language_mode != language_mode_) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010638 int scope_position = Smi::cast(other_array->get(3))->value();
10639 if (scope_position != scope_position_) return false;
10640 String* source = String::cast(other_array->get(1));
ager@chromium.org381abbb2009-02-25 13:23:22 +000010641 return source->Equals(source_);
10642 }
10643
ager@chromium.org381abbb2009-02-25 13:23:22 +000010644 static uint32_t StringSharedHashHelper(String* source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010645 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010646 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010647 int scope_position) {
ager@chromium.org381abbb2009-02-25 13:23:22 +000010648 uint32_t hash = source->Hash();
10649 if (shared->HasSourceCode()) {
10650 // Instead of using the SharedFunctionInfo pointer in the hash
10651 // code computation, we use a combination of the hash of the
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010652 // script source code and the start position of the calling scope.
10653 // We do this to ensure that the cache entries can survive garbage
ager@chromium.org381abbb2009-02-25 13:23:22 +000010654 // collection.
10655 Script* script = Script::cast(shared->script());
10656 hash ^= String::cast(script->source())->Hash();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010657 if (language_mode == STRICT_MODE) hash ^= 0x8000;
10658 if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010659 hash += scope_position;
ager@chromium.org381abbb2009-02-25 13:23:22 +000010660 }
10661 return hash;
10662 }
10663
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010664 uint32_t Hash() {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010665 return StringSharedHashHelper(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010666 source_, shared_, language_mode_, scope_position_);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010667 }
10668
10669 uint32_t HashForObject(Object* obj) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010670 FixedArray* other_array = FixedArray::cast(obj);
10671 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10672 String* source = String::cast(other_array->get(1));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010673 int language_unchecked = Smi::cast(other_array->get(2))->value();
10674 ASSERT(language_unchecked == CLASSIC_MODE ||
10675 language_unchecked == STRICT_MODE ||
10676 language_unchecked == EXTENDED_MODE);
10677 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010678 int scope_position = Smi::cast(other_array->get(3))->value();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010679 return StringSharedHashHelper(
10680 source, shared, language_mode, scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010681 }
10682
lrn@chromium.org303ada72010-10-27 09:33:13 +000010683 MUST_USE_RESULT MaybeObject* AsObject() {
10684 Object* obj;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010685 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010686 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10687 }
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010688 FixedArray* other_array = FixedArray::cast(obj);
10689 other_array->set(0, shared_);
10690 other_array->set(1, source_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010691 other_array->set(2, Smi::FromInt(language_mode_));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010692 other_array->set(3, Smi::FromInt(scope_position_));
10693 return other_array;
ager@chromium.org381abbb2009-02-25 13:23:22 +000010694 }
10695
ager@chromium.org381abbb2009-02-25 13:23:22 +000010696 private:
10697 String* source_;
10698 SharedFunctionInfo* shared_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010699 LanguageMode language_mode_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010700 int scope_position_;
ager@chromium.org381abbb2009-02-25 13:23:22 +000010701};
10702
10703
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010704// RegExpKey carries the source and flags of a regular expression as key.
10705class RegExpKey : public HashTableKey {
10706 public:
10707 RegExpKey(String* string, JSRegExp::Flags flags)
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010708 : string_(string),
10709 flags_(Smi::FromInt(flags.value())) { }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010710
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000010711 // Rather than storing the key in the hash table, a pointer to the
10712 // stored value is stored where the key should be. IsMatch then
10713 // compares the search key to the found object, rather than comparing
10714 // a key to a key.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010715 bool IsMatch(Object* obj) {
10716 FixedArray* val = FixedArray::cast(obj);
10717 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
10718 && (flags_ == val->get(JSRegExp::kFlagsIndex));
10719 }
10720
10721 uint32_t Hash() { return RegExpHash(string_, flags_); }
10722
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010723 Object* AsObject() {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010724 // Plain hash maps, which is where regexp keys are used, don't
10725 // use this function.
10726 UNREACHABLE();
10727 return NULL;
10728 }
10729
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010730 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010731 FixedArray* val = FixedArray::cast(obj);
10732 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
10733 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
10734 }
10735
10736 static uint32_t RegExpHash(String* string, Smi* flags) {
10737 return string->Hash() + flags->value();
10738 }
10739
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010740 String* string_;
10741 Smi* flags_;
10742};
10743
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010744// Utf8SymbolKey carries a vector of chars as key.
10745class Utf8SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010747 explicit Utf8SymbolKey(Vector<const char> string, uint32_t seed)
10748 : string_(string), hash_field_(0), seed_(seed) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010749
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010750 bool IsMatch(Object* string) {
10751 return String::cast(string)->IsEqualTo(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010752 }
10753
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010754 uint32_t Hash() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010755 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010756 unibrow::Utf8InputBuffer<> buffer(string_.start(),
10757 static_cast<unsigned>(string_.length()));
yangguo@chromium.org154ff992012-03-13 08:09:54 +000010758 chars_ = buffer.Utf16Length();
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010759 hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010760 uint32_t result = hash_field_ >> String::kHashShift;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010761 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10762 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010763 }
10764
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010765 uint32_t HashForObject(Object* other) {
10766 return String::cast(other)->Hash();
10767 }
10768
lrn@chromium.org303ada72010-10-27 09:33:13 +000010769 MaybeObject* AsObject() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010770 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010771 return Isolate::Current()->heap()->AllocateSymbol(
10772 string_, chars_, hash_field_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010773 }
10774
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010775 Vector<const char> string_;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010776 uint32_t hash_field_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010777 int chars_; // Caches the number of characters when computing the hash code.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010778 uint32_t seed_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010779};
10780
10781
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010782template <typename Char>
10783class SequentialSymbolKey : public HashTableKey {
10784 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010785 explicit SequentialSymbolKey(Vector<const Char> string, uint32_t seed)
10786 : string_(string), hash_field_(0), seed_(seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010787
10788 uint32_t Hash() {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010789 StringHasher hasher(string_.length(), seed_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010790
10791 // Very long strings have a trivial hash that doesn't inspect the
10792 // string contents.
10793 if (hasher.has_trivial_hash()) {
10794 hash_field_ = hasher.GetHashField();
10795 } else {
10796 int i = 0;
10797 // Do the iterative array index computation as long as there is a
10798 // chance this is an array index.
10799 while (i < string_.length() && hasher.is_array_index()) {
10800 hasher.AddCharacter(static_cast<uc32>(string_[i]));
10801 i++;
10802 }
10803
10804 // Process the remaining characters without updating the array
10805 // index.
10806 while (i < string_.length()) {
10807 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
10808 i++;
10809 }
10810 hash_field_ = hasher.GetHashField();
10811 }
10812
10813 uint32_t result = hash_field_ >> String::kHashShift;
10814 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10815 return result;
10816 }
10817
10818
10819 uint32_t HashForObject(Object* other) {
10820 return String::cast(other)->Hash();
10821 }
10822
10823 Vector<const Char> string_;
10824 uint32_t hash_field_;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010825 uint32_t seed_;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010826};
10827
10828
10829
10830class AsciiSymbolKey : public SequentialSymbolKey<char> {
10831 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010832 AsciiSymbolKey(Vector<const char> str, uint32_t seed)
10833 : SequentialSymbolKey<char>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010834
10835 bool IsMatch(Object* string) {
10836 return String::cast(string)->IsAsciiEqualTo(string_);
10837 }
10838
10839 MaybeObject* AsObject() {
10840 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010841 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010842 }
10843};
10844
10845
danno@chromium.org40cb8782011-05-25 07:58:50 +000010846class SubStringAsciiSymbolKey : public HashTableKey {
10847 public:
10848 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
10849 int from,
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010850 int length,
10851 uint32_t seed)
10852 : string_(string), from_(from), length_(length), seed_(seed) { }
danno@chromium.org40cb8782011-05-25 07:58:50 +000010853
10854 uint32_t Hash() {
10855 ASSERT(length_ >= 0);
10856 ASSERT(from_ + length_ <= string_->length());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010857 StringHasher hasher(length_, string_->GetHeap()->HashSeed());
danno@chromium.org40cb8782011-05-25 07:58:50 +000010858
10859 // Very long strings have a trivial hash that doesn't inspect the
10860 // string contents.
10861 if (hasher.has_trivial_hash()) {
10862 hash_field_ = hasher.GetHashField();
10863 } else {
10864 int i = 0;
10865 // Do the iterative array index computation as long as there is a
10866 // chance this is an array index.
10867 while (i < length_ && hasher.is_array_index()) {
10868 hasher.AddCharacter(static_cast<uc32>(
10869 string_->SeqAsciiStringGet(i + from_)));
10870 i++;
10871 }
10872
10873 // Process the remaining characters without updating the array
10874 // index.
10875 while (i < length_) {
10876 hasher.AddCharacterNoIndex(static_cast<uc32>(
10877 string_->SeqAsciiStringGet(i + from_)));
10878 i++;
10879 }
10880 hash_field_ = hasher.GetHashField();
10881 }
10882
10883 uint32_t result = hash_field_ >> String::kHashShift;
10884 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10885 return result;
10886 }
10887
10888
10889 uint32_t HashForObject(Object* other) {
10890 return String::cast(other)->Hash();
10891 }
10892
10893 bool IsMatch(Object* string) {
10894 Vector<const char> chars(string_->GetChars() + from_, length_);
10895 return String::cast(string)->IsAsciiEqualTo(chars);
10896 }
10897
10898 MaybeObject* AsObject() {
10899 if (hash_field_ == 0) Hash();
10900 Vector<const char> chars(string_->GetChars() + from_, length_);
10901 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
10902 }
10903
10904 private:
10905 Handle<SeqAsciiString> string_;
10906 int from_;
10907 int length_;
10908 uint32_t hash_field_;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010909 uint32_t seed_;
danno@chromium.org40cb8782011-05-25 07:58:50 +000010910};
10911
10912
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010913class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
10914 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010915 explicit TwoByteSymbolKey(Vector<const uc16> str, uint32_t seed)
10916 : SequentialSymbolKey<uc16>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010917
10918 bool IsMatch(Object* string) {
10919 return String::cast(string)->IsTwoByteEqualTo(string_);
10920 }
10921
10922 MaybeObject* AsObject() {
10923 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010924 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010925 }
10926};
10927
10928
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010929// SymbolKey carries a string/symbol object as key.
10930class SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010931 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010932 explicit SymbolKey(String* string)
10933 : string_(string) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010934
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010935 bool IsMatch(Object* string) {
10936 return String::cast(string)->Equals(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010937 }
10938
10939 uint32_t Hash() { return string_->Hash(); }
10940
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010941 uint32_t HashForObject(Object* other) {
10942 return String::cast(other)->Hash();
10943 }
10944
lrn@chromium.org303ada72010-10-27 09:33:13 +000010945 MaybeObject* AsObject() {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000010946 // Attempt to flatten the string, so that symbols will most often
10947 // be flat strings.
10948 string_ = string_->TryFlattenGetString();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010949 Heap* heap = string_->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950 // Transform string to symbol if possible.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010951 Map* map = heap->SymbolMapForString(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010952 if (map != NULL) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000010953 string_->set_map_no_write_barrier(map);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010954 ASSERT(string_->IsSymbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010955 return string_;
10956 }
10957 // Otherwise allocate a new symbol.
10958 StringInputBuffer buffer(string_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010959 return heap->AllocateInternalSymbol(&buffer,
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010960 string_->length(),
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010961 string_->hash_field());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010962 }
10963
10964 static uint32_t StringHash(Object* obj) {
10965 return String::cast(obj)->Hash();
10966 }
10967
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968 String* string_;
10969};
10970
10971
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010972template<typename Shape, typename Key>
10973void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010974 IteratePointers(v, 0, kElementsStartOffset);
10975}
10976
10977
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010978template<typename Shape, typename Key>
10979void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010980 IteratePointers(v,
10981 kElementsStartOffset,
10982 kHeaderSize + length() * kPointerSize);
10983}
10984
10985
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010986template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010987MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
10988 PretenureFlag pretenure) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010989 int capacity = ComputeCapacity(at_least_space_for);
10990 if (capacity > HashTable::kMaxCapacity) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010991 return Failure::OutOfMemoryException();
10992 }
10993
lrn@chromium.org303ada72010-10-27 09:33:13 +000010994 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010995 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
10996 AllocateHashTable(EntryToIndex(capacity), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010997 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010998 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010999 HashTable::cast(obj)->SetNumberOfElements(0);
11000 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
11001 HashTable::cast(obj)->SetCapacity(capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011002 return obj;
11003}
11004
11005
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011006// Find entry for key otherwise return kNotFound.
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011007int StringDictionary::FindEntry(String* key) {
11008 if (!key->IsSymbol()) {
11009 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
11010 }
11011
11012 // Optimized for symbol key. Knowledge of the key type allows:
11013 // 1. Move the check if the key is a symbol out of the loop.
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011014 // 2. Avoid comparing hash codes in symbol to symbol comparison.
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011015 // 3. Detect a case when a dictionary key is not a symbol but the key is.
11016 // In case of positive result the dictionary key may be replaced by
11017 // the symbol with minimal performance penalty. It gives a chance to
11018 // perform further lookups in code stubs (and significant performance boost
11019 // a certain style of code).
11020
11021 // EnsureCapacity will guarantee the hash table is never full.
11022 uint32_t capacity = Capacity();
11023 uint32_t entry = FirstProbe(key->Hash(), capacity);
11024 uint32_t count = 1;
11025
11026 while (true) {
11027 int index = EntryToIndex(entry);
11028 Object* element = get(index);
11029 if (element->IsUndefined()) break; // Empty entry.
11030 if (key == element) return entry;
11031 if (!element->IsSymbol() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011032 !element->IsTheHole() &&
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011033 String::cast(element)->Equals(key)) {
11034 // Replace a non-symbol key by the equivalent symbol for faster further
11035 // lookups.
11036 set(index, key);
11037 return entry;
11038 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011039 ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key));
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011040 entry = NextProbe(entry, count++, capacity);
11041 }
11042 return kNotFound;
11043}
11044
11045
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011046template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000011047MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
11048 ASSERT(NumberOfElements() < new_table->Capacity());
11049
11050 AssertNoAllocation no_gc;
11051 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
11052
11053 // Copy prefix to new array.
11054 for (int i = kPrefixStartIndex;
11055 i < kPrefixStartIndex + Shape::kPrefixSize;
11056 i++) {
11057 new_table->set(i, get(i), mode);
11058 }
11059
11060 // Rehash the elements.
11061 int capacity = Capacity();
11062 for (int i = 0; i < capacity; i++) {
11063 uint32_t from_index = EntryToIndex(i);
11064 Object* k = get(from_index);
11065 if (IsKey(k)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011066 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
ager@chromium.org04921a82011-06-27 13:21:41 +000011067 uint32_t insertion_index =
11068 EntryToIndex(new_table->FindInsertionEntry(hash));
11069 for (int j = 0; j < Shape::kEntrySize; j++) {
11070 new_table->set(insertion_index + j, get(from_index + j), mode);
11071 }
11072 }
11073 }
11074 new_table->SetNumberOfElements(NumberOfElements());
11075 new_table->SetNumberOfDeletedElements(0);
11076 return new_table;
11077}
11078
11079
11080template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000011081MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011082 int capacity = Capacity();
11083 int nof = NumberOfElements() + n;
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +000011084 int nod = NumberOfDeletedElements();
11085 // Return if:
11086 // 50% is still free after adding n elements and
11087 // at most 50% of the free elements are deleted elements.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011088 if (nod <= (capacity - nof) >> 1) {
11089 int needed_free = nof >> 1;
11090 if (nof + needed_free <= capacity) return this;
11091 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011092
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011093 const int kMinCapacityForPretenure = 256;
11094 bool pretenure =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011095 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011096 Object* obj;
11097 { MaybeObject* maybe_obj =
11098 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
11099 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11100 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011101
ager@chromium.org04921a82011-06-27 13:21:41 +000011102 return Rehash(HashTable::cast(obj), key);
11103}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011104
ager@chromium.org04921a82011-06-27 13:21:41 +000011105
11106template<typename Shape, typename Key>
11107MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
11108 int capacity = Capacity();
11109 int nof = NumberOfElements();
11110
11111 // Shrink to fit the number of elements if only a quarter of the
11112 // capacity is filled with elements.
11113 if (nof > (capacity >> 2)) return this;
11114 // Allocate a new dictionary with room for at least the current
11115 // number of elements. The allocation method will make sure that
11116 // there is extra room in the dictionary for additions. Don't go
11117 // lower than room for 16 elements.
11118 int at_least_room_for = nof;
11119 if (at_least_room_for < 16) return this;
11120
11121 const int kMinCapacityForPretenure = 256;
11122 bool pretenure =
11123 (at_least_room_for > kMinCapacityForPretenure) &&
11124 !GetHeap()->InNewSpace(this);
11125 Object* obj;
11126 { MaybeObject* maybe_obj =
11127 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
11128 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011129 }
ager@chromium.org04921a82011-06-27 13:21:41 +000011130
11131 return Rehash(HashTable::cast(obj), key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011132}
11133
11134
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011135template<typename Shape, typename Key>
11136uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011137 uint32_t capacity = Capacity();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011138 uint32_t entry = FirstProbe(hash, capacity);
11139 uint32_t count = 1;
11140 // EnsureCapacity will guarantee the hash table is never full.
11141 while (true) {
11142 Object* element = KeyAt(entry);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011143 if (element->IsUndefined() || element->IsTheHole()) break;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011144 entry = NextProbe(entry, count++, capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011145 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011146 return entry;
11147}
11148
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011149// Force instantiation of template instances class.
11150// Please note this list is compiler dependent.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011151
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011152template class HashTable<SymbolTableShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011153
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011154template class HashTable<CompilationCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011155
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011156template class HashTable<MapCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011157
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011158template class HashTable<ObjectHashTableShape<1>, Object*>;
11159
11160template class HashTable<ObjectHashTableShape<2>, Object*>;
vegorov@chromium.org7943d462011-08-01 11:41:52 +000011161
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011162template class Dictionary<StringDictionaryShape, String*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011163
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011164template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011165
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011166template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
11167
11168template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11169 Allocate(int at_least_space_for);
11170
11171template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11172 Allocate(int at_least_space_for);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011173
lrn@chromium.org303ada72010-10-27 09:33:13 +000011174template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011175 int);
11176
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011177template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011178 uint32_t, Object*);
11179
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011180template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11181 AtPut(uint32_t, Object*);
11182
ulan@chromium.org65a89c22012-02-14 11:46:07 +000011183template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11184 SlowReverseLookup(Object* value);
11185
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011186template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11187 SlowReverseLookup(Object* value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011188
11189template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
11190 Object*);
11191
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011192template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011193 FixedArray*,
11194 PropertyAttributes,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011195 Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011196
11197template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
11198 int, JSObject::DeleteMode);
11199
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011200template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11201 DeleteProperty(int, JSObject::DeleteMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011202
ager@chromium.org04921a82011-06-27 13:21:41 +000011203template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
11204 String*);
11205
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011206template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
ager@chromium.org04921a82011-06-27 13:21:41 +000011207 uint32_t);
11208
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011209template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011210 FixedArray*,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011211 int,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011212 Dictionary<StringDictionaryShape, String*>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011213
11214template int
11215Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
11216 PropertyAttributes);
11217
lrn@chromium.org303ada72010-10-27 09:33:13 +000011218template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011219 String*, Object*, PropertyDetails);
11220
lrn@chromium.org303ada72010-10-27 09:33:13 +000011221template MaybeObject*
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011222Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
11223
11224template int
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011225Dictionary<SeededNumberDictionaryShape, uint32_t>::
11226 NumberOfElementsFilterAttributes(PropertyAttributes);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011227
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011228template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011229 uint32_t, Object*, PropertyDetails);
11230
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011231template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
11232 uint32_t, Object*, PropertyDetails);
11233
11234template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11235 EnsureCapacity(int, uint32_t);
11236
11237template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
lrn@chromium.org303ada72010-10-27 09:33:13 +000011238 EnsureCapacity(int, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011239
lrn@chromium.org303ada72010-10-27 09:33:13 +000011240template MaybeObject* Dictionary<StringDictionaryShape, String*>::
11241 EnsureCapacity(int, String*);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011242
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011243template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11244 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
11245
11246template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11247 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011248
lrn@chromium.org303ada72010-10-27 09:33:13 +000011249template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011250 String*, Object*, PropertyDetails, uint32_t);
11251
11252template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011253int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011254
11255template
11256int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011257
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011258template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011259int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011260
11261
ager@chromium.org5ec48922009-05-05 07:25:34 +000011262// Collates undefined and unexisting elements below limit from position
11263// zero of the elements. The object stays in Dictionary mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011264MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011265 ASSERT(HasDictionaryElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011266 // Must stay in dictionary mode, either because of requires_slow_elements,
11267 // or because we are not going to sort (and therefore compact) all of the
11268 // elements.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011269 SeededNumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011270 HeapNumber* result_double = NULL;
11271 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11272 // Allocate space for result before we start mutating the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011273 Object* new_double;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011274 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011275 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11276 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011277 result_double = HeapNumber::cast(new_double);
11278 }
11279
lrn@chromium.org303ada72010-10-27 09:33:13 +000011280 Object* obj;
11281 { MaybeObject* maybe_obj =
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011282 SeededNumberDictionary::Allocate(dict->NumberOfElements());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011283 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11284 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011285 SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011286
11287 AssertNoAllocation no_alloc;
11288
ager@chromium.org5ec48922009-05-05 07:25:34 +000011289 uint32_t pos = 0;
11290 uint32_t undefs = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011291 int capacity = dict->Capacity();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011292 for (int i = 0; i < capacity; i++) {
11293 Object* k = dict->KeyAt(i);
11294 if (dict->IsKey(k)) {
11295 ASSERT(k->IsNumber());
11296 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
11297 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
11298 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
11299 Object* value = dict->ValueAt(i);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011300 PropertyDetails details = dict->DetailsAt(i);
11301 if (details.type() == CALLBACKS) {
11302 // Bail out and do the sorting of undefineds and array holes in JS.
11303 return Smi::FromInt(-1);
11304 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011305 uint32_t key = NumberToUint32(k);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011306 // In the following we assert that adding the entry to the new dictionary
11307 // does not cause GC. This is the case because we made sure to allocate
11308 // the dictionary big enough above, so it need not grow.
ager@chromium.org5ec48922009-05-05 07:25:34 +000011309 if (key < limit) {
11310 if (value->IsUndefined()) {
11311 undefs++;
11312 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011313 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11314 // Adding an entry with the key beyond smi-range requires
11315 // allocation. Bailout.
11316 return Smi::FromInt(-1);
11317 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000011318 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011319 pos++;
11320 }
11321 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011322 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
11323 // Adding an entry with the key beyond smi-range requires
11324 // allocation. Bailout.
11325 return Smi::FromInt(-1);
11326 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000011327 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011328 }
11329 }
11330 }
11331
11332 uint32_t result = pos;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011333 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011334 Heap* heap = GetHeap();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011335 while (undefs > 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011336 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11337 // Adding an entry with the key beyond smi-range requires
11338 // allocation. Bailout.
11339 return Smi::FromInt(-1);
11340 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011341 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
lrn@chromium.org303ada72010-10-27 09:33:13 +000011342 ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011343 pos++;
11344 undefs--;
11345 }
11346
11347 set_elements(new_dict);
11348
11349 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11350 return Smi::FromInt(static_cast<int>(result));
11351 }
11352
11353 ASSERT_NE(NULL, result_double);
11354 result_double->set_value(static_cast<double>(result));
11355 return result_double;
11356}
11357
11358
11359// Collects all defined (non-hole) and non-undefined (array) elements at
11360// the start of the elements array.
11361// If the object is in dictionary mode, it is converted to fast elements
11362// mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011363MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011364 Heap* heap = GetHeap();
11365
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011366 if (HasDictionaryElements()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000011367 // Convert to fast elements containing only the existing properties.
11368 // Ordering is irrelevant, since we are going to sort anyway.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011369 SeededNumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011370 if (IsJSArray() || dict->requires_slow_elements() ||
11371 dict->max_number_key() >= limit) {
11372 return PrepareSlowElementsForSort(limit);
11373 }
11374 // Convert to fast elements.
11375
lrn@chromium.org303ada72010-10-27 09:33:13 +000011376 Object* obj;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011377 MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
11378 FAST_HOLEY_ELEMENTS);
11379 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011380 Map* new_map = Map::cast(obj);
11381
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011382 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
lrn@chromium.org303ada72010-10-27 09:33:13 +000011383 Object* new_array;
11384 { MaybeObject* maybe_new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011385 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011386 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
11387 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011388 FixedArray* fast_elements = FixedArray::cast(new_array);
11389 dict->CopyValuesTo(fast_elements);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011390 ValidateElements();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011391
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011392 set_map_and_elements(new_map, fast_elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011393 } else if (HasExternalArrayElements()) {
11394 // External arrays cannot have holes or undefined elements.
11395 return Smi::FromInt(ExternalArray::cast(elements())->length());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011396 } else if (!HasFastDoubleElements()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011397 Object* obj;
11398 { MaybeObject* maybe_obj = EnsureWritableFastElements();
11399 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11400 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011401 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011402 ASSERT(HasFastSmiOrObjectElements() || HasFastDoubleElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011403
11404 // Collect holes at the end, undefined before that and the rest at the
11405 // start, and return the number of non-hole, non-undefined values.
11406
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011407 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
11408 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011409 if (limit > elements_length) {
11410 limit = elements_length ;
11411 }
11412 if (limit == 0) {
11413 return Smi::FromInt(0);
11414 }
11415
11416 HeapNumber* result_double = NULL;
11417 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11418 // Pessimistically allocate space for return value before
11419 // we start mutating the array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011420 Object* new_double;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011421 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011422 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11423 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011424 result_double = HeapNumber::cast(new_double);
11425 }
11426
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011427 uint32_t result = 0;
11428 if (elements_base->map() == heap->fixed_double_array_map()) {
11429 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
11430 // Split elements into defined and the_hole, in that order.
11431 unsigned int holes = limit;
11432 // Assume most arrays contain no holes and undefined values, so minimize the
11433 // number of stores of non-undefined, non-the-hole values.
11434 for (unsigned int i = 0; i < holes; i++) {
11435 if (elements->is_the_hole(i)) {
11436 holes--;
11437 } else {
11438 continue;
11439 }
11440 // Position i needs to be filled.
11441 while (holes > i) {
11442 if (elements->is_the_hole(holes)) {
11443 holes--;
11444 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011445 elements->set(i, elements->get_scalar(holes));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011446 break;
11447 }
11448 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011449 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011450 result = holes;
11451 while (holes < limit) {
11452 elements->set_the_hole(holes);
11453 holes++;
11454 }
11455 } else {
11456 FixedArray* elements = FixedArray::cast(elements_base);
11457 AssertNoAllocation no_alloc;
11458
11459 // Split elements into defined, undefined and the_hole, in that order. Only
11460 // count locations for undefined and the hole, and fill them afterwards.
11461 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
11462 unsigned int undefs = limit;
11463 unsigned int holes = limit;
11464 // Assume most arrays contain no holes and undefined values, so minimize the
11465 // number of stores of non-undefined, non-the-hole values.
11466 for (unsigned int i = 0; i < undefs; i++) {
11467 Object* current = elements->get(i);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011468 if (current->IsTheHole()) {
11469 holes--;
11470 undefs--;
11471 } else if (current->IsUndefined()) {
11472 undefs--;
11473 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011474 continue;
11475 }
11476 // Position i needs to be filled.
11477 while (undefs > i) {
11478 current = elements->get(undefs);
11479 if (current->IsTheHole()) {
11480 holes--;
11481 undefs--;
11482 } else if (current->IsUndefined()) {
11483 undefs--;
11484 } else {
11485 elements->set(i, current, write_barrier);
11486 break;
11487 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011488 }
11489 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011490 result = undefs;
11491 while (undefs < holes) {
11492 elements->set_undefined(undefs);
11493 undefs++;
11494 }
11495 while (holes < limit) {
11496 elements->set_the_hole(holes);
11497 holes++;
11498 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011499 }
11500
11501 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11502 return Smi::FromInt(static_cast<int>(result));
11503 }
11504 ASSERT_NE(NULL, result_double);
11505 result_double->set_value(static_cast<double>(result));
11506 return result_double;
11507}
11508
11509
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011510Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011511 uint8_t clamped_value = 0;
11512 if (index < static_cast<uint32_t>(length())) {
11513 if (value->IsSmi()) {
11514 int int_value = Smi::cast(value)->value();
11515 if (int_value < 0) {
11516 clamped_value = 0;
11517 } else if (int_value > 255) {
11518 clamped_value = 255;
11519 } else {
11520 clamped_value = static_cast<uint8_t>(int_value);
11521 }
11522 } else if (value->IsHeapNumber()) {
11523 double double_value = HeapNumber::cast(value)->value();
11524 if (!(double_value > 0)) {
11525 // NaN and less than zero clamp to zero.
11526 clamped_value = 0;
11527 } else if (double_value > 255) {
11528 // Greater than 255 clamp to 255.
11529 clamped_value = 255;
11530 } else {
11531 // Other doubles are rounded to the nearest integer.
11532 clamped_value = static_cast<uint8_t>(double_value + 0.5);
11533 }
11534 } else {
11535 // Clamp undefined to zero (default). All other types have been
11536 // converted to a number type further up in the call chain.
11537 ASSERT(value->IsUndefined());
11538 }
11539 set(index, clamped_value);
11540 }
11541 return Smi::FromInt(clamped_value);
11542}
11543
11544
ager@chromium.org3811b432009-10-28 14:53:37 +000011545template<typename ExternalArrayClass, typename ValueType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011546static MaybeObject* ExternalArrayIntSetter(Heap* heap,
11547 ExternalArrayClass* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000011548 uint32_t index,
11549 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011550 ValueType cast_value = 0;
11551 if (index < static_cast<uint32_t>(receiver->length())) {
11552 if (value->IsSmi()) {
11553 int int_value = Smi::cast(value)->value();
11554 cast_value = static_cast<ValueType>(int_value);
11555 } else if (value->IsHeapNumber()) {
11556 double double_value = HeapNumber::cast(value)->value();
11557 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
11558 } else {
11559 // Clamp undefined to zero (default). All other types have been
11560 // converted to a number type further up in the call chain.
11561 ASSERT(value->IsUndefined());
11562 }
11563 receiver->set(index, cast_value);
11564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011565 return heap->NumberFromInt32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011566}
11567
11568
lrn@chromium.org303ada72010-10-27 09:33:13 +000011569MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011570 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011571 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011572}
11573
11574
lrn@chromium.org303ada72010-10-27 09:33:13 +000011575MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
11576 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011577 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011578 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011579}
11580
11581
lrn@chromium.org303ada72010-10-27 09:33:13 +000011582MaybeObject* ExternalShortArray::SetValue(uint32_t index,
11583 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011584 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011585 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011586}
11587
11588
lrn@chromium.org303ada72010-10-27 09:33:13 +000011589MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
11590 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011591 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011592 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011593}
11594
11595
lrn@chromium.org303ada72010-10-27 09:33:13 +000011596MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011597 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011598 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011599}
11600
11601
lrn@chromium.org303ada72010-10-27 09:33:13 +000011602MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011603 uint32_t cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011604 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000011605 if (index < static_cast<uint32_t>(length())) {
11606 if (value->IsSmi()) {
11607 int int_value = Smi::cast(value)->value();
11608 cast_value = static_cast<uint32_t>(int_value);
11609 } else if (value->IsHeapNumber()) {
11610 double double_value = HeapNumber::cast(value)->value();
11611 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
11612 } else {
11613 // Clamp undefined to zero (default). All other types have been
11614 // converted to a number type further up in the call chain.
11615 ASSERT(value->IsUndefined());
11616 }
11617 set(index, cast_value);
11618 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011619 return heap->NumberFromUint32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011620}
11621
11622
lrn@chromium.org303ada72010-10-27 09:33:13 +000011623MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000011624 float cast_value = static_cast<float>(OS::nan_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000011626 if (index < static_cast<uint32_t>(length())) {
11627 if (value->IsSmi()) {
11628 int int_value = Smi::cast(value)->value();
11629 cast_value = static_cast<float>(int_value);
11630 } else if (value->IsHeapNumber()) {
11631 double double_value = HeapNumber::cast(value)->value();
11632 cast_value = static_cast<float>(double_value);
11633 } else {
yangguo@chromium.org56454712012-02-16 15:33:53 +000011634 // Clamp undefined to NaN (default). All other types have been
ager@chromium.org3811b432009-10-28 14:53:37 +000011635 // converted to a number type further up in the call chain.
11636 ASSERT(value->IsUndefined());
11637 }
11638 set(index, cast_value);
11639 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011640 return heap->AllocateHeapNumber(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011641}
11642
11643
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011644MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000011645 double double_value = OS::nan_value();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011646 Heap* heap = GetHeap();
11647 if (index < static_cast<uint32_t>(length())) {
11648 if (value->IsSmi()) {
11649 int int_value = Smi::cast(value)->value();
11650 double_value = static_cast<double>(int_value);
11651 } else if (value->IsHeapNumber()) {
11652 double_value = HeapNumber::cast(value)->value();
11653 } else {
yangguo@chromium.org56454712012-02-16 15:33:53 +000011654 // Clamp undefined to NaN (default). All other types have been
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011655 // converted to a number type further up in the call chain.
11656 ASSERT(value->IsUndefined());
11657 }
11658 set(index, double_value);
11659 }
11660 return heap->AllocateHeapNumber(double_value);
11661}
11662
11663
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011664JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011665 ASSERT(!HasFastProperties());
11666 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011667 return JSGlobalPropertyCell::cast(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011668}
11669
11670
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011671Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
11672 Handle<GlobalObject> global,
11673 Handle<String> name) {
11674 Isolate* isolate = global->GetIsolate();
11675 CALL_HEAP_FUNCTION(isolate,
11676 global->EnsurePropertyCell(*name),
11677 JSGlobalPropertyCell);
11678}
11679
11680
lrn@chromium.org303ada72010-10-27 09:33:13 +000011681MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011682 ASSERT(!HasFastProperties());
11683 int entry = property_dictionary()->FindEntry(name);
11684 if (entry == StringDictionary::kNotFound) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011685 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +000011686 Object* cell;
11687 { MaybeObject* maybe_cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011688 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011689 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
11690 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011691 PropertyDetails details(NONE, NORMAL);
11692 details = details.AsDeleted();
lrn@chromium.org303ada72010-10-27 09:33:13 +000011693 Object* dictionary;
11694 { MaybeObject* maybe_dictionary =
11695 property_dictionary()->Add(name, cell, details);
11696 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
11697 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011698 set_properties(StringDictionary::cast(dictionary));
11699 return cell;
11700 } else {
11701 Object* value = property_dictionary()->ValueAt(entry);
11702 ASSERT(value->IsJSGlobalPropertyCell());
11703 return value;
11704 }
11705}
11706
11707
lrn@chromium.org303ada72010-10-27 09:33:13 +000011708MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011709 SymbolKey key(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011710 return LookupKey(&key, s);
11711}
11712
11713
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011714// This class is used for looking up two character strings in the symbol table.
11715// If we don't have a hit we don't want to waste much time so we unroll the
11716// string hash calculation loop here for speed. Doesn't work if the two
11717// characters form a decimal integer, since such strings have a different hash
11718// algorithm.
11719class TwoCharHashTableKey : public HashTableKey {
11720 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011721 TwoCharHashTableKey(uint32_t c1, uint32_t c2, uint32_t seed)
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011722 : c1_(c1), c2_(c2) {
11723 // Char 1.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011724 uint32_t hash = seed;
11725 hash += c1;
11726 hash += hash << 10;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011727 hash ^= hash >> 6;
11728 // Char 2.
11729 hash += c2;
11730 hash += hash << 10;
11731 hash ^= hash >> 6;
11732 // GetHash.
11733 hash += hash << 3;
11734 hash ^= hash >> 11;
11735 hash += hash << 15;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011736 if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011737#ifdef DEBUG
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011738 StringHasher hasher(2, seed);
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011739 hasher.AddCharacter(c1);
11740 hasher.AddCharacter(c2);
11741 // If this assert fails then we failed to reproduce the two-character
11742 // version of the string hashing algorithm above. One reason could be
11743 // that we were passed two digits as characters, since the hash
11744 // algorithm is different in that case.
11745 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
11746#endif
11747 hash_ = hash;
11748 }
11749
11750 bool IsMatch(Object* o) {
11751 if (!o->IsString()) return false;
11752 String* other = String::cast(o);
11753 if (other->length() != 2) return false;
11754 if (other->Get(0) != c1_) return false;
11755 return other->Get(1) == c2_;
11756 }
11757
11758 uint32_t Hash() { return hash_; }
11759 uint32_t HashForObject(Object* key) {
11760 if (!key->IsString()) return 0;
11761 return String::cast(key)->Hash();
11762 }
11763
11764 Object* AsObject() {
11765 // The TwoCharHashTableKey is only used for looking in the symbol
11766 // table, not for adding to it.
11767 UNREACHABLE();
11768 return NULL;
11769 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011770
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011771 private:
11772 uint32_t c1_;
11773 uint32_t c2_;
11774 uint32_t hash_;
11775};
11776
11777
ager@chromium.org7c537e22008-10-16 08:43:32 +000011778bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
11779 SymbolKey key(string);
11780 int entry = FindEntry(&key);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011781 if (entry == kNotFound) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011782 return false;
11783 } else {
11784 String* result = String::cast(KeyAt(entry));
ager@chromium.org870a0b62008-11-04 11:43:05 +000011785 ASSERT(StringShape(result).IsSymbol());
ager@chromium.org7c537e22008-10-16 08:43:32 +000011786 *symbol = result;
11787 return true;
11788 }
11789}
11790
11791
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011792bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
11793 uint32_t c2,
11794 String** symbol) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011795 TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011796 int entry = FindEntry(&key);
11797 if (entry == kNotFound) {
11798 return false;
11799 } else {
11800 String* result = String::cast(KeyAt(entry));
11801 ASSERT(StringShape(result).IsSymbol());
11802 *symbol = result;
11803 return true;
11804 }
11805}
11806
11807
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011808MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str,
11809 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011810 Utf8SymbolKey key(str, GetHeap()->HashSeed());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011811 return LookupKey(&key, s);
11812}
11813
11814
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011815MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
11816 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011817 AsciiSymbolKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011818 return LookupKey(&key, s);
11819}
11820
11821
danno@chromium.org40cb8782011-05-25 07:58:50 +000011822MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
11823 int from,
11824 int length,
11825 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011826 SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
danno@chromium.org40cb8782011-05-25 07:58:50 +000011827 return LookupKey(&key, s);
11828}
11829
11830
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011831MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
11832 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011833 TwoByteSymbolKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011834 return LookupKey(&key, s);
11835}
11836
lrn@chromium.org303ada72010-10-27 09:33:13 +000011837MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011838 int entry = FindEntry(key);
11839
11840 // Symbol already in table.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011841 if (entry != kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011842 *s = KeyAt(entry);
11843 return this;
11844 }
11845
11846 // Adding new symbol. Grow table if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011847 Object* obj;
11848 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11849 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11850 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011851
11852 // Create symbol object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011853 Object* symbol;
11854 { MaybeObject* maybe_symbol = key->AsObject();
11855 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
11856 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011857
11858 // If the symbol table grew as part of EnsureCapacity, obj is not
11859 // the current symbol table and therefore we cannot use
11860 // SymbolTable::cast here.
11861 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
11862
11863 // Add the new symbol and return it along with the symbol table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011864 entry = table->FindInsertionEntry(key->Hash());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011865 table->set(EntryToIndex(entry), symbol);
11866 table->ElementAdded();
11867 *s = symbol;
11868 return table;
11869}
11870
11871
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011872Object* CompilationCacheTable::Lookup(String* src) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011873 StringKey key(src);
11874 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011875 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011876 return get(EntryToIndex(entry) + 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011877}
11878
11879
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011880Object* CompilationCacheTable::LookupEval(String* src,
11881 Context* context,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011882 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011883 int scope_position) {
11884 StringSharedKey key(src,
11885 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011886 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011887 scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011888 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011889 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.org381abbb2009-02-25 13:23:22 +000011890 return get(EntryToIndex(entry) + 1);
11891}
11892
11893
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011894Object* CompilationCacheTable::LookupRegExp(String* src,
11895 JSRegExp::Flags flags) {
11896 RegExpKey key(src, flags);
11897 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011898 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011899 return get(EntryToIndex(entry) + 1);
11900}
11901
11902
lrn@chromium.org303ada72010-10-27 09:33:13 +000011903MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011904 StringKey key(src);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011905 Object* obj;
11906 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11907 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11908 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011909
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011910 CompilationCacheTable* cache =
11911 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011912 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011913 cache->set(EntryToIndex(entry), src);
11914 cache->set(EntryToIndex(entry) + 1, value);
11915 cache->ElementAdded();
11916 return cache;
11917}
11918
11919
lrn@chromium.org303ada72010-10-27 09:33:13 +000011920MaybeObject* CompilationCacheTable::PutEval(String* src,
11921 Context* context,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011922 SharedFunctionInfo* value,
11923 int scope_position) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011924 StringSharedKey key(src,
11925 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011926 value->language_mode(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011927 scope_position);
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.org381abbb2009-02-25 13:23:22 +000011932
11933 CompilationCacheTable* cache =
11934 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011935 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org381abbb2009-02-25 13:23:22 +000011936
lrn@chromium.org303ada72010-10-27 09:33:13 +000011937 Object* k;
11938 { MaybeObject* maybe_k = key.AsObject();
11939 if (!maybe_k->ToObject(&k)) return maybe_k;
11940 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000011941
11942 cache->set(EntryToIndex(entry), k);
11943 cache->set(EntryToIndex(entry) + 1, value);
11944 cache->ElementAdded();
11945 return cache;
11946}
11947
11948
lrn@chromium.org303ada72010-10-27 09:33:13 +000011949MaybeObject* CompilationCacheTable::PutRegExp(String* src,
11950 JSRegExp::Flags flags,
11951 FixedArray* value) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011952 RegExpKey key(src, flags);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011953 Object* obj;
11954 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11955 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11956 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011957
11958 CompilationCacheTable* cache =
11959 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011960 int entry = cache->FindInsertionEntry(key.Hash());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000011961 // We store the value in the key slot, and compare the search key
11962 // to the stored value with a custon IsMatch function during lookups.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011963 cache->set(EntryToIndex(entry), value);
11964 cache->set(EntryToIndex(entry) + 1, value);
11965 cache->ElementAdded();
11966 return cache;
11967}
11968
11969
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011970void CompilationCacheTable::Remove(Object* value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011971 Object* the_hole_value = GetHeap()->the_hole_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011972 for (int entry = 0, size = Capacity(); entry < size; entry++) {
11973 int entry_index = EntryToIndex(entry);
11974 int value_index = entry_index + 1;
11975 if (get(value_index) == value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011976 NoWriteBarrierSet(this, entry_index, the_hole_value);
11977 NoWriteBarrierSet(this, value_index, the_hole_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011978 ElementRemoved();
11979 }
11980 }
11981 return;
11982}
11983
11984
ager@chromium.org236ad962008-09-25 09:45:57 +000011985// SymbolsKey used for HashTable where key is array of symbols.
11986class SymbolsKey : public HashTableKey {
11987 public:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011988 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
ager@chromium.org236ad962008-09-25 09:45:57 +000011989
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011990 bool IsMatch(Object* symbols) {
11991 FixedArray* o = FixedArray::cast(symbols);
ager@chromium.org236ad962008-09-25 09:45:57 +000011992 int len = symbols_->length();
11993 if (o->length() != len) return false;
11994 for (int i = 0; i < len; i++) {
11995 if (o->get(i) != symbols_->get(i)) return false;
11996 }
11997 return true;
11998 }
11999
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012000 uint32_t Hash() { return HashForObject(symbols_); }
ager@chromium.org236ad962008-09-25 09:45:57 +000012001
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012002 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012003 FixedArray* symbols = FixedArray::cast(obj);
12004 int len = symbols->length();
12005 uint32_t hash = 0;
ager@chromium.org236ad962008-09-25 09:45:57 +000012006 for (int i = 0; i < len; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012007 hash ^= String::cast(symbols->get(i))->Hash();
ager@chromium.org236ad962008-09-25 09:45:57 +000012008 }
12009 return hash;
12010 }
12011
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012012 Object* AsObject() { return symbols_; }
ager@chromium.org236ad962008-09-25 09:45:57 +000012013
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012014 private:
ager@chromium.org236ad962008-09-25 09:45:57 +000012015 FixedArray* symbols_;
12016};
12017
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012018
ager@chromium.org236ad962008-09-25 09:45:57 +000012019Object* MapCache::Lookup(FixedArray* array) {
12020 SymbolsKey key(array);
12021 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012022 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012023 return get(EntryToIndex(entry) + 1);
ager@chromium.org236ad962008-09-25 09:45:57 +000012024}
12025
12026
lrn@chromium.org303ada72010-10-27 09:33:13 +000012027MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
ager@chromium.org236ad962008-09-25 09:45:57 +000012028 SymbolsKey key(array);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012029 Object* obj;
12030 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
12031 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12032 }
ager@chromium.org236ad962008-09-25 09:45:57 +000012033
12034 MapCache* cache = reinterpret_cast<MapCache*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012035 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org236ad962008-09-25 09:45:57 +000012036 cache->set(EntryToIndex(entry), array);
12037 cache->set(EntryToIndex(entry) + 1, value);
12038 cache->ElementAdded();
12039 return cache;
12040}
12041
12042
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012043template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012044MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
12045 Object* obj;
12046 { MaybeObject* maybe_obj =
12047 HashTable<Shape, Key>::Allocate(at_least_space_for);
12048 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012049 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000012050 // Initialize the next enumeration index.
12051 Dictionary<Shape, Key>::cast(obj)->
12052 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012053 return obj;
12054}
12055
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012056
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012057template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012058MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012059 Heap* heap = Dictionary<Shape, Key>::GetHeap();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012060 int length = HashTable<Shape, Key>::NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012061
12062 // Allocate and initialize iteration order array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012063 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012064 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012065 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12066 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012067 FixedArray* iteration_order = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012068 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012069 iteration_order->set(i, Smi::FromInt(i));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012070 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012071
12072 // Allocate array with enumeration order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012073 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012074 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012076 FixedArray* enumeration_order = FixedArray::cast(obj);
12077
12078 // Fill the enumeration order array with property details.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012079 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012080 int pos = 0;
12081 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012082 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012083 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012084 }
12085 }
12086
12087 // Sort the arrays wrt. enumeration order.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012088 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012089
12090 // Overwrite the enumeration_order with the enumeration indices.
12091 for (int i = 0; i < length; i++) {
12092 int index = Smi::cast(iteration_order->get(i))->value();
12093 int enum_index = PropertyDetails::kInitialIndex + i;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012094 enumeration_order->set(index, Smi::FromInt(enum_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012095 }
12096
12097 // Update the dictionary with new indices.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012098 capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099 pos = 0;
12100 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012101 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012102 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
12103 PropertyDetails details = DetailsAt(i);
12104 PropertyDetails new_details =
12105 PropertyDetails(details.attributes(), details.type(), enum_index);
12106 DetailsAtPut(i, new_details);
12107 }
12108 }
12109
12110 // Set the next enumeration index.
12111 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
12112 return this;
12113}
12114
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012115template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012116MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012117 // Check whether there are enough enumeration indices to add n elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012118 if (Shape::kIsEnumerable &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012119 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
12120 // If not, we generate new indices for the properties.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012121 Object* result;
12122 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12123 if (!maybe_result->ToObject(&result)) return maybe_result;
12124 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012125 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012126 return HashTable<Shape, Key>::EnsureCapacity(n, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012127}
12128
12129
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012130template<typename Shape, typename Key>
12131Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012132 JSReceiver::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012133 Heap* heap = Dictionary<Shape, Key>::GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012134 PropertyDetails details = DetailsAt(entry);
ager@chromium.orge2902be2009-06-08 12:21:35 +000012135 // Ignore attributes if forcing a deletion.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012136 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012137 return heap->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +000012138 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012139 SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012140 HashTable<Shape, Key>::ElementRemoved();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012141 return heap->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012142}
12143
12144
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012145template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000012146MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
12147 return HashTable<Shape, Key>::Shrink(key);
12148}
12149
12150
12151template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012152MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012153 int entry = this->FindEntry(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012154
12155 // If the entry is present set the value;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012156 if (entry != Dictionary<Shape, Key>::kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012157 ValueAtPut(entry, value);
12158 return this;
12159 }
12160
12161 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012162 Object* obj;
12163 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12164 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12165 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012166
lrn@chromium.org303ada72010-10-27 09:33:13 +000012167 Object* k;
12168 { MaybeObject* maybe_k = Shape::AsObject(key);
12169 if (!maybe_k->ToObject(&k)) return maybe_k;
12170 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012171 PropertyDetails details = PropertyDetails(NONE, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012172
12173 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12174 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012175}
12176
12177
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012178template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012179MaybeObject* Dictionary<Shape, Key>::Add(Key key,
12180 Object* value,
12181 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012182 // Valdate key is absent.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012183 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184 // 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 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012189
12190 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12191 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012192}
12193
12194
12195// Add a key, value pair to the dictionary.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012196template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012197MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
12198 Object* value,
12199 PropertyDetails details,
12200 uint32_t hash) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012201 // Compute the key object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012202 Object* k;
12203 { MaybeObject* maybe_k = Shape::AsObject(key);
12204 if (!maybe_k->ToObject(&k)) return maybe_k;
12205 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012206
12207 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012208 // Insert element at empty or deleted entry
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012209 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012210 // Assign an enumeration index to the property and update
12211 // SetNextEnumerationIndex.
12212 int index = NextEnumerationIndex();
12213 details = PropertyDetails(details.attributes(), details.type(), index);
12214 SetNextEnumerationIndex(index + 1);
12215 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012216 SetEntry(entry, k, value, details);
12217 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
12218 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
12219 HashTable<Shape, Key>::ElementAdded();
12220 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012221}
12222
12223
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012224void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012225 // If the dictionary requires slow elements an element has already
12226 // been added at a high index.
12227 if (requires_slow_elements()) return;
12228 // Check if this index is high enough that we should require slow
12229 // elements.
12230 if (key > kRequiresSlowElementsLimit) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012231 set_requires_slow_elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232 return;
12233 }
12234 // Update max key value.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012235 Object* max_index_object = get(kMaxNumberKeyIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012236 if (!max_index_object->IsSmi() || max_number_key() < key) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012237 FixedArray::set(kMaxNumberKeyIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012238 Smi::FromInt(key << kRequiresSlowElementsTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012239 }
12240}
12241
12242
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012243MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
12244 Object* value,
12245 PropertyDetails details) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012246 UpdateMaxNumberKey(key);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012247 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012248 return Add(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012249}
12250
12251
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012252MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
12253 Object* value) {
12254 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
12255 return Add(key, value, PropertyDetails(NONE, NORMAL));
12256}
12257
12258
12259MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012260 UpdateMaxNumberKey(key);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012261 return AtPut(key, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012262}
12263
12264
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012265MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
12266 Object* value) {
12267 return AtPut(key, value);
12268}
12269
12270
12271Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
12272 Handle<SeededNumberDictionary> dictionary,
12273 uint32_t index,
12274 Handle<Object> value,
12275 PropertyDetails details) {
12276 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12277 dictionary->Set(index, *value, details),
12278 SeededNumberDictionary);
12279}
12280
12281
12282Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
12283 Handle<UnseededNumberDictionary> dictionary,
12284 uint32_t index,
12285 Handle<Object> value) {
12286 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12287 dictionary->Set(index, *value),
12288 UnseededNumberDictionary);
12289}
12290
12291
12292MaybeObject* SeededNumberDictionary::Set(uint32_t key,
12293 Object* value,
12294 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012295 int entry = FindEntry(key);
12296 if (entry == kNotFound) return AddNumberEntry(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012297 // Preserve enumeration index.
12298 details = PropertyDetails(details.attributes(),
12299 details.type(),
12300 DetailsAt(entry).index());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012301 MaybeObject* maybe_object_key = SeededNumberDictionaryShape::AsObject(key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012302 Object* object_key;
12303 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000012304 SetEntry(entry, object_key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012305 return this;
12306}
12307
12308
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012309MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
12310 Object* value) {
12311 int entry = FindEntry(key);
12312 if (entry == kNotFound) return AddNumberEntry(key, value);
12313 MaybeObject* maybe_object_key = UnseededNumberDictionaryShape::AsObject(key);
12314 Object* object_key;
12315 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
12316 SetEntry(entry, object_key, value);
12317 return this;
12318}
12319
12320
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012321
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012322template<typename Shape, typename Key>
12323int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
12324 PropertyAttributes filter) {
12325 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012326 int result = 0;
12327 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012328 Object* k = HashTable<Shape, Key>::KeyAt(i);
12329 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012330 PropertyDetails details = DetailsAt(i);
12331 if (details.IsDeleted()) continue;
12332 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012333 if ((attr & filter) == 0) result++;
12334 }
12335 }
12336 return result;
12337}
12338
12339
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012340template<typename Shape, typename Key>
12341int Dictionary<Shape, Key>::NumberOfEnumElements() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012342 return NumberOfElementsFilterAttributes(
12343 static_cast<PropertyAttributes>(DONT_ENUM));
12344}
12345
12346
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012347template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012348void Dictionary<Shape, Key>::CopyKeysTo(
12349 FixedArray* storage,
12350 PropertyAttributes filter,
12351 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012352 ASSERT(storage->length() >= NumberOfEnumElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012353 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012354 int index = 0;
12355 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012356 Object* k = HashTable<Shape, Key>::KeyAt(i);
12357 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012358 PropertyDetails details = DetailsAt(i);
12359 if (details.IsDeleted()) continue;
12360 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012361 if ((attr & filter) == 0) storage->set(index++, k);
12362 }
12363 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012364 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12365 storage->SortPairs(storage, index);
12366 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012367 ASSERT(storage->length() >= index);
12368}
12369
12370
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012371void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
12372 FixedArray* sort_array) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012373 ASSERT(storage->length() >= NumberOfEnumElements());
12374 int capacity = Capacity();
12375 int index = 0;
12376 for (int i = 0; i < capacity; i++) {
12377 Object* k = KeyAt(i);
12378 if (IsKey(k)) {
12379 PropertyDetails details = DetailsAt(i);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012380 if (details.IsDeleted() || details.IsDontEnum()) continue;
12381 storage->set(index, k);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012382 sort_array->set(index, Smi::FromInt(details.index()));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012383 index++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012384 }
12385 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012386 storage->SortPairs(sort_array, sort_array->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012387 ASSERT(storage->length() >= index);
12388}
12389
12390
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012391template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012392void Dictionary<Shape, Key>::CopyKeysTo(
12393 FixedArray* storage,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012394 int index,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012395 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012396 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
12397 static_cast<PropertyAttributes>(NONE)));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012398 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012399 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012400 Object* k = HashTable<Shape, Key>::KeyAt(i);
12401 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012402 PropertyDetails details = DetailsAt(i);
12403 if (details.IsDeleted()) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012404 storage->set(index++, k);
12405 }
12406 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012407 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12408 storage->SortPairs(storage, index);
12409 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012410 ASSERT(storage->length() >= index);
12411}
12412
12413
12414// Backwards lookup (slow).
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012415template<typename Shape, typename Key>
12416Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
12417 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012418 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012419 Object* k = HashTable<Shape, Key>::KeyAt(i);
12420 if (Dictionary<Shape, Key>::IsKey(k)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012421 Object* e = ValueAt(i);
12422 if (e->IsJSGlobalPropertyCell()) {
12423 e = JSGlobalPropertyCell::cast(e)->value();
12424 }
12425 if (e == value) return k;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012426 }
12427 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012428 Heap* heap = Dictionary<Shape, Key>::GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012429 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012430}
12431
12432
lrn@chromium.org303ada72010-10-27 09:33:13 +000012433MaybeObject* StringDictionary::TransformPropertiesToFastFor(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012434 JSObject* obj, int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012435 // Make sure we preserve dictionary representation if there are too many
12436 // descriptors.
12437 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
12438
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012439 MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12440 if (maybe_result->IsFailure()) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012441
12442 int instance_descriptor_length = 0;
12443 int number_of_fields = 0;
12444
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012445 Heap* heap = GetHeap();
12446
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012447 // Compute the length of the instance descriptor.
12448 int capacity = Capacity();
12449 for (int i = 0; i < capacity; i++) {
12450 Object* k = KeyAt(i);
12451 if (IsKey(k)) {
12452 Object* value = ValueAt(i);
12453 PropertyType type = DetailsAt(i).type();
12454 ASSERT(type != FIELD);
12455 instance_descriptor_length++;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000012456 if (type == NORMAL &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012457 (!value->IsJSFunction() || heap->InNewSpace(value))) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000012458 number_of_fields += 1;
12459 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012460 }
12461 }
12462
12463 // Allocate the instance descriptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012464 DescriptorArray* descriptors;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012465 MaybeObject* maybe_descriptors =
12466 DescriptorArray::Allocate(instance_descriptor_length,
12467 DescriptorArray::MAY_BE_SHARED);
12468 if (!maybe_descriptors->To(&descriptors)) {
12469 return maybe_descriptors;
lrn@chromium.org303ada72010-10-27 09:33:13 +000012470 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012471
yangguo@chromium.org99aa4902012-07-06 16:21:55 +000012472 FixedArray::WhitenessWitness witness(descriptors);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012473
ager@chromium.org32912102009-01-16 10:38:43 +000012474 int inobject_props = obj->map()->inobject_properties();
12475 int number_of_allocated_fields =
12476 number_of_fields + unused_property_fields - inobject_props;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000012477 if (number_of_allocated_fields < 0) {
12478 // There is enough inobject space for all fields (including unused).
12479 number_of_allocated_fields = 0;
12480 unused_property_fields = inobject_props - number_of_fields;
12481 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012482
12483 // Allocate the fixed array for the fields.
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012484 FixedArray* fields;
12485 MaybeObject* maybe_fields =
12486 heap->AllocateFixedArray(number_of_allocated_fields);
12487 if (!maybe_fields->To(&fields)) return maybe_fields;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012488
12489 // Fill in the instance descriptor and the fields.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012490 int next_descriptor = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012491 int current_offset = 0;
12492 for (int i = 0; i < capacity; i++) {
12493 Object* k = KeyAt(i);
12494 if (IsKey(k)) {
12495 Object* value = ValueAt(i);
12496 // Ensure the key is a symbol before writing into the instance descriptor.
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012497 String* key;
12498 MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
12499 if (!maybe_key->To(&key)) return maybe_key;
12500
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012501 PropertyDetails details = DetailsAt(i);
12502 PropertyType type = details.type();
ager@chromium.org32912102009-01-16 10:38:43 +000012503
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012504 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012505 ConstantFunctionDescriptor d(key,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012506 JSFunction::cast(value),
12507 details.attributes(),
12508 details.index());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000012509 descriptors->Set(next_descriptor, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012510 } else if (type == NORMAL) {
ager@chromium.org32912102009-01-16 10:38:43 +000012511 if (current_offset < inobject_props) {
12512 obj->InObjectPropertyAtPut(current_offset,
12513 value,
12514 UPDATE_WRITE_BARRIER);
12515 } else {
12516 int offset = current_offset - inobject_props;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012517 fields->set(offset, value);
ager@chromium.org32912102009-01-16 10:38:43 +000012518 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012519 FieldDescriptor d(key,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012520 current_offset++,
12521 details.attributes(),
12522 details.index());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000012523 descriptors->Set(next_descriptor, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012524 } else if (type == CALLBACKS) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012525 CallbacksDescriptor d(key,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012526 value,
12527 details.attributes(),
12528 details.index());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000012529 descriptors->Set(next_descriptor, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012530 } else {
12531 UNREACHABLE();
12532 }
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000012533 ++next_descriptor;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012534 }
12535 }
12536 ASSERT(current_offset == number_of_fields);
12537
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012538 descriptors->Sort(witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012539 // Allocate new map.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000012540 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012541 MaybeObject* maybe_new_map =
12542 obj->map()->CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION);
12543 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012544
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000012545 new_map->set_unused_property_fields(unused_property_fields);
12546
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012547 // Transform the object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000012548 obj->set_map(new_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012549
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012550 obj->set_properties(fields);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012551 ASSERT(obj->IsJSObject());
12552
ager@chromium.org32912102009-01-16 10:38:43 +000012553 // Check that it really works.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012554 ASSERT(obj->HasFastProperties());
ager@chromium.org32912102009-01-16 10:38:43 +000012555
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012556 return obj;
12557}
12558
12559
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012560bool ObjectHashSet::Contains(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012561 ASSERT(IsKey(key));
12562
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012563 // 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 +000012564 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12565 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
12566 }
12567 return (FindEntry(key) != kNotFound);
12568}
12569
12570
12571MaybeObject* ObjectHashSet::Add(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012572 ASSERT(IsKey(key));
12573
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012574 // Make sure the key object has an identity hash code.
12575 int hash;
12576 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12577 if (maybe_hash->IsFailure()) return maybe_hash;
12578 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12579 }
12580 int entry = FindEntry(key);
12581
12582 // Check whether key is already present.
12583 if (entry != kNotFound) return this;
12584
12585 // Check whether the hash set should be extended and add entry.
12586 Object* obj;
12587 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12588 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12589 }
12590 ObjectHashSet* table = ObjectHashSet::cast(obj);
12591 entry = table->FindInsertionEntry(hash);
12592 table->set(EntryToIndex(entry), key);
12593 table->ElementAdded();
12594 return table;
12595}
12596
12597
12598MaybeObject* ObjectHashSet::Remove(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012599 ASSERT(IsKey(key));
12600
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012601 // If the object does not have an identity hash, it was never used as a key.
12602 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12603 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
12604 }
12605 int entry = FindEntry(key);
12606
12607 // Check whether key is actually present.
12608 if (entry == kNotFound) return this;
12609
12610 // Remove entry and try to shrink this hash set.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012611 set_the_hole(EntryToIndex(entry));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012612 ElementRemoved();
12613 return Shrink(key);
12614}
12615
12616
12617Object* ObjectHashTable::Lookup(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012618 ASSERT(IsKey(key));
12619
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012620 // If the object does not have an identity hash, it was never used as a key.
12621 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12622 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000012623 return GetHeap()->the_hole_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012624 }
12625 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012626 int entry = FindEntry(key);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000012627 if (entry == kNotFound) return GetHeap()->the_hole_value();
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012628 return get(EntryToIndex(entry) + 1);
12629}
12630
12631
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012632MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012633 ASSERT(IsKey(key));
12634
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012635 // Make sure the key object has an identity hash code.
12636 int hash;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012637 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012638 if (maybe_hash->IsFailure()) return maybe_hash;
12639 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12640 }
12641 int entry = FindEntry(key);
12642
12643 // Check whether to perform removal operation.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000012644 if (value->IsTheHole()) {
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012645 if (entry == kNotFound) return this;
12646 RemoveEntry(entry);
12647 return Shrink(key);
12648 }
12649
12650 // Key is already in table, just overwrite value.
12651 if (entry != kNotFound) {
12652 set(EntryToIndex(entry) + 1, value);
12653 return this;
12654 }
12655
12656 // Check whether the hash table should be extended.
12657 Object* obj;
12658 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12659 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12660 }
12661 ObjectHashTable* table = ObjectHashTable::cast(obj);
12662 table->AddEntry(table->FindInsertionEntry(hash), key, value);
12663 return table;
12664}
12665
12666
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012667void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012668 set(EntryToIndex(entry), key);
12669 set(EntryToIndex(entry) + 1, value);
12670 ElementAdded();
12671}
12672
12673
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012674void ObjectHashTable::RemoveEntry(int entry) {
12675 set_the_hole(EntryToIndex(entry));
12676 set_the_hole(EntryToIndex(entry) + 1);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012677 ElementRemoved();
12678}
12679
12680
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012681#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012682// Check if there is a break point at this code position.
12683bool DebugInfo::HasBreakPoint(int code_position) {
12684 // Get the break point info object for this code position.
12685 Object* break_point_info = GetBreakPointInfo(code_position);
12686
12687 // If there is no break point info object or no break points in the break
12688 // point info object there is no break point at this code position.
12689 if (break_point_info->IsUndefined()) return false;
12690 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
12691}
12692
12693
12694// Get the break point info object for this code position.
12695Object* DebugInfo::GetBreakPointInfo(int code_position) {
12696 // Find the index of the break point info object for this code position.
12697 int index = GetBreakPointInfoIndex(code_position);
12698
12699 // Return the break point info object if any.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012700 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012701 return BreakPointInfo::cast(break_points()->get(index));
12702}
12703
12704
12705// Clear a break point at the specified code position.
12706void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
12707 int code_position,
12708 Handle<Object> break_point_object) {
12709 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12710 if (break_point_info->IsUndefined()) return;
12711 BreakPointInfo::ClearBreakPoint(
12712 Handle<BreakPointInfo>::cast(break_point_info),
12713 break_point_object);
12714}
12715
12716
12717void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
12718 int code_position,
12719 int source_position,
12720 int statement_position,
12721 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012722 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012723 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12724 if (!break_point_info->IsUndefined()) {
12725 BreakPointInfo::SetBreakPoint(
12726 Handle<BreakPointInfo>::cast(break_point_info),
12727 break_point_object);
12728 return;
12729 }
12730
12731 // Adding a new break point for a code position which did not have any
12732 // break points before. Try to find a free slot.
12733 int index = kNoBreakPointInfo;
12734 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12735 if (debug_info->break_points()->get(i)->IsUndefined()) {
12736 index = i;
12737 break;
12738 }
12739 }
12740 if (index == kNoBreakPointInfo) {
12741 // No free slot - extend break point info array.
12742 Handle<FixedArray> old_break_points =
12743 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012744 Handle<FixedArray> new_break_points =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012745 isolate->factory()->NewFixedArray(
12746 old_break_points->length() +
12747 Debug::kEstimatedNofBreakPointsInFunction);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000012748
12749 debug_info->set_break_points(*new_break_points);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012750 for (int i = 0; i < old_break_points->length(); i++) {
12751 new_break_points->set(i, old_break_points->get(i));
12752 }
12753 index = old_break_points->length();
12754 }
12755 ASSERT(index != kNoBreakPointInfo);
12756
12757 // Allocate new BreakPointInfo object and set the break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012758 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
12759 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012760 new_break_point_info->set_code_position(Smi::FromInt(code_position));
12761 new_break_point_info->set_source_position(Smi::FromInt(source_position));
12762 new_break_point_info->
12763 set_statement_position(Smi::FromInt(statement_position));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012764 new_break_point_info->set_break_point_objects(
12765 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012766 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
12767 debug_info->break_points()->set(index, *new_break_point_info);
12768}
12769
12770
12771// Get the break point objects for a code position.
12772Object* DebugInfo::GetBreakPointObjects(int code_position) {
12773 Object* break_point_info = GetBreakPointInfo(code_position);
12774 if (break_point_info->IsUndefined()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012775 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012776 }
12777 return BreakPointInfo::cast(break_point_info)->break_point_objects();
12778}
12779
12780
12781// Get the total number of break points.
12782int DebugInfo::GetBreakPointCount() {
12783 if (break_points()->IsUndefined()) return 0;
12784 int count = 0;
12785 for (int i = 0; i < break_points()->length(); i++) {
12786 if (!break_points()->get(i)->IsUndefined()) {
12787 BreakPointInfo* break_point_info =
12788 BreakPointInfo::cast(break_points()->get(i));
12789 count += break_point_info->GetBreakPointCount();
12790 }
12791 }
12792 return count;
12793}
12794
12795
12796Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
12797 Handle<Object> break_point_object) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012798 Heap* heap = debug_info->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012799 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012800 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12801 if (!debug_info->break_points()->get(i)->IsUndefined()) {
12802 Handle<BreakPointInfo> break_point_info =
12803 Handle<BreakPointInfo>(BreakPointInfo::cast(
12804 debug_info->break_points()->get(i)));
12805 if (BreakPointInfo::HasBreakPointObject(break_point_info,
12806 break_point_object)) {
12807 return *break_point_info;
12808 }
12809 }
12810 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012811 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012812}
12813
12814
12815// Find the index of the break point info object for the specified code
12816// position.
12817int DebugInfo::GetBreakPointInfoIndex(int code_position) {
12818 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
12819 for (int i = 0; i < break_points()->length(); i++) {
12820 if (!break_points()->get(i)->IsUndefined()) {
12821 BreakPointInfo* break_point_info =
12822 BreakPointInfo::cast(break_points()->get(i));
12823 if (break_point_info->code_position()->value() == code_position) {
12824 return i;
12825 }
12826 }
12827 }
12828 return kNoBreakPointInfo;
12829}
12830
12831
12832// Remove the specified break point object.
12833void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
12834 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012835 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012836 // If there are no break points just ignore.
12837 if (break_point_info->break_point_objects()->IsUndefined()) return;
12838 // If there is a single break point clear it if it is the same.
12839 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12840 if (break_point_info->break_point_objects() == *break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012841 break_point_info->set_break_point_objects(
12842 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012843 }
12844 return;
12845 }
12846 // If there are multiple break points shrink the array
12847 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
12848 Handle<FixedArray> old_array =
12849 Handle<FixedArray>(
12850 FixedArray::cast(break_point_info->break_point_objects()));
12851 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012852 isolate->factory()->NewFixedArray(old_array->length() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012853 int found_count = 0;
12854 for (int i = 0; i < old_array->length(); i++) {
12855 if (old_array->get(i) == *break_point_object) {
12856 ASSERT(found_count == 0);
12857 found_count++;
12858 } else {
12859 new_array->set(i - found_count, old_array->get(i));
12860 }
12861 }
12862 // If the break point was found in the list change it.
12863 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
12864}
12865
12866
12867// Add the specified break point object.
12868void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
12869 Handle<Object> break_point_object) {
12870 // If there was no break point objects before just set it.
12871 if (break_point_info->break_point_objects()->IsUndefined()) {
12872 break_point_info->set_break_point_objects(*break_point_object);
12873 return;
12874 }
12875 // If the break point object is the same as before just ignore.
12876 if (break_point_info->break_point_objects() == *break_point_object) return;
12877 // If there was one break point object before replace with array.
12878 if (!break_point_info->break_point_objects()->IsFixedArray()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012879 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012880 array->set(0, break_point_info->break_point_objects());
12881 array->set(1, *break_point_object);
12882 break_point_info->set_break_point_objects(*array);
12883 return;
12884 }
12885 // If there was more than one break point before extend array.
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 FACTORY->NewFixedArray(old_array->length() + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012891 for (int i = 0; i < old_array->length(); i++) {
12892 // If the break point was there before just ignore.
12893 if (old_array->get(i) == *break_point_object) return;
12894 new_array->set(i, old_array->get(i));
12895 }
12896 // Add the new break point.
12897 new_array->set(old_array->length(), *break_point_object);
12898 break_point_info->set_break_point_objects(*new_array);
12899}
12900
12901
12902bool BreakPointInfo::HasBreakPointObject(
12903 Handle<BreakPointInfo> break_point_info,
12904 Handle<Object> break_point_object) {
12905 // No break point.
12906 if (break_point_info->break_point_objects()->IsUndefined()) return false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012907 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012908 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12909 return break_point_info->break_point_objects() == *break_point_object;
12910 }
12911 // Multiple break points.
12912 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
12913 for (int i = 0; i < array->length(); i++) {
12914 if (array->get(i) == *break_point_object) {
12915 return true;
12916 }
12917 }
12918 return false;
12919}
12920
12921
12922// Get the number of break points.
12923int BreakPointInfo::GetBreakPointCount() {
12924 // No break point.
12925 if (break_point_objects()->IsUndefined()) return 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012926 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012927 if (!break_point_objects()->IsFixedArray()) return 1;
12928 // Multiple break points.
12929 return FixedArray::cast(break_point_objects())->length();
12930}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000012931#endif // ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012932
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012933
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000012934Object* JSDate::GetField(Object* object, Smi* index) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000012935 return JSDate::cast(object)->DoGetField(
12936 static_cast<FieldIndex>(index->value()));
12937}
12938
12939
12940Object* JSDate::DoGetField(FieldIndex index) {
12941 ASSERT(index != kDateValue);
12942
12943 DateCache* date_cache = GetIsolate()->date_cache();
12944
12945 if (index < kFirstUncachedField) {
12946 Object* stamp = cache_stamp();
12947 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
12948 // Since the stamp is not NaN, the value is also not NaN.
12949 int64_t local_time_ms =
12950 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
12951 SetLocalFields(local_time_ms, date_cache);
12952 }
12953 switch (index) {
12954 case kYear: return year();
12955 case kMonth: return month();
12956 case kDay: return day();
12957 case kWeekday: return weekday();
12958 case kHour: return hour();
12959 case kMinute: return min();
12960 case kSecond: return sec();
12961 default: UNREACHABLE();
12962 }
12963 }
12964
12965 if (index >= kFirstUTCField) {
12966 return GetUTCField(index, value()->Number(), date_cache);
12967 }
12968
12969 double time = value()->Number();
12970 if (isnan(time)) return GetIsolate()->heap()->nan_value();
12971
12972 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
12973 int days = DateCache::DaysFromTime(local_time_ms);
12974
12975 if (index == kDays) return Smi::FromInt(days);
12976
12977 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
12978 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
12979 ASSERT(index == kTimeInDay);
12980 return Smi::FromInt(time_in_day_ms);
12981}
12982
12983
12984Object* JSDate::GetUTCField(FieldIndex index,
12985 double value,
12986 DateCache* date_cache) {
12987 ASSERT(index >= kFirstUTCField);
12988
12989 if (isnan(value)) return GetIsolate()->heap()->nan_value();
12990
12991 int64_t time_ms = static_cast<int64_t>(value);
12992
12993 if (index == kTimezoneOffset) {
12994 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
12995 }
12996
12997 int days = DateCache::DaysFromTime(time_ms);
12998
12999 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
13000
13001 if (index <= kDayUTC) {
13002 int year, month, day;
13003 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
13004 if (index == kYearUTC) return Smi::FromInt(year);
13005 if (index == kMonthUTC) return Smi::FromInt(month);
13006 ASSERT(index == kDayUTC);
13007 return Smi::FromInt(day);
13008 }
13009
13010 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
13011 switch (index) {
13012 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
13013 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
13014 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
13015 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
13016 case kDaysUTC: return Smi::FromInt(days);
13017 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
13018 default: UNREACHABLE();
13019 }
13020
13021 UNREACHABLE();
13022 return NULL;
13023}
13024
13025
13026void JSDate::SetValue(Object* value, bool is_value_nan) {
13027 set_value(value);
13028 if (is_value_nan) {
13029 HeapNumber* nan = GetIsolate()->heap()->nan_value();
13030 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
13031 set_year(nan, SKIP_WRITE_BARRIER);
13032 set_month(nan, SKIP_WRITE_BARRIER);
13033 set_day(nan, SKIP_WRITE_BARRIER);
13034 set_hour(nan, SKIP_WRITE_BARRIER);
13035 set_min(nan, SKIP_WRITE_BARRIER);
13036 set_sec(nan, SKIP_WRITE_BARRIER);
13037 set_weekday(nan, SKIP_WRITE_BARRIER);
13038 } else {
13039 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
13040 }
13041}
13042
13043
13044void JSDate::SetLocalFields(int64_t local_time_ms, DateCache* date_cache) {
13045 int days = DateCache::DaysFromTime(local_time_ms);
13046 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
13047 int year, month, day;
13048 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
13049 int weekday = date_cache->Weekday(days);
13050 int hour = time_in_day_ms / (60 * 60 * 1000);
13051 int min = (time_in_day_ms / (60 * 1000)) % 60;
13052 int sec = (time_in_day_ms / 1000) % 60;
13053 set_cache_stamp(date_cache->stamp());
13054 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
13055 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
13056 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
13057 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
13058 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
13059 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
13060 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
13061}
13062
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013063} } // namespace v8::internal