blob: 6185e2dcf049484646a37600c1f944222e18b4b9 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "execution.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "full-codegen.h"
38#include "hydrogen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include "objects-inl.h"
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000040#include "objects-visiting.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "macro-assembler.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "safepoint-table.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000043#include "scanner-base.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "string-stream.h"
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000045#include "utils.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000046#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047
mads.s.ager31e71382008-08-13 09:32:07 +000048#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +000049#include "disasm.h"
mads.s.ager31e71382008-08-13 09:32:07 +000050#include "disassembler.h"
51#endif
52
kasperl@chromium.org71affb52009-05-26 05:44:31 +000053namespace v8 {
54namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056// Getters and setters are stored in a fixed array property. These are
57// constants for their indices.
58const int kGetterIndex = 0;
59const int kSetterIndex = 1;
60
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000061uint64_t FixedDoubleArray::kHoleNanInt64 = -1;
62uint64_t FixedDoubleArray::kCanonicalNonHoleNanLower32 = 0x7FF00000;
63uint64_t FixedDoubleArray::kCanonicalNonHoleNanInt64 =
64 kCanonicalNonHoleNanLower32 << 32;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
lrn@chromium.org303ada72010-10-27 09:33:13 +000066MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
67 Object* value) {
68 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000069 { MaybeObject* maybe_result =
70 constructor->GetHeap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +000071 if (!maybe_result->ToObject(&result)) return maybe_result;
72 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073 JSValue::cast(result)->set_value(value);
74 return result;
75}
76
77
lrn@chromium.org303ada72010-10-27 09:33:13 +000078MaybeObject* Object::ToObject(Context* global_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 if (IsNumber()) {
80 return CreateJSValue(global_context->number_function(), this);
81 } else if (IsBoolean()) {
82 return CreateJSValue(global_context->boolean_function(), this);
83 } else if (IsString()) {
84 return CreateJSValue(global_context->string_function(), this);
85 }
86 ASSERT(IsJSObject());
87 return this;
88}
89
90
lrn@chromium.org303ada72010-10-27 09:33:13 +000091MaybeObject* Object::ToObject() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000092 if (IsJSObject()) {
93 return this;
94 } else if (IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000095 Isolate* isolate = Isolate::Current();
96 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097 return CreateJSValue(global_context->number_function(), this);
98 } else if (IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000099 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
100 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101 return CreateJSValue(global_context->boolean_function(), this);
102 } else if (IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000103 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
104 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105 return CreateJSValue(global_context->string_function(), this);
106 }
107
108 // Throw a type error.
109 return Failure::InternalError();
110}
111
112
113Object* Object::ToBoolean() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 if (IsTrue()) return this;
115 if (IsFalse()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000116 if (IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000117 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000118 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000119 HeapObject* heap_object = HeapObject::cast(this);
120 if (heap_object->IsUndefined() || heap_object->IsNull()) {
121 return heap_object->GetHeap()->false_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000122 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123 // Undetectable object is false
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000124 if (heap_object->IsUndetectableObject()) {
125 return heap_object->GetHeap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000127 if (heap_object->IsString()) {
128 return heap_object->GetHeap()->ToBoolean(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000129 String::cast(this)->length() != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000130 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000131 if (heap_object->IsHeapNumber()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132 return HeapNumber::cast(this)->HeapNumberToBoolean();
133 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000134 return heap_object->GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000135}
136
137
138void Object::Lookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000139 Object* holder = NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000140 if (IsSmi()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000141 Context* global_context = Isolate::Current()->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142 holder = global_context->number_function()->instance_prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000143 } else {
144 HeapObject* heap_object = HeapObject::cast(this);
145 if (heap_object->IsJSObject()) {
146 return JSObject::cast(this)->Lookup(name, result);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000147 } else if (heap_object->IsJSProxy()) {
148 return result->HandlerResult();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000149 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000150 Context* global_context = Isolate::Current()->context()->global_context();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000151 if (heap_object->IsString()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000152 holder = global_context->string_function()->instance_prototype();
153 } else if (heap_object->IsHeapNumber()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000154 holder = global_context->number_function()->instance_prototype();
155 } else if (heap_object->IsBoolean()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000156 holder = global_context->boolean_function()->instance_prototype();
157 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000159 ASSERT(holder != NULL); // Cannot handle null or undefined.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000160 JSObject::cast(holder)->Lookup(name, result);
161}
162
163
lrn@chromium.org303ada72010-10-27 09:33:13 +0000164MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
165 String* name,
166 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000167 LookupResult result;
168 Lookup(name, &result);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000170 ASSERT(*attributes <= ABSENT);
171 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172}
173
174
lrn@chromium.org303ada72010-10-27 09:33:13 +0000175MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
176 Object* structure,
177 String* name,
178 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000179 Isolate* isolate = name->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000180 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000181 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000182 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000183 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000184 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000185 reinterpret_cast<AccessorDescriptor*>(
186 Foreign::cast(structure)->address());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000187 MaybeObject* value = (callback->getter)(receiver, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000188 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189 return value;
190 }
191
192 // api style callbacks.
193 if (structure->IsAccessorInfo()) {
194 AccessorInfo* data = AccessorInfo::cast(structure);
195 Object* fun_obj = data->getter();
196 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
197 HandleScope scope;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000198 JSObject* self = JSObject::cast(receiver);
199 JSObject* holder_handle = JSObject::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000200 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000201 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
202 CustomArguments args(isolate, data->data(), self, holder_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000203 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204 v8::Handle<v8::Value> result;
205 {
206 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000207 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000208 result = call_fun(v8::Utils::ToLocal(key), info);
209 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000210 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
211 if (result.IsEmpty()) {
212 return isolate->heap()->undefined_value();
213 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214 return *v8::Utils::OpenHandle(*result);
215 }
216
217 // __defineGetter__ callback
218 if (structure->IsFixedArray()) {
219 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
220 if (getter->IsJSFunction()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000221 return Object::GetPropertyWithDefinedGetter(receiver,
222 JSFunction::cast(getter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000223 }
224 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000225 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000226 }
227
228 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000229 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230}
231
232
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000233MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw,
234 String* name_raw,
235 Object* handler_raw) {
236 Isolate* isolate = name_raw->GetIsolate();
237 HandleScope scope;
238 Handle<Object> receiver(receiver_raw);
239 Handle<Object> name(name_raw);
240 Handle<Object> handler(handler_raw);
241
242 // Extract trap function.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000243 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("get");
244 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
245 if (trap->IsUndefined()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000246 // Get the derived `get' property.
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000247 trap = isolate->derived_get_trap();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000248 }
249
250 // Call trap function.
251 Object** args[] = { receiver.location(), name.location() };
252 bool has_exception;
253 Handle<Object> result =
254 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
255 if (has_exception) return Failure::Exception();
256
257 return *result;
258}
259
260
lrn@chromium.org303ada72010-10-27 09:33:13 +0000261MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
262 JSFunction* getter) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000263 HandleScope scope;
264 Handle<JSFunction> fun(JSFunction::cast(getter));
265 Handle<Object> self(receiver);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000266#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000267 Debug* debug = fun->GetHeap()->isolate()->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000268 // Handle stepping into a getter if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000269 if (debug->StepInActive()) {
270 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000271 }
272#endif
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000273 bool has_pending_exception;
274 Handle<Object> result =
275 Execution::Call(fun, self, 0, NULL, &has_pending_exception);
276 // Check for pending exception and return the result.
277 if (has_pending_exception) return Failure::Exception();
278 return *result;
279}
280
281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000282// Only deal with CALLBACKS and INTERCEPTOR
lrn@chromium.org303ada72010-10-27 09:33:13 +0000283MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
ager@chromium.org8bb60582008-12-11 12:02:20 +0000284 Object* receiver,
285 LookupResult* result,
286 String* name,
287 PropertyAttributes* attributes) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000288 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000289 switch (result->type()) {
290 case CALLBACKS: {
291 // Only allow API accessors.
292 Object* obj = result->GetCallbackObject();
293 if (obj->IsAccessorInfo()) {
294 AccessorInfo* info = AccessorInfo::cast(obj);
295 if (info->all_can_read()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000296 *attributes = result->GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297 return GetPropertyWithCallback(receiver,
298 result->GetCallbackObject(),
299 name,
300 result->holder());
301 }
302 }
303 break;
304 }
305 case NORMAL:
306 case FIELD:
307 case CONSTANT_FUNCTION: {
308 // Search ALL_CAN_READ accessors in prototype chain.
309 LookupResult r;
310 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000311 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000312 return GetPropertyWithFailedAccessCheck(receiver,
313 &r,
314 name,
315 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 }
317 break;
318 }
319 case INTERCEPTOR: {
320 // If the object has an interceptor, try real named properties.
321 // No access check in GetPropertyAttributeWithInterceptor.
322 LookupResult r;
323 result->holder()->LookupRealNamedProperty(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000324 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000325 return GetPropertyWithFailedAccessCheck(receiver,
326 &r,
327 name,
328 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000329 }
ager@chromium.org9ed6c322010-02-19 12:24:05 +0000330 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000332 default:
333 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334 }
335 }
336
ager@chromium.org8bb60582008-12-11 12:02:20 +0000337 // No accessible property found.
338 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000339 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
341 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000342}
343
344
ager@chromium.org870a0b62008-11-04 11:43:05 +0000345PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
346 Object* receiver,
347 LookupResult* result,
348 String* name,
349 bool continue_search) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000350 if (result->IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000351 switch (result->type()) {
352 case CALLBACKS: {
353 // Only allow API accessors.
354 Object* obj = result->GetCallbackObject();
355 if (obj->IsAccessorInfo()) {
356 AccessorInfo* info = AccessorInfo::cast(obj);
357 if (info->all_can_read()) {
358 return result->GetAttributes();
359 }
360 }
361 break;
362 }
363
364 case NORMAL:
365 case FIELD:
366 case CONSTANT_FUNCTION: {
367 if (!continue_search) break;
368 // Search ALL_CAN_READ accessors in prototype chain.
369 LookupResult r;
370 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000371 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000372 return GetPropertyAttributeWithFailedAccessCheck(receiver,
373 &r,
374 name,
375 continue_search);
376 }
377 break;
378 }
379
380 case INTERCEPTOR: {
381 // If the object has an interceptor, try real named properties.
382 // No access check in GetPropertyAttributeWithInterceptor.
383 LookupResult r;
384 if (continue_search) {
385 result->holder()->LookupRealNamedProperty(name, &r);
386 } else {
387 result->holder()->LocalLookupRealNamedProperty(name, &r);
388 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000389 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000390 return GetPropertyAttributeWithFailedAccessCheck(receiver,
391 &r,
392 name,
393 continue_search);
394 }
395 break;
396 }
397
ager@chromium.org5c838252010-02-19 08:53:10 +0000398 default:
399 UNREACHABLE();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000400 }
401 }
402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000403 GetHeap()->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000404 return ABSENT;
405}
406
407
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000408Object* JSObject::GetNormalizedProperty(LookupResult* result) {
409 ASSERT(!HasFastProperties());
410 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
411 if (IsGlobalObject()) {
412 value = JSGlobalPropertyCell::cast(value)->value();
413 }
414 ASSERT(!value->IsJSGlobalPropertyCell());
415 return value;
416}
417
418
419Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
420 ASSERT(!HasFastProperties());
421 if (IsGlobalObject()) {
422 JSGlobalPropertyCell* cell =
423 JSGlobalPropertyCell::cast(
424 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
425 cell->set_value(value);
426 } else {
427 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
428 }
429 return value;
430}
431
432
lrn@chromium.org303ada72010-10-27 09:33:13 +0000433MaybeObject* JSObject::SetNormalizedProperty(String* name,
434 Object* value,
435 PropertyDetails details) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000436 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000437 int entry = property_dictionary()->FindEntry(name);
438 if (entry == StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000439 Object* store_value = value;
440 if (IsGlobalObject()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000441 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000442 MaybeObject* maybe_store_value =
443 heap->AllocateJSGlobalPropertyCell(value);
444 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000445 }
lrn@chromium.org303ada72010-10-27 09:33:13 +0000446 Object* dict;
447 { MaybeObject* maybe_dict =
448 property_dictionary()->Add(name, store_value, details);
449 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
450 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000451 set_properties(StringDictionary::cast(dict));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000452 return value;
453 }
454 // Preserve enumeration index.
455 details = PropertyDetails(details.attributes(),
456 details.type(),
457 property_dictionary()->DetailsAt(entry).index());
458 if (IsGlobalObject()) {
459 JSGlobalPropertyCell* cell =
460 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
461 cell->set_value(value);
462 // Please note we have to update the property details.
463 property_dictionary()->DetailsAtPut(entry, details);
464 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000465 property_dictionary()->SetEntry(entry, name, value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000466 }
467 return value;
468}
469
470
lrn@chromium.org303ada72010-10-27 09:33:13 +0000471MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000472 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000473 StringDictionary* dictionary = property_dictionary();
474 int entry = dictionary->FindEntry(name);
475 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000476 // If we have a global object set the cell to the hole.
477 if (IsGlobalObject()) {
478 PropertyDetails details = dictionary->DetailsAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000479 if (details.IsDontDelete()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000480 if (mode != FORCE_DELETION) return GetHeap()->false_value();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000481 // When forced to delete global properties, we have to make a
482 // map change to invalidate any ICs that think they can load
483 // from the DontDelete cell without checking if it contains
484 // the hole value.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000485 Object* new_map;
486 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
487 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
488 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000489 set_map(Map::cast(new_map));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000490 }
491 JSGlobalPropertyCell* cell =
492 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000493 cell->set_value(cell->heap()->the_hole_value());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000494 dictionary->DetailsAtPut(entry, details.AsDeleted());
495 } else {
496 return dictionary->DeleteProperty(entry, mode);
497 }
498 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000499 return GetHeap()->true_value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000500}
501
502
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000503bool JSObject::IsDirty() {
504 Object* cons_obj = map()->constructor();
505 if (!cons_obj->IsJSFunction())
506 return true;
507 JSFunction* fun = JSFunction::cast(cons_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000508 if (!fun->shared()->IsApiFunction())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000509 return true;
510 // If the object is fully fast case and has the same map it was
511 // created with then no changes can have been made to it.
512 return map() != fun->initial_map()
513 || !HasFastElements()
514 || !HasFastProperties();
515}
516
517
lrn@chromium.org303ada72010-10-27 09:33:13 +0000518MaybeObject* Object::GetProperty(Object* receiver,
519 LookupResult* result,
520 String* name,
521 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522 // Make sure that the top context does not change when doing
523 // callbacks or interceptor calls.
524 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 Heap* heap = name->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526
527 // Traverse the prototype chain from the current object (this) to
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000528 // the holder and check for access rights. This avoids traversing the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529 // objects more than once in case of interceptors, because the
530 // holder will always be the interceptor holder and the search may
531 // only continue with a current object just after the interceptor
532 // holder in the prototype chain.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000533 // Proxy handlers do not use the proxy's prototype, so we can skip this.
534 if (!result->IsHandler()) {
535 Object* last = result->IsProperty() ? result->holder() : heap->null_value();
536 ASSERT(this != this->GetPrototype());
537 for (Object* current = this; true; current = current->GetPrototype()) {
538 if (current->IsAccessCheckNeeded()) {
539 // Check if we're allowed to read from the current object. Note
540 // that even though we may not actually end up loading the named
541 // property from the current object, we still check that we have
542 // access to it.
543 JSObject* checked = JSObject::cast(current);
544 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
545 return checked->GetPropertyWithFailedAccessCheck(receiver,
546 result,
547 name,
548 attributes);
549 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000551 // Stop traversing the chain once we reach the last object in the
552 // chain; either the holder of the result or null in case of an
553 // absent property.
554 if (current == last) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000555 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000556 }
557
kasper.lund44510672008-07-25 07:37:58 +0000558 if (!result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 *attributes = ABSENT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000561 }
562 *attributes = result->GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563 Object* value;
564 JSObject* holder = result->holder();
565 switch (result->type()) {
566 case NORMAL:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000567 value = holder->GetNormalizedProperty(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570 case FIELD:
ager@chromium.org7c537e22008-10-16 08:43:32 +0000571 value = holder->FastPropertyAt(result->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000573 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574 case CONSTANT_FUNCTION:
575 return result->GetConstantFunction();
576 case CALLBACKS:
577 return GetPropertyWithCallback(receiver,
578 result->GetCallbackObject(),
579 name,
580 holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000581 case HANDLER: {
582 JSProxy* proxy = JSProxy::cast(this);
583 return GetPropertyWithHandler(receiver, name, proxy->handler());
584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585 case INTERCEPTOR: {
586 JSObject* recvr = JSObject::cast(receiver);
587 return holder->GetPropertyWithInterceptor(recvr, name, attributes);
588 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000589 case MAP_TRANSITION:
590 case EXTERNAL_ARRAY_TRANSITION:
591 case CONSTANT_TRANSITION:
592 case NULL_DESCRIPTOR:
593 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000594 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000595 UNREACHABLE();
596 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597}
598
599
lrn@chromium.org303ada72010-10-27 09:33:13 +0000600MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000601 Object* holder = NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000602 if (IsSmi()) {
603 Context* global_context = Isolate::Current()->context()->global_context();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000604 holder = global_context->number_function()->instance_prototype();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000605 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000606 HeapObject* heap_object = HeapObject::cast(this);
607
608 if (heap_object->IsJSObject()) {
609 return JSObject::cast(this)->GetElementWithReceiver(receiver, index);
610 }
611 Heap* heap = heap_object->GetHeap();
612 Isolate* isolate = heap->isolate();
613
614 Context* global_context = isolate->context()->global_context();
615 if (heap_object->IsString()) {
616 holder = global_context->string_function()->instance_prototype();
617 } else if (heap_object->IsHeapNumber()) {
618 holder = global_context->number_function()->instance_prototype();
619 } else if (heap_object->IsBoolean()) {
620 holder = global_context->boolean_function()->instance_prototype();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000621 } else if (heap_object->IsJSProxy()) {
622 return heap->undefined_value(); // For now...
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000623 } else {
624 // Undefined and null have no indexed properties.
625 ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
626 return heap->undefined_value();
627 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000628 }
629
630 return JSObject::cast(holder)->GetElementWithReceiver(receiver, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631}
632
633
634Object* Object::GetPrototype() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000635 if (IsSmi()) {
636 Heap* heap = Isolate::Current()->heap();
637 Context* context = heap->isolate()->context()->global_context();
638 return context->number_function()->instance_prototype();
639 }
640
641 HeapObject* heap_object = HeapObject::cast(this);
642
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000643 // The object is either a number, a string, a boolean,
644 // a real JS object, or a Harmony proxy.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000645 if (heap_object->IsJSReceiver()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000646 return heap_object->map()->prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000647 }
648 Heap* heap = heap_object->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000649 Context* context = heap->isolate()->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000651 if (heap_object->IsHeapNumber()) {
652 return context->number_function()->instance_prototype();
653 }
654 if (heap_object->IsString()) {
655 return context->string_function()->instance_prototype();
656 }
657 if (heap_object->IsBoolean()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000658 return context->boolean_function()->instance_prototype();
659 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 return heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000661 }
662}
663
664
whesse@chromium.org023421e2010-12-21 12:19:12 +0000665void Object::ShortPrint(FILE* out) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000666 HeapStringAllocator allocator;
667 StringStream accumulator(&allocator);
668 ShortPrint(&accumulator);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000669 accumulator.OutputToFile(out);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670}
671
672
673void Object::ShortPrint(StringStream* accumulator) {
674 if (IsSmi()) {
675 Smi::cast(this)->SmiPrint(accumulator);
676 } else if (IsFailure()) {
677 Failure::cast(this)->FailurePrint(accumulator);
678 } else {
679 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
680 }
681}
682
683
whesse@chromium.org023421e2010-12-21 12:19:12 +0000684void Smi::SmiPrint(FILE* out) {
685 PrintF(out, "%d", value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686}
687
688
689void Smi::SmiPrint(StringStream* accumulator) {
690 accumulator->Add("%d", value());
691}
692
693
694void Failure::FailurePrint(StringStream* accumulator) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000695 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696}
697
698
whesse@chromium.org023421e2010-12-21 12:19:12 +0000699void Failure::FailurePrint(FILE* out) {
700 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000701}
702
703
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704// Should a word be prefixed by 'a' or 'an' in order to read naturally in
705// English? Returns false for non-ASCII or words that don't start with
706// a capital letter. The a/an rule follows pronunciation in English.
707// We don't use the BBC's overcorrect "an historic occasion" though if
708// you speak a dialect you may well say "an 'istoric occasion".
709static bool AnWord(String* str) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000710 if (str->length() == 0) return false; // A nothing.
711 int c0 = str->Get(0);
712 int c1 = str->length() > 1 ? str->Get(1) : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000713 if (c0 == 'U') {
714 if (c1 > 'Z') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000715 return true; // An Umpire, but a UTF8String, a U.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000716 }
717 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000718 return true; // An Ape, an ABCBook.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
720 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
721 c0 == 'S' || c0 == 'X')) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000722 return true; // An MP3File, an M.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000723 }
724 return false;
725}
726
727
lrn@chromium.org303ada72010-10-27 09:33:13 +0000728MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000729#ifdef DEBUG
730 // Do not attempt to flatten in debug mode when allocation is not
731 // allowed. This is to avoid an assertion failure when allocating.
732 // Flattening strings is the only case where we always allow
733 // allocation because no GC is performed if the allocation fails.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000734 if (!HEAP->IsAllocationAllowed()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735#endif
736
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000737 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000738 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739 case kConsStringTag: {
740 ConsString* cs = ConsString::cast(this);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000741 if (cs->second()->length() == 0) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000742 return cs->first();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743 }
744 // There's little point in putting the flat string in new space if the
745 // cons string is in old space. It can never get GCed until there is
746 // an old space GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000747 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000748 int len = length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000749 Object* object;
750 String* result;
ager@chromium.org5ec48922009-05-05 07:25:34 +0000751 if (IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000752 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000753 if (!maybe_object->ToObject(&object)) return maybe_object;
754 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000755 result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000756 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000757 int first_length = first->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000758 char* dest = SeqAsciiString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000759 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000760 String* second = cs->second();
761 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000762 dest + first_length,
763 0,
764 len - first_length);
765 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000766 { MaybeObject* maybe_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000767 heap->AllocateRawTwoByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000768 if (!maybe_object->ToObject(&object)) return maybe_object;
769 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000770 result = String::cast(object);
771 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000772 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000773 int first_length = first->length();
774 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000775 String* second = cs->second();
776 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000777 dest + first_length,
778 0,
779 len - first_length);
780 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000781 cs->set_first(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000782 cs->set_second(heap->empty_string());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000783 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000784 }
785 default:
786 return this;
787 }
788}
789
790
ager@chromium.org6f10e412009-02-13 10:11:16 +0000791bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000792 // Externalizing twice leaks the external resource, so it's
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000793 // prohibited by the API.
794 ASSERT(!this->IsExternalString());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000795#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +0000796 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000797 // Assert that the resource and the string are equivalent.
798 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000799 ScopedVector<uc16> smart_chars(this->length());
800 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
801 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +0000802 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000803 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000804 }
805#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000806 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000807 int size = this->Size(); // Byte size of the original string.
808 if (size < ExternalString::kSize) {
809 // The string is too small to fit an external String in its place. This can
810 // only happen for zero length strings.
811 return false;
812 }
813 ASSERT(size >= ExternalString::kSize);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000814 bool is_ascii = this->IsAsciiRepresentation();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000815 bool is_symbol = this->IsSymbol();
816 int length = this->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000817 int hash_field = this->hash_field();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000818
819 // Morph the object to an external string by adjusting the map and
820 // reinitializing the fields.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000821 this->set_map(is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000822 heap->external_string_with_ascii_data_map() :
823 heap->external_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000824 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
825 self->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000826 self->set_hash_field(hash_field);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000827 self->set_resource(resource);
828 // Additionally make the object into an external symbol if the original string
829 // was a symbol to start with.
830 if (is_symbol) {
831 self->Hash(); // Force regeneration of the hash value.
832 // Now morph this external string into a external symbol.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000833 this->set_map(is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000834 heap->external_symbol_with_ascii_data_map() :
835 heap->external_symbol_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000836 }
837
838 // Fill the remainder of the string with dead wood.
839 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000840 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000841 return true;
842}
843
844
845bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
846#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +0000847 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000848 // Assert that the resource and the string are equivalent.
849 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000850 ScopedVector<char> smart_chars(this->length());
851 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
852 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +0000853 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000854 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000855 }
856#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000857 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000858 int size = this->Size(); // Byte size of the original string.
859 if (size < ExternalString::kSize) {
860 // The string is too small to fit an external String in its place. This can
861 // only happen for zero length strings.
862 return false;
863 }
864 ASSERT(size >= ExternalString::kSize);
865 bool is_symbol = this->IsSymbol();
866 int length = this->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000867 int hash_field = this->hash_field();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000868
869 // Morph the object to an external string by adjusting the map and
870 // reinitializing the fields.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000871 this->set_map(heap->external_ascii_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000872 ExternalAsciiString* self = ExternalAsciiString::cast(this);
873 self->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000874 self->set_hash_field(hash_field);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000875 self->set_resource(resource);
876 // Additionally make the object into an external symbol if the original string
877 // was a symbol to start with.
878 if (is_symbol) {
879 self->Hash(); // Force regeneration of the hash value.
880 // Now morph this external string into a external symbol.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000881 this->set_map(heap->external_ascii_symbol_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000882 }
883
884 // Fill the remainder of the string with dead wood.
885 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000886 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000887 return true;
888}
889
890
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891void String::StringShortPrint(StringStream* accumulator) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000892 int len = length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000893 if (len > kMaxShortPrintLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894 accumulator->Add("<Very long string[%u]>", len);
895 return;
896 }
897
898 if (!LooksValid()) {
899 accumulator->Add("<Invalid String>");
900 return;
901 }
902
903 StringInputBuffer buf(this);
904
905 bool truncated = false;
kasper.lund7276f142008-07-30 08:49:36 +0000906 if (len > kMaxShortPrintLength) {
907 len = kMaxShortPrintLength;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000908 truncated = true;
909 }
910 bool ascii = true;
911 for (int i = 0; i < len; i++) {
912 int c = buf.GetNext();
913
914 if (c < 32 || c >= 127) {
915 ascii = false;
916 }
917 }
918 buf.Reset(this);
919 if (ascii) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000920 accumulator->Add("<String[%u]: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000921 for (int i = 0; i < len; i++) {
922 accumulator->Put(buf.GetNext());
923 }
924 accumulator->Put('>');
925 } else {
926 // Backslash indicates that the string contains control
927 // characters and that backslashes are therefore escaped.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000928 accumulator->Add("<String[%u]\\: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000929 for (int i = 0; i < len; i++) {
930 int c = buf.GetNext();
931 if (c == '\n') {
932 accumulator->Add("\\n");
933 } else if (c == '\r') {
934 accumulator->Add("\\r");
935 } else if (c == '\\') {
936 accumulator->Add("\\\\");
937 } else if (c < 32 || c > 126) {
938 accumulator->Add("\\x%02x", c);
939 } else {
940 accumulator->Put(c);
941 }
942 }
943 if (truncated) {
944 accumulator->Put('.');
945 accumulator->Put('.');
946 accumulator->Put('.');
947 }
948 accumulator->Put('>');
949 }
950 return;
951}
952
953
954void JSObject::JSObjectShortPrint(StringStream* accumulator) {
955 switch (map()->instance_type()) {
956 case JS_ARRAY_TYPE: {
957 double length = JSArray::cast(this)->length()->Number();
958 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
959 break;
960 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000961 case JS_REGEXP_TYPE: {
962 accumulator->Add("<JS RegExp>");
963 break;
964 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000965 case JS_FUNCTION_TYPE: {
966 Object* fun_name = JSFunction::cast(this)->shared()->name();
967 bool printed = false;
968 if (fun_name->IsString()) {
969 String* str = String::cast(fun_name);
970 if (str->length() > 0) {
971 accumulator->Add("<JS Function ");
972 accumulator->Put(str);
973 accumulator->Put('>');
974 printed = true;
975 }
976 }
977 if (!printed) {
978 accumulator->Add("<JS Function>");
979 }
980 break;
981 }
982 // All other JSObjects are rather similar to each other (JSObject,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000983 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984 default: {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000985 Map* map_of_this = map();
986 Heap* heap = map_of_this->heap();
987 Object* constructor = map_of_this->constructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 bool printed = false;
989 if (constructor->IsHeapObject() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 !heap->Contains(HeapObject::cast(constructor))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
992 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000993 bool global_object = IsJSGlobalProxy();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994 if (constructor->IsJSFunction()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000995 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
997 } else {
998 Object* constructor_name =
999 JSFunction::cast(constructor)->shared()->name();
1000 if (constructor_name->IsString()) {
1001 String* str = String::cast(constructor_name);
1002 if (str->length() > 0) {
1003 bool vowel = AnWord(str);
1004 accumulator->Add("<%sa%s ",
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001005 global_object ? "Global Object: " : "",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006 vowel ? "n" : "");
1007 accumulator->Put(str);
1008 accumulator->Put('>');
1009 printed = true;
1010 }
1011 }
1012 }
1013 }
1014 if (!printed) {
1015 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1016 }
1017 }
1018 if (IsJSValue()) {
1019 accumulator->Add(" value = ");
1020 JSValue::cast(this)->value()->ShortPrint(accumulator);
1021 }
1022 accumulator->Put('>');
1023 break;
1024 }
1025 }
1026}
1027
1028
1029void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 // if (!HEAP->InNewSpace(this)) PrintF("*", this);
1031 Heap* heap = GetHeap();
1032 if (!heap->Contains(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033 accumulator->Add("!!!INVALID POINTER!!!");
1034 return;
1035 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001036 if (!heap->Contains(map())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001037 accumulator->Add("!!!INVALID MAP!!!");
1038 return;
1039 }
1040
1041 accumulator->Add("%p ", this);
1042
1043 if (IsString()) {
1044 String::cast(this)->StringShortPrint(accumulator);
1045 return;
1046 }
1047 if (IsJSObject()) {
1048 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1049 return;
1050 }
1051 switch (map()->instance_type()) {
1052 case MAP_TYPE:
1053 accumulator->Add("<Map>");
1054 break;
1055 case FIXED_ARRAY_TYPE:
1056 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1057 break;
1058 case BYTE_ARRAY_TYPE:
1059 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1060 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001061 case EXTERNAL_PIXEL_ARRAY_TYPE:
1062 accumulator->Add("<ExternalPixelArray[%u]>",
1063 ExternalPixelArray::cast(this)->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001064 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00001065 case EXTERNAL_BYTE_ARRAY_TYPE:
1066 accumulator->Add("<ExternalByteArray[%u]>",
1067 ExternalByteArray::cast(this)->length());
1068 break;
1069 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1070 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1071 ExternalUnsignedByteArray::cast(this)->length());
1072 break;
1073 case EXTERNAL_SHORT_ARRAY_TYPE:
1074 accumulator->Add("<ExternalShortArray[%u]>",
1075 ExternalShortArray::cast(this)->length());
1076 break;
1077 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1078 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1079 ExternalUnsignedShortArray::cast(this)->length());
1080 break;
1081 case EXTERNAL_INT_ARRAY_TYPE:
1082 accumulator->Add("<ExternalIntArray[%u]>",
1083 ExternalIntArray::cast(this)->length());
1084 break;
1085 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1086 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1087 ExternalUnsignedIntArray::cast(this)->length());
1088 break;
1089 case EXTERNAL_FLOAT_ARRAY_TYPE:
1090 accumulator->Add("<ExternalFloatArray[%u]>",
1091 ExternalFloatArray::cast(this)->length());
1092 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001093 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1094 accumulator->Add("<ExternalDoubleArray[%u]>",
1095 ExternalDoubleArray::cast(this)->length());
1096 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001097 case SHARED_FUNCTION_INFO_TYPE:
1098 accumulator->Add("<SharedFunctionInfo>");
1099 break;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001100 case JS_MESSAGE_OBJECT_TYPE:
1101 accumulator->Add("<JSMessageObject>");
1102 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103#define MAKE_STRUCT_CASE(NAME, Name, name) \
1104 case NAME##_TYPE: \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001105 accumulator->Put('<'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106 accumulator->Add(#Name); \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001107 accumulator->Put('>'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001108 break;
1109 STRUCT_LIST(MAKE_STRUCT_CASE)
1110#undef MAKE_STRUCT_CASE
1111 case CODE_TYPE:
1112 accumulator->Add("<Code>");
1113 break;
1114 case ODDBALL_TYPE: {
1115 if (IsUndefined())
1116 accumulator->Add("<undefined>");
1117 else if (IsTheHole())
1118 accumulator->Add("<the hole>");
1119 else if (IsNull())
1120 accumulator->Add("<null>");
1121 else if (IsTrue())
1122 accumulator->Add("<true>");
1123 else if (IsFalse())
1124 accumulator->Add("<false>");
1125 else
1126 accumulator->Add("<Odd Oddball>");
1127 break;
1128 }
1129 case HEAP_NUMBER_TYPE:
1130 accumulator->Add("<Number: ");
1131 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1132 accumulator->Put('>');
1133 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001134 case FOREIGN_TYPE:
1135 accumulator->Add("<Foreign>");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001136 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001137 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1138 accumulator->Add("Cell for ");
1139 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1140 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141 default:
1142 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1143 break;
1144 }
1145}
1146
1147
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148void HeapObject::Iterate(ObjectVisitor* v) {
1149 // Handle header
1150 IteratePointer(v, kMapOffset);
1151 // Handle object body
1152 Map* m = map();
1153 IterateBody(m->instance_type(), SizeFromMap(m), v);
1154}
1155
1156
1157void HeapObject::IterateBody(InstanceType type, int object_size,
1158 ObjectVisitor* v) {
1159 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1160 // During GC, the map pointer field is encoded.
1161 if (type < FIRST_NONSTRING_TYPE) {
1162 switch (type & kStringRepresentationMask) {
1163 case kSeqStringTag:
1164 break;
1165 case kConsStringTag:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001166 ConsString::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001168 case kExternalStringTag:
1169 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1170 reinterpret_cast<ExternalAsciiString*>(this)->
1171 ExternalAsciiStringIterateBody(v);
1172 } else {
1173 reinterpret_cast<ExternalTwoByteString*>(this)->
1174 ExternalTwoByteStringIterateBody(v);
1175 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176 break;
1177 }
1178 return;
1179 }
1180
1181 switch (type) {
1182 case FIXED_ARRAY_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001183 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001185 case FIXED_DOUBLE_ARRAY_TYPE:
1186 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001187 case JS_OBJECT_TYPE:
ager@chromium.org32912102009-01-16 10:38:43 +00001188 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 case JS_VALUE_TYPE:
1190 case JS_ARRAY_TYPE:
ager@chromium.org236ad962008-09-25 09:45:57 +00001191 case JS_REGEXP_TYPE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001192 case JS_GLOBAL_PROXY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 case JS_GLOBAL_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001194 case JS_BUILTINS_OBJECT_TYPE:
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001195 case JS_MESSAGE_OBJECT_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001196 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 break;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001198 case JS_FUNCTION_TYPE:
1199 reinterpret_cast<JSFunction*>(this)
1200 ->JSFunctionIterateBody(object_size, v);
1201 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202 case ODDBALL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001203 Oddball::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204 break;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001205 case JS_PROXY_TYPE:
1206 JSProxy::BodyDescriptor::IterateBody(this, v);
1207 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001208 case FOREIGN_TYPE:
1209 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001210 break;
1211 case MAP_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001212 Map::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213 break;
1214 case CODE_TYPE:
1215 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1216 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001217 case JS_GLOBAL_PROPERTY_CELL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001218 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001219 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220 case HEAP_NUMBER_TYPE:
1221 case FILLER_TYPE:
1222 case BYTE_ARRAY_TYPE:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001223 case EXTERNAL_PIXEL_ARRAY_TYPE:
ager@chromium.org3811b432009-10-28 14:53:37 +00001224 case EXTERNAL_BYTE_ARRAY_TYPE:
1225 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1226 case EXTERNAL_SHORT_ARRAY_TYPE:
1227 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1228 case EXTERNAL_INT_ARRAY_TYPE:
1229 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1230 case EXTERNAL_FLOAT_ARRAY_TYPE:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001231 case EXTERNAL_DOUBLE_ARRAY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001233 case SHARED_FUNCTION_INFO_TYPE:
1234 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001235 break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001236
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237#define MAKE_STRUCT_CASE(NAME, Name, name) \
1238 case NAME##_TYPE:
1239 STRUCT_LIST(MAKE_STRUCT_CASE)
1240#undef MAKE_STRUCT_CASE
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001241 StructBodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242 break;
1243 default:
1244 PrintF("Unknown type: %d\n", type);
1245 UNREACHABLE();
1246 }
1247}
1248
1249
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001250Object* HeapNumber::HeapNumberToBoolean() {
1251 // NaN, +0, and -0 should return the false object
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001252#if __BYTE_ORDER == __LITTLE_ENDIAN
1253 union IeeeDoubleLittleEndianArchType u;
1254#elif __BYTE_ORDER == __BIG_ENDIAN
1255 union IeeeDoubleBigEndianArchType u;
1256#endif
1257 u.d = value();
1258 if (u.bits.exp == 2047) {
1259 // Detect NaN for IEEE double precision floating point.
1260 if ((u.bits.man_low | u.bits.man_high) != 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 return GetHeap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001263 if (u.bits.exp == 0) {
1264 // Detect +0, and -0 for IEEE double precision floating point.
1265 if ((u.bits.man_low | u.bits.man_high) == 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001266 return GetHeap()->false_value();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001267 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001268 return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269}
1270
1271
whesse@chromium.org023421e2010-12-21 12:19:12 +00001272void HeapNumber::HeapNumberPrint(FILE* out) {
1273 PrintF(out, "%.16g", Number());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274}
1275
1276
1277void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1278 // The Windows version of vsnprintf can allocate when printing a %g string
1279 // into a buffer that may not be big enough. We don't want random memory
1280 // allocation when producing post-crash stack traces, so we print into a
1281 // buffer that is plenty big enough for any floating point number, then
1282 // print that using vsnprintf (which may truncate but never allocate if
1283 // there is no more space in the buffer).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001284 EmbeddedVector<char, 100> buffer;
1285 OS::SNPrintF(buffer, "%.16g", Number());
1286 accumulator->Add("%s", buffer.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287}
1288
1289
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001290String* JSReceiver::class_name() {
1291 if (IsJSFunction() && IsJSFunctionProxy()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001292 return GetHeap()->function_class_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001293 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 if (map()->constructor()->IsJSFunction()) {
1295 JSFunction* constructor = JSFunction::cast(map()->constructor());
1296 return String::cast(constructor->shared()->instance_class_name());
1297 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001298 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001299 return GetHeap()->Object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300}
1301
1302
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001303String* JSReceiver::constructor_name() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001304 if (map()->constructor()->IsJSFunction()) {
1305 JSFunction* constructor = JSFunction::cast(map()->constructor());
1306 String* name = String::cast(constructor->shared()->name());
vegorov@chromium.org42841962010-10-18 11:18:59 +00001307 if (name->length() > 0) return name;
1308 String* inferred_name = constructor->shared()->inferred_name();
1309 if (inferred_name->length() > 0) return inferred_name;
1310 Object* proto = GetPrototype();
1311 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001312 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001313 // TODO(rossberg): what about proxies?
ager@chromium.orga1645e22009-09-09 19:27:10 +00001314 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001315 return GetHeap()->Object_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001316}
1317
1318
lrn@chromium.org303ada72010-10-27 09:33:13 +00001319MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1320 String* name,
1321 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001322 int index = new_map->PropertyIndexFor(name);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001323 if (map()->unused_property_fields() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324 ASSERT(map()->unused_property_fields() == 0);
1325 int new_unused = new_map->unused_property_fields();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001326 Object* values;
1327 { MaybeObject* maybe_values =
1328 properties()->CopySize(properties()->length() + new_unused + 1);
1329 if (!maybe_values->ToObject(&values)) return maybe_values;
1330 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331 set_properties(FixedArray::cast(values));
1332 }
1333 set_map(new_map);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001334 return FastPropertyAtPut(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335}
1336
1337
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001338static bool IsIdentifier(UnicodeCache* cache,
1339 unibrow::CharacterStream* buffer) {
1340 // Checks whether the buffer contains an identifier (no escape).
1341 if (!buffer->has_more()) return false;
1342 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1343 return false;
1344 }
1345 while (buffer->has_more()) {
1346 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1347 return false;
1348 }
1349 }
1350 return true;
1351}
1352
1353
lrn@chromium.org303ada72010-10-27 09:33:13 +00001354MaybeObject* JSObject::AddFastProperty(String* name,
1355 Object* value,
1356 PropertyAttributes attributes) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001357 ASSERT(!IsJSGlobalProxy());
1358
ager@chromium.org8c51fc92009-04-22 11:54:55 +00001359 // Normalize the object if the name is an actual string (not the
1360 // hidden symbols) and is not a real identifier.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001361 Isolate* isolate = GetHeap()->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001362 StringInputBuffer buffer(name);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001363 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001364 && name != isolate->heap()->hidden_symbol()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001365 Object* obj;
1366 { MaybeObject* maybe_obj =
1367 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1368 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1369 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 return AddSlowProperty(name, value, attributes);
1371 }
1372
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001373 DescriptorArray* old_descriptors = map()->instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001374 // Compute the new index for new field.
1375 int index = map()->NextFreePropertyIndex();
1376
1377 // Allocate new instance descriptors with (name, index) added
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001378 FieldDescriptor new_field(name, index, attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001379 Object* new_descriptors;
1380 { MaybeObject* maybe_new_descriptors =
1381 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1382 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1383 return maybe_new_descriptors;
1384 }
1385 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001386
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001387 // Only allow map transition if the object isn't the global object and there
1388 // is not a transition for the name, or there's a transition for the name but
1389 // it's unrelated to properties.
1390 int descriptor_index = old_descriptors->Search(name);
1391
1392 // External array transitions are stored in the descriptor for property "",
1393 // which is not a identifier and should have forced a switch to slow
1394 // properties above.
1395 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
1396 old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION);
1397 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
1398 old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 bool allow_map_transition =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001400 can_insert_transition &&
1401 (isolate->context()->global_context()->object_function()->map() != map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402
ager@chromium.org7c537e22008-10-16 08:43:32 +00001403 ASSERT(index < map()->inobject_properties() ||
1404 (index - map()->inobject_properties()) < properties()->length() ||
1405 map()->unused_property_fields() == 0);
1406 // Allocate a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001407 Object* r;
1408 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1409 if (!maybe_r->ToObject(&r)) return maybe_r;
1410 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001411 Map* new_map = Map::cast(r);
1412 if (allow_map_transition) {
1413 // Allocate new instance descriptors for the old map with map transition.
1414 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001415 Object* r;
1416 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1417 if (!maybe_r->ToObject(&r)) return maybe_r;
1418 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001419 old_descriptors = DescriptorArray::cast(r);
1420 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001421
ager@chromium.org7c537e22008-10-16 08:43:32 +00001422 if (map()->unused_property_fields() == 0) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001423 if (properties()->length() > MaxFastProperties()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001424 Object* obj;
1425 { MaybeObject* maybe_obj =
1426 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1427 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1428 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001429 return AddSlowProperty(name, value, attributes);
1430 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431 // Make room for the new value
lrn@chromium.org303ada72010-10-27 09:33:13 +00001432 Object* values;
1433 { MaybeObject* maybe_values =
1434 properties()->CopySize(properties()->length() + kFieldsAdded);
1435 if (!maybe_values->ToObject(&values)) return maybe_values;
1436 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001437 set_properties(FixedArray::cast(values));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001438 new_map->set_unused_property_fields(kFieldsAdded - 1);
1439 } else {
1440 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001442 // We have now allocated all the necessary objects.
1443 // All the changes can be applied at once, so they are atomic.
1444 map()->set_instance_descriptors(old_descriptors);
1445 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1446 set_map(new_map);
1447 return FastPropertyAtPut(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001448}
1449
1450
lrn@chromium.org303ada72010-10-27 09:33:13 +00001451MaybeObject* JSObject::AddConstantFunctionProperty(
1452 String* name,
1453 JSFunction* function,
1454 PropertyAttributes attributes) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001455 ASSERT(!GetHeap()->InNewSpace(function));
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001456
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001457 // Allocate new instance descriptors with (name, function) added
1458 ConstantFunctionDescriptor d(name, function, attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001459 Object* new_descriptors;
1460 { MaybeObject* maybe_new_descriptors =
1461 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1462 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1463 return maybe_new_descriptors;
1464 }
1465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466
1467 // Allocate a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001468 Object* new_map;
1469 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1470 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1471 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472
1473 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1474 Map::cast(new_map)->set_instance_descriptors(descriptors);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001475 Map* old_map = map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476 set_map(Map::cast(new_map));
1477
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001478 // If the old map is the global object map (from new Object()),
1479 // then transitions are not added to it, so we are done.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001480 Heap* heap = old_map->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001481 if (old_map == heap->isolate()->context()->global_context()->
1482 object_function()->map()) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001483 return function;
1484 }
1485
1486 // Do not add CONSTANT_TRANSITIONS to global objects
1487 if (IsGlobalObject()) {
1488 return function;
1489 }
1490
1491 // Add a CONSTANT_TRANSITION descriptor to the old map,
1492 // so future assignments to this property on other objects
1493 // of the same type will create a normal field, not a constant function.
1494 // Don't do this for special properties, with non-trival attributes.
1495 if (attributes != NONE) {
1496 return function;
1497 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001498 ConstTransitionDescriptor mark(name, Map::cast(new_map));
lrn@chromium.org303ada72010-10-27 09:33:13 +00001499 { MaybeObject* maybe_new_descriptors =
1500 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1501 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1502 // We have accomplished the main goal, so return success.
1503 return function;
1504 }
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001505 }
1506 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1507
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001508 return function;
1509}
1510
1511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001512// Add property in slow mode
lrn@chromium.org303ada72010-10-27 09:33:13 +00001513MaybeObject* JSObject::AddSlowProperty(String* name,
1514 Object* value,
1515 PropertyAttributes attributes) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001516 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001517 StringDictionary* dict = property_dictionary();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001518 Object* store_value = value;
1519 if (IsGlobalObject()) {
1520 // In case name is an orphaned property reuse the cell.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001521 int entry = dict->FindEntry(name);
1522 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001523 store_value = dict->ValueAt(entry);
1524 JSGlobalPropertyCell::cast(store_value)->set_value(value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001525 // Assign an enumeration index to the property and update
1526 // SetNextEnumerationIndex.
1527 int index = dict->NextEnumerationIndex();
1528 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1529 dict->SetNextEnumerationIndex(index + 1);
1530 dict->SetEntry(entry, name, store_value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001531 return value;
1532 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001533 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001534 { MaybeObject* maybe_store_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001535 heap->AllocateJSGlobalPropertyCell(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001536 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1537 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001538 JSGlobalPropertyCell::cast(store_value)->set_value(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001540 PropertyDetails details = PropertyDetails(attributes, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001541 Object* result;
1542 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1543 if (!maybe_result->ToObject(&result)) return maybe_result;
1544 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001545 if (dict != result) set_properties(StringDictionary::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546 return value;
1547}
1548
1549
lrn@chromium.org303ada72010-10-27 09:33:13 +00001550MaybeObject* JSObject::AddProperty(String* name,
1551 Object* value,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001552 PropertyAttributes attributes,
1553 StrictModeFlag strict_mode) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001554 ASSERT(!IsJSGlobalProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001555 Map* map_of_this = map();
1556 Heap* heap = map_of_this->heap();
1557 if (!map_of_this->is_extensible()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001558 if (strict_mode == kNonStrictMode) {
1559 return heap->undefined_value();
1560 } else {
1561 Handle<Object> args[1] = {Handle<String>(name)};
1562 return heap->isolate()->Throw(
1563 *FACTORY->NewTypeError("object_not_extensible",
1564 HandleVector(args, 1)));
1565 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001566 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001567 if (HasFastProperties()) {
1568 // Ensure the descriptor array does not get too big.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001569 if (map_of_this->instance_descriptors()->number_of_descriptors() <
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 DescriptorArray::kMaxNumberOfDescriptors) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 return AddConstantFunctionProperty(name,
1573 JSFunction::cast(value),
1574 attributes);
1575 } else {
1576 return AddFastProperty(name, value, attributes);
1577 }
1578 } else {
1579 // Normalize the object to prevent very large instance descriptors.
1580 // This eliminates unwanted N^2 allocation and lookup behavior.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001581 Object* obj;
1582 { MaybeObject* maybe_obj =
1583 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1584 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586 }
1587 }
1588 return AddSlowProperty(name, value, attributes);
1589}
1590
1591
lrn@chromium.org303ada72010-10-27 09:33:13 +00001592MaybeObject* JSObject::SetPropertyPostInterceptor(
1593 String* name,
1594 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001595 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001596 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 // Check local property, ignore interceptor.
1598 LookupResult result;
1599 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00001600 if (result.IsFound()) {
1601 // An existing property, a map transition or a null descriptor was
1602 // found. Use set property to handle all these cases.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001603 return SetProperty(&result, name, value, attributes, strict_mode);
ager@chromium.org5c838252010-02-19 08:53:10 +00001604 }
1605 // Add a new real property.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001606 return AddProperty(name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607}
1608
1609
lrn@chromium.org303ada72010-10-27 09:33:13 +00001610MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1611 Object* value,
1612 PropertyAttributes attributes) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001613 StringDictionary* dictionary = property_dictionary();
1614 int old_index = dictionary->FindEntry(name);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001615 int new_enumeration_index = 0; // 0 means "Use the next available index."
1616 if (old_index != -1) {
1617 // All calls to ReplaceSlowProperty have had all transitions removed.
1618 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1619 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1620 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001621
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001622 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001623 return SetNormalizedProperty(name, value, new_details);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001624}
1625
ager@chromium.org6141cbe2009-11-20 12:14:52 +00001626
lrn@chromium.org303ada72010-10-27 09:33:13 +00001627MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
ager@chromium.org7c537e22008-10-16 08:43:32 +00001628 String* name,
1629 Object* new_value,
1630 PropertyAttributes attributes) {
1631 Map* old_map = map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001632 Object* result;
1633 { MaybeObject* maybe_result =
1634 ConvertDescriptorToField(name, new_value, attributes);
1635 if (!maybe_result->ToObject(&result)) return maybe_result;
1636 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001637 // If we get to this point we have succeeded - do not return failure
1638 // after this point. Later stuff is optional.
1639 if (!HasFastProperties()) {
1640 return result;
1641 }
1642 // Do not add transitions to the map of "new Object()".
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001643 if (map() == old_map->heap()->isolate()->context()->global_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001644 object_function()->map()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001645 return result;
1646 }
1647
1648 MapTransitionDescriptor transition(name,
1649 map(),
1650 attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001651 Object* new_descriptors;
1652 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1653 CopyInsert(&transition, KEEP_TRANSITIONS);
1654 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1655 return result; // Yes, return _result_.
1656 }
1657 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001658 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1659 return result;
1660}
1661
1662
lrn@chromium.org303ada72010-10-27 09:33:13 +00001663MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1664 Object* new_value,
1665 PropertyAttributes attributes) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001666 if (map()->unused_property_fields() == 0 &&
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001667 properties()->length() > MaxFastProperties()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001668 Object* obj;
1669 { MaybeObject* maybe_obj =
1670 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1671 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1672 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001673 return ReplaceSlowProperty(name, new_value, attributes);
1674 }
1675
1676 int index = map()->NextFreePropertyIndex();
1677 FieldDescriptor new_field(name, index, attributes);
1678 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001679 Object* descriptors_unchecked;
1680 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1681 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1682 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1683 return maybe_descriptors_unchecked;
1684 }
1685 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001686 DescriptorArray* new_descriptors =
1687 DescriptorArray::cast(descriptors_unchecked);
1688
1689 // Make a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001690 Object* new_map_unchecked;
1691 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1692 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1693 return maybe_new_map_unchecked;
1694 }
1695 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001696 Map* new_map = Map::cast(new_map_unchecked);
1697 new_map->set_instance_descriptors(new_descriptors);
1698
1699 // Make new properties array if necessary.
1700 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1701 int new_unused_property_fields = map()->unused_property_fields() - 1;
1702 if (map()->unused_property_fields() == 0) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001703 new_unused_property_fields = kFieldsAdded - 1;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001704 Object* new_properties_object;
1705 { MaybeObject* maybe_new_properties_object =
1706 properties()->CopySize(properties()->length() + kFieldsAdded);
1707 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1708 return maybe_new_properties_object;
1709 }
1710 }
1711 new_properties = FixedArray::cast(new_properties_object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001712 }
1713
1714 // Update pointers to commit changes.
1715 // Object points to the new map.
1716 new_map->set_unused_property_fields(new_unused_property_fields);
1717 set_map(new_map);
1718 if (new_properties) {
1719 set_properties(FixedArray::cast(new_properties));
1720 }
1721 return FastPropertyAtPut(index, new_value);
1722}
1723
1724
1725
lrn@chromium.org303ada72010-10-27 09:33:13 +00001726MaybeObject* JSObject::SetPropertyWithInterceptor(
1727 String* name,
1728 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001729 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001730 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 Isolate* isolate = GetIsolate();
1732 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 Handle<JSObject> this_handle(this);
1734 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001736 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1737 if (!interceptor->setter()->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001738 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1739 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001740 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741 v8::NamedPropertySetter setter =
1742 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1743 v8::Handle<v8::Value> result;
1744 {
1745 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001747 Handle<Object> value_unhole(value->IsTheHole() ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001748 isolate->heap()->undefined_value() :
1749 value,
1750 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001751 result = setter(v8::Utils::ToLocal(name_handle),
1752 v8::Utils::ToLocal(value_unhole),
1753 info);
1754 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001756 if (!result.IsEmpty()) return *value_handle;
1757 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001758 MaybeObject* raw_result =
1759 this_handle->SetPropertyPostInterceptor(*name_handle,
1760 *value_handle,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001761 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001762 strict_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001764 return raw_result;
1765}
1766
1767
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001768MaybeObject* JSReceiver::SetProperty(String* name,
1769 Object* value,
1770 PropertyAttributes attributes,
1771 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772 LookupResult result;
1773 LocalLookup(name, &result);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001774 return SetProperty(&result, name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001775}
1776
1777
lrn@chromium.org303ada72010-10-27 09:33:13 +00001778MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1779 String* name,
1780 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001781 JSObject* holder,
1782 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001783 Isolate* isolate = GetIsolate();
1784 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001785
1786 // We should never get here to initialize a const with the hole
1787 // value since a const declaration would conflict with the setter.
1788 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001790
1791 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001792 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001793 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001794 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001795 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001796 reinterpret_cast<AccessorDescriptor*>(
1797 Foreign::cast(structure)->address());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001798 MaybeObject* obj = (callback->setter)(this, value, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001799 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001800 if (obj->IsFailure()) return obj;
1801 return *value_handle;
1802 }
1803
1804 if (structure->IsAccessorInfo()) {
1805 // api style callbacks
1806 AccessorInfo* data = AccessorInfo::cast(structure);
1807 Object* call_obj = data->setter();
1808 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1809 if (call_fun == NULL) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1812 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001813 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001814 {
1815 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 call_fun(v8::Utils::ToLocal(key),
1818 v8::Utils::ToLocal(value_handle),
1819 info);
1820 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001821 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001822 return *value_handle;
1823 }
1824
1825 if (structure->IsFixedArray()) {
1826 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
1827 if (setter->IsJSFunction()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001828 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001830 if (strict_mode == kNonStrictMode) {
1831 return value;
1832 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001834 Handle<Object> holder_handle(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 return isolate->Throw(
1837 *isolate->factory()->NewTypeError("no_setter_in_callback",
1838 HandleVector(args, 2)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001840 }
1841
1842 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001843 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001844}
1845
1846
lrn@chromium.org303ada72010-10-27 09:33:13 +00001847MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
1848 Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 Isolate* isolate = GetIsolate();
1850 Handle<Object> value_handle(value, isolate);
1851 Handle<JSFunction> fun(JSFunction::cast(setter), isolate);
1852 Handle<JSObject> self(this, isolate);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001853#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001854 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001855 // Handle stepping into a setter if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856 if (debug->StepInActive()) {
1857 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001858 }
1859#endif
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001860 bool has_pending_exception;
1861 Object** argv[] = { value_handle.location() };
1862 Execution::Call(fun, self, 1, argv, &has_pending_exception);
1863 // Check for pending exception and return the result.
1864 if (has_pending_exception) return Failure::Exception();
1865 return *value_handle;
1866}
1867
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001868
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869void JSObject::LookupCallbackSetterInPrototypes(String* name,
1870 LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001871 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001873 pt != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001874 pt = pt->GetPrototype()) {
1875 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00001876 if (result->IsProperty()) {
1877 if (result->IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 result->NotFound();
1879 return;
1880 }
1881 if (result->type() == CALLBACKS) {
1882 return;
1883 }
1884 }
1885 }
1886 result->NotFound();
1887}
1888
1889
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001890MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
1891 uint32_t index,
1892 Object* value,
1893 bool* found,
1894 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001895 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001896 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001897 pt != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001898 pt = pt->GetPrototype()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001899 if (!JSObject::cast(pt)->HasDictionaryElements()) {
1900 continue;
1901 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001902 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
1903 int entry = dictionary->FindEntry(index);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001904 if (entry != NumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001905 PropertyDetails details = dictionary->DetailsAt(entry);
1906 if (details.type() == CALLBACKS) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001907 *found = true;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001908 return SetElementWithCallback(dictionary->ValueAt(entry),
1909 index,
1910 value,
1911 JSObject::cast(pt),
1912 strict_mode);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001913 }
1914 }
1915 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001916 *found = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001917 return heap->the_hole_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001918}
1919
1920
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001921void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1922 DescriptorArray* descriptors = map()->instance_descriptors();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001923 int number = descriptors->SearchWithCache(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924 if (number != DescriptorArray::kNotFound) {
1925 result->DescriptorResult(this, descriptors->GetDetails(number), number);
1926 } else {
1927 result->NotFound();
1928 }
1929}
1930
1931
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001932void Map::LookupInDescriptors(JSObject* holder,
1933 String* name,
1934 LookupResult* result) {
1935 DescriptorArray* descriptors = instance_descriptors();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001936 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
1937 int number = cache->Lookup(descriptors, name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001938 if (number == DescriptorLookupCache::kAbsent) {
1939 number = descriptors->Search(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001940 cache->Update(descriptors, name, number);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001941 }
1942 if (number != DescriptorArray::kNotFound) {
1943 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
1944 } else {
1945 result->NotFound();
1946 }
1947}
1948
1949
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001950static JSObject::ElementsKind GetElementsKindFromExternalArrayType(
1951 ExternalArrayType array_type) {
1952 switch (array_type) {
1953 case kExternalByteArray:
1954 return JSObject::EXTERNAL_BYTE_ELEMENTS;
1955 break;
1956 case kExternalUnsignedByteArray:
1957 return JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
1958 break;
1959 case kExternalShortArray:
1960 return JSObject::EXTERNAL_SHORT_ELEMENTS;
1961 break;
1962 case kExternalUnsignedShortArray:
1963 return JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
1964 break;
1965 case kExternalIntArray:
1966 return JSObject::EXTERNAL_INT_ELEMENTS;
1967 break;
1968 case kExternalUnsignedIntArray:
1969 return JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS;
1970 break;
1971 case kExternalFloatArray:
1972 return JSObject::EXTERNAL_FLOAT_ELEMENTS;
1973 break;
1974 case kExternalDoubleArray:
1975 return JSObject::EXTERNAL_DOUBLE_ELEMENTS;
1976 break;
1977 case kExternalPixelArray:
1978 return JSObject::EXTERNAL_PIXEL_ELEMENTS;
1979 break;
1980 }
1981 UNREACHABLE();
1982 return JSObject::DICTIONARY_ELEMENTS;
1983}
1984
1985
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001986MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
1987 bool safe_to_add_transition) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001988 Heap* current_heap = heap();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001989 DescriptorArray* descriptors = instance_descriptors();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001990 String* external_array_sentinel_name = current_heap->empty_symbol();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001991
1992 if (safe_to_add_transition) {
1993 // It's only safe to manipulate the descriptor array if it would be
1994 // safe to add a transition.
1995
1996 ASSERT(!is_shared()); // no transitions can be added to shared maps.
1997 // Check if the external array transition already exists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001998 DescriptorLookupCache* cache =
1999 current_heap->isolate()->descriptor_lookup_cache();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002000 int index = cache->Lookup(descriptors, external_array_sentinel_name);
2001 if (index == DescriptorLookupCache::kAbsent) {
2002 index = descriptors->Search(external_array_sentinel_name);
2003 cache->Update(descriptors,
2004 external_array_sentinel_name,
2005 index);
2006 }
2007
2008 // If the transition already exists, check the type. If there is a match,
2009 // return it.
2010 if (index != DescriptorArray::kNotFound) {
2011 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
2012 if (details.type() == EXTERNAL_ARRAY_TRANSITION &&
2013 details.array_type() == array_type) {
2014 return descriptors->GetValue(index);
2015 } else {
2016 safe_to_add_transition = false;
2017 }
2018 }
2019 }
2020
2021 // No transition to an existing external array map. Make a new one.
2022 Object* obj;
2023 { MaybeObject* maybe_map = CopyDropTransitions();
2024 if (!maybe_map->ToObject(&obj)) return maybe_map;
2025 }
2026 Map* new_map = Map::cast(obj);
2027
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002028 new_map->set_elements_kind(GetElementsKindFromExternalArrayType(array_type));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002029 GetIsolate()->counters()->map_to_external_array_elements()->Increment();
2030
2031 // Only remember the map transition if the object's map is NOT equal to the
2032 // global object_function's map and there is not an already existing
2033 // non-matching external array transition.
2034 bool allow_map_transition =
2035 safe_to_add_transition &&
2036 (GetIsolate()->context()->global_context()->object_function()->map() !=
2037 map());
2038 if (allow_map_transition) {
2039 // Allocate new instance descriptors for the old map with map transition.
2040 ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
2041 Map::cast(new_map),
2042 array_type);
2043 Object* new_descriptors;
2044 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
2045 &desc,
2046 KEEP_TRANSITIONS);
2047 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2048 return maybe_new_descriptors;
2049 }
2050 descriptors = DescriptorArray::cast(new_descriptors);
2051 set_instance_descriptors(descriptors);
2052 }
2053
2054 return new_map;
2055}
2056
2057
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058void JSObject::LocalLookupRealNamedProperty(String* name,
2059 LookupResult* result) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002060 if (IsJSGlobalProxy()) {
2061 Object* proto = GetPrototype();
2062 if (proto->IsNull()) return result->NotFound();
2063 ASSERT(proto->IsJSGlobalObject());
2064 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2065 }
2066
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002067 if (HasFastProperties()) {
2068 LookupInDescriptor(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002069 if (result->IsFound()) {
2070 // A property, a map transition or a null descriptor was found.
2071 // We return all of these result types because
2072 // LocalLookupRealNamedProperty is used when setting properties
2073 // where map transitions and null descriptors are handled.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002074 ASSERT(result->holder() == this && result->type() != NORMAL);
2075 // Disallow caching for uninitialized constants. These can only
2076 // occur as fields.
2077 if (result->IsReadOnly() && result->type() == FIELD &&
ager@chromium.org7c537e22008-10-16 08:43:32 +00002078 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002079 result->DisallowCaching();
2080 }
2081 return;
2082 }
2083 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002084 int entry = property_dictionary()->FindEntry(name);
2085 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002086 Object* value = property_dictionary()->ValueAt(entry);
2087 if (IsGlobalObject()) {
2088 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2089 if (d.IsDeleted()) {
2090 result->NotFound();
2091 return;
2092 }
2093 value = JSGlobalPropertyCell::cast(value)->value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002094 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002095 // Make sure to disallow caching for uninitialized constants
2096 // found in the dictionary-mode objects.
2097 if (value->IsTheHole()) result->DisallowCaching();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002098 result->DictionaryResult(this, entry);
2099 return;
2100 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002101 }
2102 result->NotFound();
2103}
2104
2105
2106void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2107 LocalLookupRealNamedProperty(name, result);
2108 if (result->IsProperty()) return;
2109
2110 LookupRealNamedPropertyInPrototypes(name, result);
2111}
2112
2113
2114void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2115 LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002116 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002117 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002118 pt != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002119 pt = JSObject::cast(pt)->GetPrototype()) {
2120 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002121 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002122 }
2123 result->NotFound();
2124}
2125
2126
2127// We only need to deal with CALLBACKS and INTERCEPTORS
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002128MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2129 LookupResult* result,
2130 String* name,
2131 Object* value,
2132 bool check_prototype,
2133 StrictModeFlag strict_mode) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002134 if (check_prototype && !result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002135 LookupCallbackSetterInPrototypes(name, result);
2136 }
2137
2138 if (result->IsProperty()) {
2139 if (!result->IsReadOnly()) {
2140 switch (result->type()) {
2141 case CALLBACKS: {
2142 Object* obj = result->GetCallbackObject();
2143 if (obj->IsAccessorInfo()) {
2144 AccessorInfo* info = AccessorInfo::cast(obj);
2145 if (info->all_can_write()) {
2146 return SetPropertyWithCallback(result->GetCallbackObject(),
2147 name,
2148 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002149 result->holder(),
2150 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002151 }
2152 }
2153 break;
2154 }
2155 case INTERCEPTOR: {
2156 // Try lookup real named properties. Note that only property can be
2157 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2158 LookupResult r;
2159 LookupRealNamedProperty(name, &r);
2160 if (r.IsProperty()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002161 return SetPropertyWithFailedAccessCheck(&r,
2162 name,
2163 value,
2164 check_prototype,
2165 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002166 }
2167 break;
2168 }
2169 default: {
2170 break;
2171 }
2172 }
2173 }
2174 }
2175
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002176 HandleScope scope;
2177 Handle<Object> value_handle(value);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002178 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002179 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002180 return *value_handle;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002181}
2182
2183
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002184MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2185 String* key,
2186 Object* value,
2187 PropertyAttributes attributes,
2188 StrictModeFlag strict_mode) {
2189 if (result->IsFound() && result->type() == HANDLER) {
2190 return JSProxy::cast(this)->SetPropertyWithHandler(
2191 key, value, attributes, strict_mode);
2192 } else {
2193 return JSObject::cast(this)->SetPropertyForResult(
2194 result, key, value, attributes, strict_mode);
2195 }
2196}
2197
2198
2199MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2200 String* name_raw,
2201 Object* value_raw,
2202 PropertyAttributes attributes,
2203 StrictModeFlag strict_mode) {
2204 Isolate* isolate = GetIsolate();
2205 HandleScope scope;
2206 Handle<Object> receiver(this);
2207 Handle<Object> name(name_raw);
2208 Handle<Object> value(value_raw);
2209 Handle<Object> handler(this->handler());
2210
2211 // Extract trap function.
2212 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set");
2213 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2214 if (trap->IsUndefined()) {
2215 trap = isolate->derived_set_trap();
2216 }
2217
2218 // Call trap function.
2219 Object** args[] = {
2220 receiver.location(), name.location(), value.location()
2221 };
2222 bool has_exception;
2223 Handle<Object> result =
2224 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2225 if (has_exception) return Failure::Exception();
2226
2227 return value_raw;
2228}
2229
2230
2231MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2232 JSReceiver* receiver_raw,
2233 String* name_raw,
2234 bool* has_exception) {
2235 Isolate* isolate = GetIsolate();
2236 HandleScope scope;
2237 Handle<JSReceiver> receiver(receiver_raw);
2238 Handle<Object> name(name_raw);
2239 Handle<Object> handler(this->handler());
2240
2241 // Extract trap function.
2242 Handle<String> trap_name =
2243 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2244 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2245 if (trap->IsUndefined()) {
2246 Handle<Object> args[] = { handler, trap_name };
2247 Handle<Object> error = isolate->factory()->NewTypeError(
2248 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2249 isolate->Throw(*error);
2250 *has_exception = true;
2251 return NONE;
2252 }
2253
2254 // Call trap function.
2255 Object** args[] = { name.location() };
2256 Handle<Object> result =
2257 Execution::Call(trap, handler, ARRAY_SIZE(args), args, has_exception);
2258 if (has_exception) return NONE;
2259
2260 // TODO(rossberg): convert result to PropertyAttributes
2261 USE(result);
2262 return NONE;
2263}
2264
2265
2266MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002267 String* name,
2268 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002269 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002270 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002271 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002272 // Make sure that the top context does not change when doing callbacks or
2273 // interceptor calls.
2274 AssertNoContextChange ncc;
2275
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002276 // Optimization for 2-byte strings often used as keys in a decompression
2277 // dictionary. We make these short keys into symbols to avoid constantly
2278 // reallocating them.
2279 if (!name->IsSymbol() && name->length() <= 2) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002280 Object* symbol_version;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002281 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002282 if (maybe_symbol_version->ToObject(&symbol_version)) {
2283 name = String::cast(symbol_version);
2284 }
2285 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002286 }
2287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002288 // Check access rights if needed.
2289 if (IsAccessCheckNeeded()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002291 return SetPropertyWithFailedAccessCheck(result,
2292 name,
2293 value,
2294 true,
2295 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002296 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002297
2298 if (IsJSGlobalProxy()) {
2299 Object* proto = GetPrototype();
2300 if (proto->IsNull()) return value;
2301 ASSERT(proto->IsJSGlobalObject());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002302 return JSObject::cast(proto)->SetProperty(
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002303 result, name, value, attributes, strict_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002304 }
2305
ager@chromium.org32912102009-01-16 10:38:43 +00002306 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002307 // We could not find a local property so let's check whether there is an
2308 // accessor that wants to handle the property.
2309 LookupResult accessor_result;
2310 LookupCallbackSetterInPrototypes(name, &accessor_result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002311 if (accessor_result.IsProperty()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002312 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2313 name,
2314 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002315 accessor_result.holder(),
2316 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002317 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002318 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002319 if (!result->IsFound()) {
2320 // Neither properties nor transitions found.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002321 return AddProperty(name, value, attributes, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002322 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002323 if (result->IsReadOnly() && result->IsProperty()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002324 if (strict_mode == kStrictMode) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002325 HandleScope scope;
2326 Handle<String> key(name);
2327 Handle<Object> holder(this);
2328 Handle<Object> args[2] = { key, holder };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002329 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2330 "strict_read_only_property", HandleVector(args, 2)));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002331 } else {
2332 return value;
2333 }
2334 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002335 // This is a real property that is not read-only, or it is a
2336 // transition or null descriptor and there are no setters in the prototypes.
2337 switch (result->type()) {
2338 case NORMAL:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002339 return SetNormalizedProperty(result, value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002340 case FIELD:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002341 return FastPropertyAtPut(result->GetFieldIndex(), value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002342 case MAP_TRANSITION:
2343 if (attributes == result->GetAttributes()) {
2344 // Only use map transition if the attributes match.
2345 return AddFastPropertyUsingMap(result->GetTransitionMap(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002346 name,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002347 value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002348 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002349 return ConvertDescriptorToField(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002350 case CONSTANT_FUNCTION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002351 // Only replace the function if necessary.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002352 if (value == result->GetConstantFunction()) return value;
2353 // Preserve the attributes of this existing property.
2354 attributes = result->GetAttributes();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002355 return ConvertDescriptorToField(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002356 case CALLBACKS:
2357 return SetPropertyWithCallback(result->GetCallbackObject(),
2358 name,
2359 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002360 result->holder(),
2361 strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002362 case INTERCEPTOR:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002363 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002364 case CONSTANT_TRANSITION: {
2365 // If the same constant function is being added we can simply
2366 // transition to the target map.
2367 Map* target_map = result->GetTransitionMap();
2368 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2369 int number = target_descriptors->SearchWithCache(name);
2370 ASSERT(number != DescriptorArray::kNotFound);
2371 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2372 JSFunction* function =
2373 JSFunction::cast(target_descriptors->GetValue(number));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002374 ASSERT(!HEAP->InNewSpace(function));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002375 if (value == function) {
2376 set_map(target_map);
2377 return value;
2378 }
2379 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2380 // FIELD, even if the value is a constant function.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002381 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002382 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002383 case NULL_DESCRIPTOR:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002384 case EXTERNAL_ARRAY_TRANSITION:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002385 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002386 default:
2387 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002388 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002389 UNREACHABLE();
2390 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002391}
2392
2393
2394// Set a real local property, even if it is READ_ONLY. If the property is not
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002395// present, add it with attributes NONE. This code is an exact clone of
2396// SetProperty, with the check for IsReadOnly and the check for a
2397// callback setter removed. The two lines looking up the LookupResult
2398// result are also added. If one of the functions is changed, the other
2399// should be.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002400MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002401 String* name,
2402 Object* value,
2403 PropertyAttributes attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002405 // Make sure that the top context does not change when doing callbacks or
2406 // interceptor calls.
2407 AssertNoContextChange ncc;
ager@chromium.org5c838252010-02-19 08:53:10 +00002408 LookupResult result;
2409 LocalLookup(name, &result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002410 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002411 if (IsAccessCheckNeeded()) {
2412 Heap* heap = GetHeap();
2413 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002414 return SetPropertyWithFailedAccessCheck(&result,
2415 name,
2416 value,
2417 false,
2418 kNonStrictMode);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002419 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002420 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002421
2422 if (IsJSGlobalProxy()) {
2423 Object* proto = GetPrototype();
2424 if (proto->IsNull()) return value;
2425 ASSERT(proto->IsJSGlobalObject());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002426 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002427 name,
2428 value,
2429 attributes);
2430 }
2431
ager@chromium.org7c537e22008-10-16 08:43:32 +00002432 // Check for accessor in prototype chain removed here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00002433 if (!result.IsFound()) {
2434 // Neither properties nor transitions found.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002435 return AddProperty(name, value, attributes, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002436 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002437
ager@chromium.org5c838252010-02-19 08:53:10 +00002438 PropertyDetails details = PropertyDetails(attributes, NORMAL);
2439
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002440 // Check of IsReadOnly removed from here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00002441 switch (result.type()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002442 case NORMAL:
ager@chromium.org5c838252010-02-19 08:53:10 +00002443 return SetNormalizedProperty(name, value, details);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002444 case FIELD:
ager@chromium.org5c838252010-02-19 08:53:10 +00002445 return FastPropertyAtPut(result.GetFieldIndex(), value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002446 case MAP_TRANSITION:
ager@chromium.org5c838252010-02-19 08:53:10 +00002447 if (attributes == result.GetAttributes()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002448 // Only use map transition if the attributes match.
ager@chromium.org5c838252010-02-19 08:53:10 +00002449 return AddFastPropertyUsingMap(result.GetTransitionMap(),
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002450 name,
2451 value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002452 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002453 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002454 case CONSTANT_FUNCTION:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002455 // Only replace the function if necessary.
ager@chromium.org5c838252010-02-19 08:53:10 +00002456 if (value == result.GetConstantFunction()) return value;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002457 // Preserve the attributes of this existing property.
ager@chromium.org5c838252010-02-19 08:53:10 +00002458 attributes = result.GetAttributes();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002459 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002460 case CALLBACKS:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002461 case INTERCEPTOR:
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002462 // Override callback in clone
2463 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002464 case CONSTANT_TRANSITION:
2465 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
2466 // if the value is a function.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002467 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002468 case NULL_DESCRIPTOR:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002469 case EXTERNAL_ARRAY_TRANSITION:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002470 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002471 default:
2472 UNREACHABLE();
2473 }
2474 UNREACHABLE();
2475 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002476}
2477
2478
2479PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
2480 JSObject* receiver,
2481 String* name,
2482 bool continue_search) {
2483 // Check local property, ignore interceptor.
2484 LookupResult result;
2485 LocalLookupRealNamedProperty(name, &result);
kasper.lund44510672008-07-25 07:37:58 +00002486 if (result.IsProperty()) return result.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002487
2488 if (continue_search) {
2489 // Continue searching via the prototype chain.
2490 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002491 if (!pt->IsNull()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002492 return JSObject::cast(pt)->
2493 GetPropertyAttributeWithReceiver(receiver, name);
2494 }
2495 }
2496 return ABSENT;
2497}
2498
2499
2500PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2501 JSObject* receiver,
2502 String* name,
2503 bool continue_search) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002504 Isolate* isolate = GetIsolate();
2505
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002506 // Make sure that the top context does not change when doing
2507 // callbacks or interceptor calls.
2508 AssertNoContextChange ncc;
2509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002510 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002511 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2512 Handle<JSObject> receiver_handle(receiver);
2513 Handle<JSObject> holder_handle(this);
2514 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002515 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002516 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002517 if (!interceptor->query()->IsUndefined()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002518 v8::NamedPropertyQuery query =
2519 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002520 LOG(isolate,
2521 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002522 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002523 {
2524 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002525 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002526 result = query(v8::Utils::ToLocal(name_handle), info);
2527 }
2528 if (!result.IsEmpty()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002529 ASSERT(result->IsInt32());
2530 return static_cast<PropertyAttributes>(result->Int32Value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002531 }
2532 } else if (!interceptor->getter()->IsUndefined()) {
2533 v8::NamedPropertyGetter getter =
2534 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002535 LOG(isolate,
2536 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002537 v8::Handle<v8::Value> result;
2538 {
2539 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002540 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002541 result = getter(v8::Utils::ToLocal(name_handle), info);
2542 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002543 if (!result.IsEmpty()) return DONT_ENUM;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002544 }
2545 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2546 *name_handle,
2547 continue_search);
2548}
2549
2550
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002551PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
2552 JSReceiver* receiver,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002553 String* key) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002554 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002555 if (IsJSObject() && key->AsArrayIndex(&index)) {
2556 if (JSObject::cast(this)->HasElementWithReceiver(receiver, index))
2557 return NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002558 return ABSENT;
2559 }
2560 // Named property.
2561 LookupResult result;
2562 Lookup(key, &result);
2563 return GetPropertyAttribute(receiver, &result, key, true);
2564}
2565
2566
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002567PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
2568 LookupResult* result,
2569 String* name,
2570 bool continue_search) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002571 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002572 if (IsAccessCheckNeeded()) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002573 JSObject* this_obj = JSObject::cast(this);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002574 Heap* heap = GetHeap();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002575 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
2576 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
2577 receiver, result, name, continue_search);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002579 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002580 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002581 switch (result->type()) {
2582 case NORMAL: // fall through
2583 case FIELD:
2584 case CONSTANT_FUNCTION:
2585 case CALLBACKS:
2586 return result->GetAttributes();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002587 case HANDLER: {
2588 // TODO(rossberg): propagate exceptions properly.
2589 bool has_exception = false;
2590 return JSProxy::cast(this)->GetPropertyAttributeWithHandler(
2591 receiver, name, &has_exception);
2592 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002593 case INTERCEPTOR:
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002594 return result->holder()->GetPropertyAttributeWithInterceptor(
2595 JSObject::cast(receiver), name, continue_search);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002596 default:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002597 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002598 }
2599 }
2600 return ABSENT;
2601}
2602
2603
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002604PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002605 // Check whether the name is an array index.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002606 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002607 if (IsJSObject() && name->AsArrayIndex(&index)) {
2608 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002609 return ABSENT;
2610 }
2611 // Named property.
2612 LookupResult result;
2613 LocalLookup(name, &result);
2614 return GetPropertyAttribute(this, &result, name, false);
2615}
2616
2617
lrn@chromium.org303ada72010-10-27 09:33:13 +00002618MaybeObject* NormalizedMapCache::Get(JSObject* obj,
2619 PropertyNormalizationMode mode) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002620 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002621 Map* fast = obj->map();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002622 int index = fast->Hash() % kEntries;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002623 Object* result = get(index);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002624 if (result->IsMap() &&
2625 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002626#ifdef DEBUG
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002627 Map::cast(result)->SharedMapVerify();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002628 if (FLAG_enable_slow_asserts) {
2629 // The cached map should match newly created normalized map bit-by-bit.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002630 Object* fresh;
2631 { MaybeObject* maybe_fresh =
2632 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2633 if (maybe_fresh->ToObject(&fresh)) {
2634 ASSERT(memcmp(Map::cast(fresh)->address(),
2635 Map::cast(result)->address(),
2636 Map::kSize) == 0);
2637 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002638 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002639 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002640#endif
2641 return result;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002642 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002643
lrn@chromium.org303ada72010-10-27 09:33:13 +00002644 { MaybeObject* maybe_result =
2645 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2646 if (!maybe_result->ToObject(&result)) return maybe_result;
2647 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002648 set(index, result);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002649 isolate->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002650
2651 return result;
2652}
2653
2654
ricow@chromium.org65fae842010-08-25 15:26:24 +00002655void NormalizedMapCache::Clear() {
2656 int entries = length();
2657 for (int i = 0; i != entries; i++) {
2658 set_undefined(i);
2659 }
2660}
2661
2662
lrn@chromium.org303ada72010-10-27 09:33:13 +00002663MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002664 if (map()->is_shared()) {
2665 // Fast case maps are never marked as shared.
2666 ASSERT(!HasFastProperties());
2667 // Replace the map with an identical copy that can be safely modified.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002668 Object* obj;
2669 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2670 UNIQUE_NORMALIZED_MAP);
2671 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2672 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002673 GetIsolate()->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002674
2675 set_map(Map::cast(obj));
2676 }
2677 return map()->UpdateCodeCache(name, code);
2678}
2679
2680
lrn@chromium.org303ada72010-10-27 09:33:13 +00002681MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
2682 int expected_additional_properties) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002683 if (!HasFastProperties()) return this;
2684
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002685 // The global object is always normalized.
2686 ASSERT(!IsGlobalObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002687 // JSGlobalProxy must never be normalized
2688 ASSERT(!IsJSGlobalProxy());
2689
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002690 Map* map_of_this = map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002691
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002692 // Allocate new content.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002693 int property_count = map_of_this->NumberOfDescribedProperties();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002694 if (expected_additional_properties > 0) {
2695 property_count += expected_additional_properties;
2696 } else {
2697 property_count += 2; // Make space for two more properties.
2698 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00002699 Object* obj;
2700 { MaybeObject* maybe_obj =
2701 StringDictionary::Allocate(property_count);
2702 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2703 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002704 StringDictionary* dictionary = StringDictionary::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002706 DescriptorArray* descs = map_of_this->instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002707 for (int i = 0; i < descs->number_of_descriptors(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002708 PropertyDetails details(descs->GetDetails(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002709 switch (details.type()) {
2710 case CONSTANT_FUNCTION: {
2711 PropertyDetails d =
2712 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002713 Object* value = descs->GetConstantFunction(i);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002714 Object* result;
2715 { MaybeObject* maybe_result =
2716 dictionary->Add(descs->GetKey(i), value, d);
2717 if (!maybe_result->ToObject(&result)) return maybe_result;
2718 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002719 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002720 break;
2721 }
2722 case FIELD: {
2723 PropertyDetails d =
2724 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002725 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
lrn@chromium.org303ada72010-10-27 09:33:13 +00002726 Object* result;
2727 { MaybeObject* maybe_result =
2728 dictionary->Add(descs->GetKey(i), value, d);
2729 if (!maybe_result->ToObject(&result)) return maybe_result;
2730 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002731 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002732 break;
2733 }
2734 case CALLBACKS: {
2735 PropertyDetails d =
2736 PropertyDetails(details.attributes(), CALLBACKS, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002737 Object* value = descs->GetCallbacksObject(i);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002738 Object* result;
2739 { MaybeObject* maybe_result =
2740 dictionary->Add(descs->GetKey(i), value, d);
2741 if (!maybe_result->ToObject(&result)) return maybe_result;
2742 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002743 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002744 break;
2745 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002746 case MAP_TRANSITION:
2747 case CONSTANT_TRANSITION:
2748 case NULL_DESCRIPTOR:
2749 case INTERCEPTOR:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002750 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002751 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002752 default:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002753 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002754 }
2755 }
2756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002757 Heap* current_heap = map_of_this->heap();
2758
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002759 // Copy the next enumeration index from instance descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002760 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002761 dictionary->SetNextEnumerationIndex(index);
2762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002763 { MaybeObject* maybe_obj =
2764 current_heap->isolate()->context()->global_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002765 normalized_map_cache()->Get(this, mode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002766 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2767 }
ager@chromium.org32912102009-01-16 10:38:43 +00002768 Map* new_map = Map::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002769
ager@chromium.org32912102009-01-16 10:38:43 +00002770 // We have now successfully allocated all the necessary objects.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002771 // Changes can now be made with the guarantee that all of them take effect.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002772
2773 // Resize the object in the heap if necessary.
2774 int new_instance_size = new_map->instance_size();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002775 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002776 ASSERT(instance_size_delta >= 0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002777 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
2778 instance_size_delta);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002779
ager@chromium.org32912102009-01-16 10:38:43 +00002780 set_map(new_map);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002781 new_map->clear_instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002782
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002783 set_properties(dictionary);
2784
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002785 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002786
2787#ifdef DEBUG
2788 if (FLAG_trace_normalization) {
2789 PrintF("Object properties have been normalized:\n");
2790 Print();
2791 }
2792#endif
2793 return this;
2794}
2795
2796
lrn@chromium.org303ada72010-10-27 09:33:13 +00002797MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002798 if (HasFastProperties()) return this;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002799 ASSERT(!IsGlobalObject());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002800 return property_dictionary()->
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002801 TransformPropertiesToFastFor(this, unused_property_fields);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002802}
2803
2804
lrn@chromium.org303ada72010-10-27 09:33:13 +00002805MaybeObject* JSObject::NormalizeElements() {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002806 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002807 if (HasDictionaryElements()) return this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002808 Map* old_map = map();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002809 ASSERT(old_map->has_fast_elements() || old_map->has_fast_double_elements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00002810
lrn@chromium.org303ada72010-10-27 09:33:13 +00002811 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002812 { MaybeObject* maybe_obj = old_map->GetSlowElementsMap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00002813 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2814 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00002815 Map* new_map = Map::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002816
2817 // Get number of entries.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002818 FixedArrayBase* array = FixedArrayBase::cast(elements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002819
2820 // Compute the effective length.
2821 int length = IsJSArray() ?
2822 Smi::cast(JSArray::cast(this)->length())->value() :
2823 array->length();
lrn@chromium.org303ada72010-10-27 09:33:13 +00002824 { MaybeObject* maybe_obj = NumberDictionary::Allocate(length);
2825 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2826 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002827 bool has_double_elements = old_map->has_fast_double_elements();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002828 NumberDictionary* dictionary = NumberDictionary::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002829 // Copy entries.
2830 for (int i = 0; i < length; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002831 Object* value = NULL;
2832 if (has_double_elements) {
2833 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
2834 if (double_array->is_the_hole(i)) {
2835 value = GetIsolate()->heap()->the_hole_value();
2836 } else {
2837 // Objects must be allocated in the old object space, since the
2838 // overall number of HeapNumbers needed for the conversion might
2839 // exceed the capacity of new space, and we would fail repeatedly
2840 // trying to convert the FixedDoubleArray.
2841 MaybeObject* maybe_value_object =
2842 GetHeap()->AllocateHeapNumber(double_array->get(i), TENURED);
2843 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002844 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002845 } else {
2846 ASSERT(old_map->has_fast_elements());
2847 FixedArray* fixed_array = FixedArray::cast(array);
2848 value = fixed_array->get(i);
2849 }
2850 PropertyDetails details = PropertyDetails(NONE, NORMAL);
2851 if (!value->IsTheHole()) {
2852 Object* result;
2853 MaybeObject* maybe_result =
2854 dictionary->AddNumberEntry(i, value, details);
2855 if (!maybe_result->ToObject(&result)) return maybe_result;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002856 dictionary = NumberDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002857 }
2858 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00002859 // Switch to using the dictionary as the backing storage for
2860 // elements. Set the new map first to satify the elements type
2861 // assert in set_elements().
2862 set_map(new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002863 set_elements(dictionary);
2864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002865 new_map->heap()->isolate()->counters()->elements_to_dictionary()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002866 Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002867
2868#ifdef DEBUG
2869 if (FLAG_trace_normalization) {
2870 PrintF("Object elements have been normalized:\n");
2871 Print();
2872 }
2873#endif
2874
2875 return this;
2876}
2877
2878
lrn@chromium.org303ada72010-10-27 09:33:13 +00002879MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
2880 DeleteMode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002881 // Check local property, ignore interceptor.
2882 LookupResult result;
2883 LocalLookupRealNamedProperty(name, &result);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002884 if (!result.IsProperty()) return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002885
2886 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002887 Object* obj;
2888 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2889 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2890 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002891
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002892 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002893}
2894
2895
lrn@chromium.org303ada72010-10-27 09:33:13 +00002896MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002897 Isolate* isolate = GetIsolate();
2898 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002899 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2900 Handle<String> name_handle(name);
2901 Handle<JSObject> this_handle(this);
2902 if (!interceptor->deleter()->IsUndefined()) {
2903 v8::NamedPropertyDeleter deleter =
2904 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002905 LOG(isolate,
2906 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
2907 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002908 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002909 v8::Handle<v8::Boolean> result;
2910 {
2911 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002912 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002913 result = deleter(v8::Utils::ToLocal(name_handle), info);
2914 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002915 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002916 if (!result.IsEmpty()) {
2917 ASSERT(result->IsBoolean());
2918 return *v8::Utils::OpenHandle(*result);
2919 }
2920 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00002921 MaybeObject* raw_result =
ager@chromium.orge2902be2009-06-08 12:21:35 +00002922 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002923 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002924 return raw_result;
2925}
2926
2927
lrn@chromium.org303ada72010-10-27 09:33:13 +00002928MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index,
2929 DeleteMode mode) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002930 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002931 switch (GetElementsKind()) {
2932 case FAST_ELEMENTS: {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002933 Object* obj;
2934 { MaybeObject* maybe_obj = EnsureWritableFastElements();
2935 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2936 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002937 uint32_t length = IsJSArray() ?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002938 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
2939 static_cast<uint32_t>(FixedArray::cast(elements())->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002940 if (index < length) {
2941 FixedArray::cast(elements())->set_the_hole(index);
2942 }
2943 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002944 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002945 case DICTIONARY_ELEMENTS: {
2946 NumberDictionary* dictionary = element_dictionary();
2947 int entry = dictionary->FindEntry(index);
2948 if (entry != NumberDictionary::kNotFound) {
2949 return dictionary->DeleteProperty(entry, mode);
2950 }
2951 break;
2952 }
2953 default:
2954 UNREACHABLE();
2955 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002956 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002957 return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002958}
2959
2960
lrn@chromium.org303ada72010-10-27 09:33:13 +00002961MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002962 Isolate* isolate = GetIsolate();
2963 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002964 // Make sure that the top context does not change when doing
2965 // callbacks or interceptor calls.
2966 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002967 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002968 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002969 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002970 v8::IndexedPropertyDeleter deleter =
2971 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
2972 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002973 LOG(isolate,
2974 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
2975 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002976 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002977 v8::Handle<v8::Boolean> result;
2978 {
2979 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002980 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002981 result = deleter(index, info);
2982 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002983 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002984 if (!result.IsEmpty()) {
2985 ASSERT(result->IsBoolean());
2986 return *v8::Utils::OpenHandle(*result);
2987 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00002988 MaybeObject* raw_result =
ager@chromium.orge2902be2009-06-08 12:21:35 +00002989 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002990 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002991 return raw_result;
2992}
2993
2994
lrn@chromium.org303ada72010-10-27 09:33:13 +00002995MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002996 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002997 // Check access rights if needed.
2998 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002999 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3000 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3001 return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003002 }
3003
3004 if (IsJSGlobalProxy()) {
3005 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003006 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003007 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00003008 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003009 }
3010
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003011 if (HasIndexedInterceptor()) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003012 // Skip interceptor if forcing deletion.
3013 if (mode == FORCE_DELETION) {
3014 return DeleteElementPostInterceptor(index, mode);
3015 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003016 return DeleteElementWithInterceptor(index);
3017 }
3018
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003019 switch (GetElementsKind()) {
3020 case FAST_ELEMENTS: {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003021 Object* obj;
3022 { MaybeObject* maybe_obj = EnsureWritableFastElements();
3023 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3024 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003025 int length = IsJSArray()
3026 ? Smi::cast(JSArray::cast(this)->length())->value()
3027 : FixedArray::cast(elements())->length();
3028 if (index < static_cast<uint32_t>(length)) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003029 FixedArray::cast(elements())->set_the_hole(index);
3030 }
3031 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003032 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003033 case FAST_DOUBLE_ELEMENTS: {
3034 int length = IsJSArray()
3035 ? Smi::cast(JSArray::cast(this)->length())->value()
3036 : FixedArray::cast(elements())->length();
3037 if (index < static_cast<uint32_t>(length)) {
3038 FixedDoubleArray::cast(elements())->set_the_hole(index);
3039 }
3040 break;
3041 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003042 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003043 case EXTERNAL_BYTE_ELEMENTS:
3044 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3045 case EXTERNAL_SHORT_ELEMENTS:
3046 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3047 case EXTERNAL_INT_ELEMENTS:
3048 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3049 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003050 case EXTERNAL_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003051 // Pixel and external array elements cannot be deleted. Just
3052 // silently ignore here.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003053 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003054 case DICTIONARY_ELEMENTS: {
3055 NumberDictionary* dictionary = element_dictionary();
3056 int entry = dictionary->FindEntry(index);
3057 if (entry != NumberDictionary::kNotFound) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003058 Object* result = dictionary->DeleteProperty(entry, mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003059 if (mode == STRICT_DELETION && result ==
3060 isolate->heap()->false_value()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003061 // In strict mode, deleting a non-configurable property throws
3062 // exception. dictionary->DeleteProperty will return false_value()
3063 // if a non-configurable property is being deleted.
3064 HandleScope scope;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003065 Handle<Object> self(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003066 Handle<Object> i = isolate->factory()->NewNumberFromUint(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003067 Handle<Object> args[2] = { i, self };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003068 return isolate->Throw(*isolate->factory()->NewTypeError(
3069 "strict_delete_property", HandleVector(args, 2)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003070 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003071 }
3072 break;
3073 }
3074 default:
3075 UNREACHABLE();
3076 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003077 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003078 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003079}
3080
3081
lrn@chromium.org303ada72010-10-27 09:33:13 +00003082MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003083 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003084 // ECMA-262, 3rd, 8.6.2.5
3085 ASSERT(name->IsString());
3086
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003087 // Check access rights if needed.
3088 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003089 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3090 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3091 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003092 }
3093
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003094 if (IsJSGlobalProxy()) {
3095 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003096 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003097 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00003098 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003099 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003100
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003101 uint32_t index = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003102 if (name->AsArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003103 return DeleteElement(index, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003104 } else {
3105 LookupResult result;
3106 LocalLookup(name, &result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003107 if (!result.IsProperty()) return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003108 // Ignore attributes if forcing a deletion.
3109 if (result.IsDontDelete() && mode != FORCE_DELETION) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003110 if (mode == STRICT_DELETION) {
3111 // Deleting a non-configurable property in strict mode.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003112 HandleScope scope(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003113 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003114 return isolate->Throw(*isolate->factory()->NewTypeError(
3115 "strict_delete_property", HandleVector(args, 2)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003116 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003117 return isolate->heap()->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003118 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003119 // Check for interceptor.
3120 if (result.type() == INTERCEPTOR) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003121 // Skip interceptor if forcing a deletion.
3122 if (mode == FORCE_DELETION) {
3123 return DeletePropertyPostInterceptor(name, mode);
3124 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003125 return DeletePropertyWithInterceptor(name);
3126 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003127 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003128 Object* obj;
3129 { MaybeObject* maybe_obj =
3130 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3131 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3132 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003133 // Make sure the properties are normalized before removing the entry.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003134 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003135 }
3136}
3137
3138
3139// Check whether this object references another object.
3140bool JSObject::ReferencesObject(Object* obj) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003141 Map* map_of_this = map();
3142 Heap* heap = map_of_this->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003143 AssertNoAllocation no_alloc;
3144
3145 // Is the object the constructor for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003146 if (map_of_this->constructor() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003147 return true;
3148 }
3149
3150 // Is the object the prototype for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003151 if (map_of_this->prototype() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003152 return true;
3153 }
3154
3155 // Check if the object is among the named properties.
3156 Object* key = SlowReverseLookup(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003157 if (!key->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003158 return true;
3159 }
3160
3161 // Check if the object is among the indexed properties.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003162 switch (GetElementsKind()) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003163 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003164 case EXTERNAL_BYTE_ELEMENTS:
3165 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3166 case EXTERNAL_SHORT_ELEMENTS:
3167 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3168 case EXTERNAL_INT_ELEMENTS:
3169 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3170 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003171 case EXTERNAL_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003172 // Raw pixels and external arrays do not reference other
3173 // objects.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003174 break;
3175 case FAST_ELEMENTS: {
3176 int length = IsJSArray() ?
3177 Smi::cast(JSArray::cast(this)->length())->value() :
3178 FixedArray::cast(elements())->length();
3179 for (int i = 0; i < length; i++) {
3180 Object* element = FixedArray::cast(elements())->get(i);
3181 if (!element->IsTheHole() && element == obj) {
3182 return true;
3183 }
3184 }
3185 break;
3186 }
3187 case DICTIONARY_ELEMENTS: {
3188 key = element_dictionary()->SlowReverseLookup(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003189 if (!key->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003190 return true;
3191 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003192 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003193 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003194 default:
3195 UNREACHABLE();
3196 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003197 }
3198
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003199 // For functions check the context.
3200 if (IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003201 // Get the constructor function for arguments array.
3202 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003203 heap->isolate()->context()->global_context()->
3204 arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003205 JSFunction* arguments_function =
3206 JSFunction::cast(arguments_boilerplate->map()->constructor());
3207
3208 // Get the context and don't check if it is the global context.
3209 JSFunction* f = JSFunction::cast(this);
3210 Context* context = f->context();
3211 if (context->IsGlobalContext()) {
3212 return false;
3213 }
3214
3215 // Check the non-special context slots.
3216 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
3217 // Only check JS objects.
3218 if (context->get(i)->IsJSObject()) {
3219 JSObject* ctxobj = JSObject::cast(context->get(i));
3220 // If it is an arguments array check the content.
3221 if (ctxobj->map()->constructor() == arguments_function) {
3222 if (ctxobj->ReferencesObject(obj)) {
3223 return true;
3224 }
3225 } else if (ctxobj == obj) {
3226 return true;
3227 }
3228 }
3229 }
3230
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003231 // Check the context extension (if any) if it can have references.
3232 if (context->has_extension() && !context->IsCatchContext()) {
3233 return JSObject::cast(context->extension())->ReferencesObject(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003234 }
3235 }
3236
3237 // No references to object.
3238 return false;
3239}
3240
3241
lrn@chromium.org303ada72010-10-27 09:33:13 +00003242MaybeObject* JSObject::PreventExtensions() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003243 Isolate* isolate = GetIsolate();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003244 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003245 !isolate->MayNamedAccess(this,
3246 isolate->heap()->undefined_value(),
3247 v8::ACCESS_KEYS)) {
3248 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
3249 return isolate->heap()->false_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003250 }
3251
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003252 if (IsJSGlobalProxy()) {
3253 Object* proto = GetPrototype();
3254 if (proto->IsNull()) return this;
3255 ASSERT(proto->IsJSGlobalObject());
3256 return JSObject::cast(proto)->PreventExtensions();
3257 }
3258
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003259 // If there are fast elements we normalize.
3260 if (HasFastElements()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003261 Object* ok;
3262 { MaybeObject* maybe_ok = NormalizeElements();
3263 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3264 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003265 }
3266 // Make sure that we never go back to fast case.
3267 element_dictionary()->set_requires_slow_elements();
3268
3269 // Do a map transition, other objects with this map may still
3270 // be extensible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003271 Object* new_map;
3272 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
3273 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3274 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003275 Map::cast(new_map)->set_is_extensible(false);
3276 set_map(Map::cast(new_map));
3277 ASSERT(!map()->is_extensible());
3278 return new_map;
3279}
3280
3281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003282// Tests for the fast common case for property enumeration:
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003283// - This object and all prototypes has an enum cache (which means that it has
3284// no interceptors and needs no access checks).
3285// - This object has no elements.
3286// - No prototype has enumerable properties/elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003287bool JSObject::IsSimpleEnum() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003288 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003289 for (Object* o = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003290 o != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003291 o = JSObject::cast(o)->GetPrototype()) {
3292 JSObject* curr = JSObject::cast(o);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003293 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003294 ASSERT(!curr->HasNamedInterceptor());
3295 ASSERT(!curr->HasIndexedInterceptor());
3296 ASSERT(!curr->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003297 if (curr->NumberOfEnumElements() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003298 if (curr != this) {
3299 FixedArray* curr_fixed_array =
3300 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003301 if (curr_fixed_array->length() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003302 }
3303 }
3304 return true;
3305}
3306
3307
3308int Map::NumberOfDescribedProperties() {
3309 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003310 DescriptorArray* descs = instance_descriptors();
3311 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3312 if (descs->IsProperty(i)) result++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003313 }
3314 return result;
3315}
3316
3317
3318int Map::PropertyIndexFor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003319 DescriptorArray* descs = instance_descriptors();
3320 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3321 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
3322 return descs->GetFieldIndex(i);
3323 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003324 }
3325 return -1;
3326}
3327
3328
3329int Map::NextFreePropertyIndex() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003330 int max_index = -1;
3331 DescriptorArray* descs = instance_descriptors();
3332 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3333 if (descs->GetType(i) == FIELD) {
3334 int current_index = descs->GetFieldIndex(i);
3335 if (current_index > max_index) max_index = current_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003336 }
3337 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003338 return max_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003339}
3340
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003341
3342AccessorDescriptor* Map::FindAccessor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003343 DescriptorArray* descs = instance_descriptors();
3344 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3345 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
3346 return descs->GetCallbacks(i);
3347 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 }
3349 return NULL;
3350}
3351
3352
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003353void JSReceiver::LocalLookup(String* name, LookupResult* result) {
3354 if (IsJSProxy()) {
3355 result->HandlerResult();
3356 } else {
3357 JSObject::cast(this)->LocalLookup(name, result);
3358 }
3359}
3360
3361
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003362void JSObject::LocalLookup(String* name, LookupResult* result) {
3363 ASSERT(name->IsString());
3364
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003365 Heap* heap = GetHeap();
3366
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003367 if (IsJSGlobalProxy()) {
3368 Object* proto = GetPrototype();
3369 if (proto->IsNull()) return result->NotFound();
3370 ASSERT(proto->IsJSGlobalObject());
3371 return JSObject::cast(proto)->LocalLookup(name, result);
3372 }
3373
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003374 // Do not use inline caching if the object is a non-global object
3375 // that requires access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003376 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003377 result->DisallowCaching();
3378 }
3379
3380 // Check __proto__ before interceptor.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003381 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003382 result->ConstantResult(this);
3383 return;
3384 }
3385
3386 // Check for lookup interceptor except when bootstrapping.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003387 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003388 result->InterceptorResult(this);
3389 return;
3390 }
3391
3392 LocalLookupRealNamedProperty(name, result);
3393}
3394
3395
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003396void JSReceiver::Lookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003397 // Ecma-262 3rd 8.6.2.4
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003398 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003400 current != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 current = JSObject::cast(current)->GetPrototype()) {
3402 JSObject::cast(current)->LocalLookup(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003403 if (result->IsProperty()) return;
ager@chromium.org870a0b62008-11-04 11:43:05 +00003404 }
3405 result->NotFound();
3406}
3407
3408
3409// Search object and it's prototype chain for callback properties.
3410void JSObject::LookupCallback(String* name, LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003411 Heap* heap = GetHeap();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003412 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003413 current != heap->null_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003414 current = JSObject::cast(current)->GetPrototype()) {
3415 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003416 if (result->IsProperty() && result->type() == CALLBACKS) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417 }
3418 result->NotFound();
3419}
3420
3421
lrn@chromium.org303ada72010-10-27 09:33:13 +00003422MaybeObject* JSObject::DefineGetterSetter(String* name,
3423 PropertyAttributes attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003424 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003425 // Make sure that the top context does not change when doing callbacks or
3426 // interceptor calls.
3427 AssertNoContextChange ncc;
3428
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003429 // Try to flatten before operating on the string.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003430 name->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003431
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003432 if (!CanSetCallback(name)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003433 return heap->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003434 }
3435
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003436 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003437 bool is_element = name->AsArrayIndex(&index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003438
3439 if (is_element) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003440 switch (GetElementsKind()) {
3441 case FAST_ELEMENTS:
3442 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003443 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003444 case EXTERNAL_BYTE_ELEMENTS:
3445 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3446 case EXTERNAL_SHORT_ELEMENTS:
3447 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3448 case EXTERNAL_INT_ELEMENTS:
3449 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3450 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003451 case EXTERNAL_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003452 // Ignore getters and setters on pixel and external array
3453 // elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003454 return heap->undefined_value();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003455 case DICTIONARY_ELEMENTS: {
3456 // Lookup the index.
3457 NumberDictionary* dictionary = element_dictionary();
3458 int entry = dictionary->FindEntry(index);
3459 if (entry != NumberDictionary::kNotFound) {
3460 Object* result = dictionary->ValueAt(entry);
3461 PropertyDetails details = dictionary->DetailsAt(entry);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003462 if (details.IsReadOnly()) return heap->undefined_value();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003463 if (details.type() == CALLBACKS) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003464 if (result->IsFixedArray()) {
3465 return result;
3466 }
3467 // Otherwise allow to override it.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003468 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003469 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003470 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003471 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003472 default:
3473 UNREACHABLE();
3474 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003475 }
3476 } else {
3477 // Lookup the name.
3478 LookupResult result;
3479 LocalLookup(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003480 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003481 if (result.IsReadOnly()) return heap->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003482 if (result.type() == CALLBACKS) {
3483 Object* obj = result.GetCallbackObject();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003484 // Need to preserve old getters/setters.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003485 if (obj->IsFixedArray()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003486 // Use set to update attributes.
3487 return SetPropertyCallback(name, obj, attributes);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003488 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003489 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003490 }
3491 }
3492
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003493 // Allocate the fixed array to hold getter and setter.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003494 Object* structure;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003495 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003496 if (!maybe_structure->ToObject(&structure)) return maybe_structure;
3497 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003498
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003499 if (is_element) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003500 return SetElementCallback(index, structure, attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003501 } else {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003502 return SetPropertyCallback(name, structure, attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003503 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003504}
3505
3506
3507bool JSObject::CanSetCallback(String* name) {
3508 ASSERT(!IsAccessCheckNeeded()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003509 || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003510
3511 // Check if there is an API defined callback object which prohibits
3512 // callback overwriting in this object or it's prototype chain.
3513 // This mechanism is needed for instance in a browser setting, where
3514 // certain accessors such as window.location should not be allowed
3515 // to be overwritten because allowing overwriting could potentially
3516 // cause security problems.
3517 LookupResult callback_result;
3518 LookupCallback(name, &callback_result);
3519 if (callback_result.IsProperty()) {
3520 Object* obj = callback_result.GetCallbackObject();
3521 if (obj->IsAccessorInfo() &&
3522 AccessorInfo::cast(obj)->prohibits_overwriting()) {
3523 return false;
3524 }
3525 }
3526
3527 return true;
3528}
3529
3530
lrn@chromium.org303ada72010-10-27 09:33:13 +00003531MaybeObject* JSObject::SetElementCallback(uint32_t index,
3532 Object* structure,
3533 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003534 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3535
3536 // Normalize elements to make this operation simple.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003537 Object* ok;
3538 { MaybeObject* maybe_ok = NormalizeElements();
3539 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3540 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003541
3542 // Update the dictionary with the new CALLBACKS property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003543 Object* dict;
3544 { MaybeObject* maybe_dict =
3545 element_dictionary()->Set(index, structure, details);
3546 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
3547 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003548
3549 NumberDictionary* elements = NumberDictionary::cast(dict);
3550 elements->set_requires_slow_elements();
3551 // Set the potential new dictionary on the object.
3552 set_elements(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003553
3554 return structure;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555}
3556
3557
lrn@chromium.org303ada72010-10-27 09:33:13 +00003558MaybeObject* JSObject::SetPropertyCallback(String* name,
3559 Object* structure,
3560 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003561 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3562
3563 bool convert_back_to_fast = HasFastProperties() &&
3564 (map()->instance_descriptors()->number_of_descriptors()
3565 < DescriptorArray::kMaxNumberOfDescriptors);
3566
3567 // Normalize object to make this operation simple.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003568 Object* ok;
3569 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3570 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3571 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003572
3573 // For the global object allocate a new map to invalidate the global inline
3574 // caches which have a global property cell reference directly in the code.
3575 if (IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003576 Object* new_map;
3577 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
3578 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3579 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003580 set_map(Map::cast(new_map));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003581 // When running crankshaft, changing the map is not enough. We
3582 // need to deoptimize all functions that rely on this global
3583 // object.
3584 Deoptimizer::DeoptimizeGlobalObject(this);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003585 }
3586
3587 // Update the dictionary with the new CALLBACKS property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003588 Object* result;
3589 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
3590 if (!maybe_result->ToObject(&result)) return maybe_result;
3591 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003592
3593 if (convert_back_to_fast) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003594 { MaybeObject* maybe_ok = TransformToFastProperties(0);
3595 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3596 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003597 }
3598 return result;
3599}
3600
lrn@chromium.org303ada72010-10-27 09:33:13 +00003601MaybeObject* JSObject::DefineAccessor(String* name,
3602 bool is_getter,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003603 Object* fun,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003604 PropertyAttributes attributes) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003605 ASSERT(fun->IsJSFunction() || fun->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003606 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003607 // Check access rights if needed.
3608 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003609 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3610 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3611 return isolate->heap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003612 }
3613
3614 if (IsJSGlobalProxy()) {
3615 Object* proto = GetPrototype();
3616 if (proto->IsNull()) return this;
3617 ASSERT(proto->IsJSGlobalObject());
3618 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
3619 fun, attributes);
3620 }
3621
lrn@chromium.org303ada72010-10-27 09:33:13 +00003622 Object* array;
3623 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
3624 if (!maybe_array->ToObject(&array)) return maybe_array;
3625 }
3626 if (array->IsUndefined()) return array;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003627 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
3628 return this;
3629}
3630
3631
lrn@chromium.org303ada72010-10-27 09:33:13 +00003632MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003633 Isolate* isolate = GetIsolate();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003634 String* name = String::cast(info->name());
3635 // Check access rights if needed.
3636 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003637 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3638 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3639 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003640 }
3641
3642 if (IsJSGlobalProxy()) {
3643 Object* proto = GetPrototype();
3644 if (proto->IsNull()) return this;
3645 ASSERT(proto->IsJSGlobalObject());
3646 return JSObject::cast(proto)->DefineAccessor(info);
3647 }
3648
3649 // Make sure that the top context does not change when doing callbacks or
3650 // interceptor calls.
3651 AssertNoContextChange ncc;
3652
3653 // Try to flatten before operating on the string.
3654 name->TryFlatten();
3655
3656 if (!CanSetCallback(name)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003657 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003658 }
3659
3660 uint32_t index = 0;
3661 bool is_element = name->AsArrayIndex(&index);
3662
3663 if (is_element) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003664 if (IsJSArray()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003665
3666 // Accessors overwrite previous callbacks (cf. with getters/setters).
3667 switch (GetElementsKind()) {
3668 case FAST_ELEMENTS:
3669 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003670 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003671 case EXTERNAL_BYTE_ELEMENTS:
3672 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3673 case EXTERNAL_SHORT_ELEMENTS:
3674 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3675 case EXTERNAL_INT_ELEMENTS:
3676 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3677 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003678 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003679 // Ignore getters and setters on pixel and external array
3680 // elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003681 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003682 case DICTIONARY_ELEMENTS:
3683 break;
3684 default:
3685 UNREACHABLE();
3686 break;
3687 }
3688
lrn@chromium.org303ada72010-10-27 09:33:13 +00003689 Object* ok;
3690 { MaybeObject* maybe_ok =
3691 SetElementCallback(index, info, info->property_attributes());
3692 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3693 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003694 } else {
3695 // Lookup the name.
3696 LookupResult result;
3697 LocalLookup(name, &result);
3698 // ES5 forbids turning a property into an accessor if it's not
3699 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
3700 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003701 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003702 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003703 Object* ok;
3704 { MaybeObject* maybe_ok =
3705 SetPropertyCallback(name, info, info->property_attributes());
3706 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3707 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003708 }
3709
3710 return this;
3711}
3712
3713
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003714Object* JSObject::LookupAccessor(String* name, bool is_getter) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003715 Heap* heap = GetHeap();
3716
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003717 // Make sure that the top context does not change when doing callbacks or
3718 // interceptor calls.
3719 AssertNoContextChange ncc;
3720
3721 // Check access rights if needed.
3722 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003723 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
3724 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
3725 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726 }
3727
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728 // Make the lookup and include prototypes.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003729 int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003730 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003731 if (name->AsArrayIndex(&index)) {
3732 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003733 obj != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003734 obj = JSObject::cast(obj)->GetPrototype()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003735 JSObject* js_object = JSObject::cast(obj);
3736 if (js_object->HasDictionaryElements()) {
3737 NumberDictionary* dictionary = js_object->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003738 int entry = dictionary->FindEntry(index);
3739 if (entry != NumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003740 Object* element = dictionary->ValueAt(entry);
3741 PropertyDetails details = dictionary->DetailsAt(entry);
3742 if (details.type() == CALLBACKS) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003743 if (element->IsFixedArray()) {
3744 return FixedArray::cast(element)->get(accessor_index);
3745 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003746 }
3747 }
3748 }
3749 }
3750 } else {
3751 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003752 obj != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003753 obj = JSObject::cast(obj)->GetPrototype()) {
3754 LookupResult result;
3755 JSObject::cast(obj)->LocalLookup(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003756 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003757 if (result.IsReadOnly()) return heap->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003758 if (result.type() == CALLBACKS) {
3759 Object* obj = result.GetCallbackObject();
3760 if (obj->IsFixedArray()) {
3761 return FixedArray::cast(obj)->get(accessor_index);
3762 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003763 }
3764 }
3765 }
3766 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003767 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003768}
3769
3770
3771Object* JSObject::SlowReverseLookup(Object* value) {
3772 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003773 DescriptorArray* descs = map()->instance_descriptors();
3774 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3775 if (descs->GetType(i) == FIELD) {
3776 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
3777 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003778 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003779 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
3780 if (descs->GetConstantFunction(i) == value) {
3781 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003782 }
3783 }
3784 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003785 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003786 } else {
3787 return property_dictionary()->SlowReverseLookup(value);
3788 }
3789}
3790
3791
lrn@chromium.org303ada72010-10-27 09:33:13 +00003792MaybeObject* Map::CopyDropDescriptors() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003793 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003794 Object* result;
3795 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003796 heap->AllocateMap(instance_type(), instance_size());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003797 if (!maybe_result->ToObject(&result)) return maybe_result;
3798 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003799 Map::cast(result)->set_prototype(prototype());
3800 Map::cast(result)->set_constructor(constructor());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003801 // Don't copy descriptors, so map transitions always remain a forest.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003802 // If we retained the same descriptors we would have two maps
3803 // pointing to the same transition which is bad because the garbage
3804 // collector relies on being able to reverse pointers from transitions
3805 // to maps. If properties need to be retained use CopyDropTransitions.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003806 Map::cast(result)->clear_instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003807 // Please note instance_type and instance_size are set when allocated.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003808 Map::cast(result)->set_inobject_properties(inobject_properties());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003809 Map::cast(result)->set_unused_property_fields(unused_property_fields());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003810
3811 // If the map has pre-allocated properties always start out with a descriptor
3812 // array describing these properties.
3813 if (pre_allocated_property_fields() > 0) {
3814 ASSERT(constructor()->IsJSFunction());
3815 JSFunction* ctor = JSFunction::cast(constructor());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003816 Object* descriptors;
3817 { MaybeObject* maybe_descriptors =
3818 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
3819 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
3820 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003821 Map::cast(result)->set_instance_descriptors(
3822 DescriptorArray::cast(descriptors));
3823 Map::cast(result)->set_pre_allocated_property_fields(
3824 pre_allocated_property_fields());
3825 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003826 Map::cast(result)->set_bit_field(bit_field());
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003827 Map::cast(result)->set_bit_field2(bit_field2());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003828 Map::cast(result)->set_bit_field3(bit_field3());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003829 Map::cast(result)->set_is_shared(false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003830 Map::cast(result)->ClearCodeCache(heap);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003831 return result;
3832}
3833
3834
lrn@chromium.org303ada72010-10-27 09:33:13 +00003835MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
3836 NormalizedMapSharingMode sharing) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003837 int new_instance_size = instance_size();
3838 if (mode == CLEAR_INOBJECT_PROPERTIES) {
3839 new_instance_size -= inobject_properties() * kPointerSize;
3840 }
3841
lrn@chromium.org303ada72010-10-27 09:33:13 +00003842 Object* result;
3843 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003844 GetHeap()->AllocateMap(instance_type(), new_instance_size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003845 if (!maybe_result->ToObject(&result)) return maybe_result;
3846 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003847
3848 if (mode != CLEAR_INOBJECT_PROPERTIES) {
3849 Map::cast(result)->set_inobject_properties(inobject_properties());
3850 }
3851
3852 Map::cast(result)->set_prototype(prototype());
3853 Map::cast(result)->set_constructor(constructor());
3854
3855 Map::cast(result)->set_bit_field(bit_field());
3856 Map::cast(result)->set_bit_field2(bit_field2());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003857 Map::cast(result)->set_bit_field3(bit_field3());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003858
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003859 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
3860
ricow@chromium.org65fae842010-08-25 15:26:24 +00003861#ifdef DEBUG
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003862 if (Map::cast(result)->is_shared()) {
3863 Map::cast(result)->SharedMapVerify();
3864 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003865#endif
3866
3867 return result;
3868}
3869
3870
lrn@chromium.org303ada72010-10-27 09:33:13 +00003871MaybeObject* Map::CopyDropTransitions() {
3872 Object* new_map;
3873 { MaybeObject* maybe_new_map = CopyDropDescriptors();
3874 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3875 }
3876 Object* descriptors;
3877 { MaybeObject* maybe_descriptors =
3878 instance_descriptors()->RemoveTransitions();
3879 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
3880 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003881 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003882 return new_map;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003883}
3884
3885
lrn@chromium.org303ada72010-10-27 09:33:13 +00003886MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003887 // Allocate the code cache if not present.
3888 if (code_cache()->IsFixedArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003889 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003890 { MaybeObject* maybe_result = code->heap()->AllocateCodeCache();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003891 if (!maybe_result->ToObject(&result)) return maybe_result;
3892 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003893 set_code_cache(result);
3894 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003895
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003896 // Update the code cache.
3897 return CodeCache::cast(code_cache())->Update(name, code);
3898}
3899
3900
3901Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
3902 // Do a lookup if a code cache exists.
3903 if (!code_cache()->IsFixedArray()) {
3904 return CodeCache::cast(code_cache())->Lookup(name, flags);
3905 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003906 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003907 }
3908}
3909
3910
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00003911int Map::IndexInCodeCache(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003912 // Get the internal index if a code cache exists.
3913 if (!code_cache()->IsFixedArray()) {
3914 return CodeCache::cast(code_cache())->GetIndex(name, code);
3915 }
3916 return -1;
3917}
3918
3919
3920void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
3921 // No GC is supposed to happen between a call to IndexInCodeCache and
3922 // RemoveFromCodeCache so the code cache must be there.
3923 ASSERT(!code_cache()->IsFixedArray());
3924 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
3925}
3926
3927
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003928void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003929 // Traverse the transition tree without using a stack. We do this by
3930 // reversing the pointers in the maps and descriptor arrays.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003931 Map* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003932 Map* meta_map = heap()->meta_map();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003933 Object** map_or_index_field = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003934 while (current != meta_map) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003935 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003936 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003937 if (!d->IsEmpty()) {
3938 FixedArray* contents = reinterpret_cast<FixedArray*>(
3939 d->get(DescriptorArray::kContentArrayIndex));
3940 map_or_index_field = RawField(contents, HeapObject::kMapOffset);
3941 Object* map_or_index = *map_or_index_field;
3942 bool map_done = true; // Controls a nested continue statement.
3943 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
3944 i < contents->length();
3945 i += 2) {
3946 PropertyDetails details(Smi::cast(contents->get(i + 1)));
3947 if (details.IsTransition()) {
3948 // Found a map in the transition array. We record our progress in
3949 // the transition array by recording the current map in the map field
3950 // of the next map and recording the index in the transition array in
3951 // the map field of the array.
3952 Map* next = Map::cast(contents->get(i));
3953 next->set_map(current);
3954 *map_or_index_field = Smi::FromInt(i + 2);
3955 current = next;
3956 map_done = false;
3957 break;
3958 }
3959 }
3960 if (!map_done) continue;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003961 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003962 // That was the regular transitions, now for the prototype transitions.
3963 FixedArray* prototype_transitions =
3964 current->unchecked_prototype_transitions();
3965 Object** proto_map_or_index_field =
3966 RawField(prototype_transitions, HeapObject::kMapOffset);
3967 Object* map_or_index = *proto_map_or_index_field;
3968 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
3969 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
3970 if (i < prototype_transitions->length()) {
3971 // Found a map in the prototype transition array. Record progress in
3972 // an analogous way to the regular transitions array above.
3973 Object* perhaps_map = prototype_transitions->get(i);
3974 if (perhaps_map->IsMap()) {
3975 Map* next = Map::cast(perhaps_map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003976 next->set_map(current);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003977 *proto_map_or_index_field =
3978 Smi::FromInt(i + kProtoTransitionElementsPerEntry);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003979 current = next;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003980 continue;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003981 }
3982 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003983 *proto_map_or_index_field = heap()->fixed_array_map();
3984 if (map_or_index_field != NULL) {
3985 *map_or_index_field = heap()->fixed_array_map();
3986 }
3987
3988 // The callback expects a map to have a real map as its map, so we save
3989 // the map field, which is being used to track the traversal and put the
3990 // correct map (the meta_map) in place while we do the callback.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003991 Map* prev = current->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003992 current->set_map(meta_map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003993 callback(current, data);
3994 current = prev;
3995 }
3996}
3997
3998
lrn@chromium.org303ada72010-10-27 09:33:13 +00003999MaybeObject* CodeCache::Update(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004000 // The number of monomorphic stubs for normal load/store/call IC's can grow to
4001 // a large number and therefore they need to go into a hash table. They are
4002 // used to load global properties from cells.
4003 if (code->type() == NORMAL) {
4004 // Make sure that a hash table is allocated for the normal load code cache.
4005 if (normal_type_cache()->IsUndefined()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004006 Object* result;
4007 { MaybeObject* maybe_result =
4008 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
4009 if (!maybe_result->ToObject(&result)) return maybe_result;
4010 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004011 set_normal_type_cache(result);
4012 }
4013 return UpdateNormalTypeCache(name, code);
4014 } else {
4015 ASSERT(default_cache()->IsFixedArray());
4016 return UpdateDefaultCache(name, code);
4017 }
4018}
4019
4020
lrn@chromium.org303ada72010-10-27 09:33:13 +00004021MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004022 // When updating the default code cache we disregard the type encoded in the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023 // flags. This allows call constant stubs to overwrite call field
4024 // stubs, etc.
4025 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
4026
4027 // First check whether we can update existing code cache without
4028 // extending it.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004029 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030 int length = cache->length();
ager@chromium.org236ad962008-09-25 09:45:57 +00004031 int deleted_index = -1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004032 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 Object* key = cache->get(i);
ager@chromium.org236ad962008-09-25 09:45:57 +00004034 if (key->IsNull()) {
4035 if (deleted_index < 0) deleted_index = i;
4036 continue;
4037 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 if (key->IsUndefined()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00004039 if (deleted_index >= 0) i = deleted_index;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004040 cache->set(i + kCodeCacheEntryNameOffset, name);
4041 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042 return this;
4043 }
4044 if (name->Equals(String::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004045 Code::Flags found =
4046 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 if (Code::RemoveTypeFromFlags(found) == flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004048 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004049 return this;
4050 }
4051 }
4052 }
4053
ager@chromium.org236ad962008-09-25 09:45:57 +00004054 // Reached the end of the code cache. If there were deleted
4055 // elements, reuse the space for the first of them.
4056 if (deleted_index >= 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004057 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
4058 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
ager@chromium.org236ad962008-09-25 09:45:57 +00004059 return this;
4060 }
4061
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004062 // Extend the code cache with some new entries (at least one). Must be a
4063 // multiple of the entry size.
4064 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
4065 new_length = new_length - new_length % kCodeCacheEntrySize;
4066 ASSERT((new_length % kCodeCacheEntrySize) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004067 Object* result;
4068 { MaybeObject* maybe_result = cache->CopySize(new_length);
4069 if (!maybe_result->ToObject(&result)) return maybe_result;
4070 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004071
4072 // Add the (name, code) pair to the new cache.
4073 cache = FixedArray::cast(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004074 cache->set(length + kCodeCacheEntryNameOffset, name);
4075 cache->set(length + kCodeCacheEntryCodeOffset, code);
4076 set_default_cache(cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 return this;
4078}
4079
4080
lrn@chromium.org303ada72010-10-27 09:33:13 +00004081MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004082 // Adding a new entry can cause a new cache to be allocated.
4083 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004084 Object* new_cache;
4085 { MaybeObject* maybe_new_cache = cache->Put(name, code);
4086 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4087 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004088 set_normal_type_cache(new_cache);
4089 return this;
4090}
4091
4092
4093Object* CodeCache::Lookup(String* name, Code::Flags flags) {
4094 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
4095 return LookupNormalTypeCache(name, flags);
4096 } else {
4097 return LookupDefaultCache(name, flags);
4098 }
4099}
4100
4101
4102Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
4103 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004104 int length = cache->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004105 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
4106 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
ager@chromium.org236ad962008-09-25 09:45:57 +00004107 // Skip deleted elements.
4108 if (key->IsNull()) continue;
4109 if (key->IsUndefined()) return key;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004110 if (name->Equals(String::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004111 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
4112 if (code->flags() == flags) {
4113 return code;
4114 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115 }
4116 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004117 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118}
4119
4120
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004121Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
4122 if (!normal_type_cache()->IsUndefined()) {
4123 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4124 return cache->Lookup(name, flags);
4125 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004126 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004127 }
4128}
4129
4130
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004131int CodeCache::GetIndex(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004132 if (code->type() == NORMAL) {
4133 if (normal_type_cache()->IsUndefined()) return -1;
4134 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004135 return cache->GetIndex(String::cast(name), code->flags());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004136 }
4137
4138 FixedArray* array = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004139 int len = array->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004140 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
4141 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004143 return -1;
4144}
4145
4146
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004147void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004148 if (code->type() == NORMAL) {
4149 ASSERT(!normal_type_cache()->IsUndefined());
4150 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004151 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004152 cache->RemoveByIndex(index);
4153 } else {
4154 FixedArray* array = default_cache();
4155 ASSERT(array->length() >= index && array->get(index)->IsCode());
4156 // Use null instead of undefined for deleted elements to distinguish
4157 // deleted elements from unused elements. This distinction is used
4158 // when looking up in the cache and when updating the cache.
4159 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
4160 array->set_null(index - 1); // Name.
4161 array->set_null(index); // Code.
4162 }
4163}
4164
4165
4166// The key in the code cache hash table consists of the property name and the
4167// code object. The actual match is on the name and the code flags. If a key
4168// is created using the flags and not a code object it can only be used for
4169// lookup not to create a new entry.
4170class CodeCacheHashTableKey : public HashTableKey {
4171 public:
4172 CodeCacheHashTableKey(String* name, Code::Flags flags)
4173 : name_(name), flags_(flags), code_(NULL) { }
4174
4175 CodeCacheHashTableKey(String* name, Code* code)
4176 : name_(name),
4177 flags_(code->flags()),
4178 code_(code) { }
4179
4180
4181 bool IsMatch(Object* other) {
4182 if (!other->IsFixedArray()) return false;
4183 FixedArray* pair = FixedArray::cast(other);
4184 String* name = String::cast(pair->get(0));
4185 Code::Flags flags = Code::cast(pair->get(1))->flags();
4186 if (flags != flags_) {
4187 return false;
4188 }
4189 return name_->Equals(name);
4190 }
4191
4192 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
4193 return name->Hash() ^ flags;
4194 }
4195
4196 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
4197
4198 uint32_t HashForObject(Object* obj) {
4199 FixedArray* pair = FixedArray::cast(obj);
4200 String* name = String::cast(pair->get(0));
4201 Code* code = Code::cast(pair->get(1));
4202 return NameFlagsHashHelper(name, code->flags());
4203 }
4204
lrn@chromium.org303ada72010-10-27 09:33:13 +00004205 MUST_USE_RESULT MaybeObject* AsObject() {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004206 ASSERT(code_ != NULL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004207 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004208 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004209 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4210 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004211 FixedArray* pair = FixedArray::cast(obj);
4212 pair->set(0, name_);
4213 pair->set(1, code_);
4214 return pair;
4215 }
4216
4217 private:
4218 String* name_;
4219 Code::Flags flags_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004220 // TODO(jkummerow): We should be able to get by without this.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004221 Code* code_;
4222};
4223
4224
4225Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
4226 CodeCacheHashTableKey key(name, flags);
4227 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004228 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004229 return get(EntryToIndex(entry) + 1);
4230}
4231
4232
lrn@chromium.org303ada72010-10-27 09:33:13 +00004233MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004234 CodeCacheHashTableKey key(name, code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004235 Object* obj;
4236 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4237 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4238 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004239
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004240 // Don't use |this|, as the table might have grown.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004241 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4242
4243 int entry = cache->FindInsertionEntry(key.Hash());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004244 Object* k;
4245 { MaybeObject* maybe_k = key.AsObject();
4246 if (!maybe_k->ToObject(&k)) return maybe_k;
4247 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004248
4249 cache->set(EntryToIndex(entry), k);
4250 cache->set(EntryToIndex(entry) + 1, code);
4251 cache->ElementAdded();
4252 return cache;
4253}
4254
4255
4256int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
4257 CodeCacheHashTableKey key(name, flags);
4258 int entry = FindEntry(&key);
4259 return (entry == kNotFound) ? -1 : entry;
4260}
4261
4262
4263void CodeCacheHashTable::RemoveByIndex(int index) {
4264 ASSERT(index >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004265 Heap* heap = GetHeap();
4266 set(EntryToIndex(index), heap->null_value());
4267 set(EntryToIndex(index) + 1, heap->null_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004268 ElementRemoved();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004269}
4270
4271
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004272static bool HasKey(FixedArray* array, Object* key) {
4273 int len0 = array->length();
4274 for (int i = 0; i < len0; i++) {
4275 Object* element = array->get(i);
4276 if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
4277 if (element->IsString() &&
4278 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
4279 return true;
4280 }
4281 }
4282 return false;
4283}
4284
4285
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004286MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
4287 Code::Flags flags,
4288 Code* code) {
4289 // Initialize cache if necessary.
4290 if (cache()->IsUndefined()) {
4291 Object* result;
4292 { MaybeObject* maybe_result =
4293 PolymorphicCodeCacheHashTable::Allocate(
4294 PolymorphicCodeCacheHashTable::kInitialSize);
4295 if (!maybe_result->ToObject(&result)) return maybe_result;
4296 }
4297 set_cache(result);
4298 } else {
4299 // This entry shouldn't be contained in the cache yet.
4300 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
4301 ->Lookup(maps, flags)->IsUndefined());
4302 }
4303 PolymorphicCodeCacheHashTable* hash_table =
4304 PolymorphicCodeCacheHashTable::cast(cache());
4305 Object* new_cache;
4306 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
4307 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4308 }
4309 set_cache(new_cache);
4310 return this;
4311}
4312
4313
4314Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
4315 if (!cache()->IsUndefined()) {
4316 PolymorphicCodeCacheHashTable* hash_table =
4317 PolymorphicCodeCacheHashTable::cast(cache());
4318 return hash_table->Lookup(maps, flags);
4319 } else {
4320 return GetHeap()->undefined_value();
4321 }
4322}
4323
4324
4325// Despite their name, object of this class are not stored in the actual
4326// hash table; instead they're temporarily used for lookups. It is therefore
4327// safe to have a weak (non-owning) pointer to a MapList as a member field.
4328class PolymorphicCodeCacheHashTableKey : public HashTableKey {
4329 public:
4330 // Callers must ensure that |maps| outlives the newly constructed object.
4331 PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags)
4332 : maps_(maps),
4333 code_flags_(code_flags) {}
4334
4335 bool IsMatch(Object* other) {
4336 MapList other_maps(kDefaultListAllocationSize);
4337 int other_flags;
4338 FromObject(other, &other_flags, &other_maps);
4339 if (code_flags_ != other_flags) return false;
4340 if (maps_->length() != other_maps.length()) return false;
4341 // Compare just the hashes first because it's faster.
4342 int this_hash = MapsHashHelper(maps_, code_flags_);
4343 int other_hash = MapsHashHelper(&other_maps, other_flags);
4344 if (this_hash != other_hash) return false;
4345
4346 // Full comparison: for each map in maps_, look for an equivalent map in
4347 // other_maps. This implementation is slow, but probably good enough for
4348 // now because the lists are short (<= 4 elements currently).
4349 for (int i = 0; i < maps_->length(); ++i) {
4350 bool match_found = false;
4351 for (int j = 0; j < other_maps.length(); ++j) {
4352 if (maps_->at(i)->EquivalentTo(other_maps.at(j))) {
4353 match_found = true;
4354 break;
4355 }
4356 }
4357 if (!match_found) return false;
4358 }
4359 return true;
4360 }
4361
4362 static uint32_t MapsHashHelper(MapList* maps, int code_flags) {
4363 uint32_t hash = code_flags;
4364 for (int i = 0; i < maps->length(); ++i) {
4365 hash ^= maps->at(i)->Hash();
4366 }
4367 return hash;
4368 }
4369
4370 uint32_t Hash() {
4371 return MapsHashHelper(maps_, code_flags_);
4372 }
4373
4374 uint32_t HashForObject(Object* obj) {
4375 MapList other_maps(kDefaultListAllocationSize);
4376 int other_flags;
4377 FromObject(obj, &other_flags, &other_maps);
4378 return MapsHashHelper(&other_maps, other_flags);
4379 }
4380
4381 MUST_USE_RESULT MaybeObject* AsObject() {
4382 Object* obj;
4383 // The maps in |maps_| must be copied to a newly allocated FixedArray,
4384 // both because the referenced MapList is short-lived, and because C++
4385 // objects can't be stored in the heap anyway.
4386 { MaybeObject* maybe_obj =
4387 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
4388 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4389 }
4390 FixedArray* list = FixedArray::cast(obj);
4391 list->set(0, Smi::FromInt(code_flags_));
4392 for (int i = 0; i < maps_->length(); ++i) {
4393 list->set(i + 1, maps_->at(i));
4394 }
4395 return list;
4396 }
4397
4398 private:
4399 static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) {
4400 FixedArray* list = FixedArray::cast(obj);
4401 maps->Rewind(0);
4402 *code_flags = Smi::cast(list->get(0))->value();
4403 for (int i = 1; i < list->length(); ++i) {
4404 maps->Add(Map::cast(list->get(i)));
4405 }
4406 return maps;
4407 }
4408
4409 MapList* maps_; // weak.
4410 int code_flags_;
4411 static const int kDefaultListAllocationSize =
4412 KeyedIC::kMaxKeyedPolymorphism + 1;
4413};
4414
4415
4416Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
4417 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4418 int entry = FindEntry(&key);
4419 if (entry == kNotFound) return GetHeap()->undefined_value();
4420 return get(EntryToIndex(entry) + 1);
4421}
4422
4423
4424MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
4425 int code_flags,
4426 Code* code) {
4427 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4428 Object* obj;
4429 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4430 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4431 }
4432 PolymorphicCodeCacheHashTable* cache =
4433 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
4434 int entry = cache->FindInsertionEntry(key.Hash());
4435 { MaybeObject* maybe_obj = key.AsObject();
4436 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4437 }
4438 cache->set(EntryToIndex(entry), obj);
4439 cache->set(EntryToIndex(entry) + 1, code);
4440 cache->ElementAdded();
4441 return cache;
4442}
4443
4444
lrn@chromium.org303ada72010-10-27 09:33:13 +00004445MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004446 ASSERT(!array->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004447 switch (array->GetElementsKind()) {
4448 case JSObject::FAST_ELEMENTS:
4449 return UnionOfKeys(FixedArray::cast(array->elements()));
4450 case JSObject::DICTIONARY_ELEMENTS: {
4451 NumberDictionary* dict = array->element_dictionary();
4452 int size = dict->NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004453
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004454 // Allocate a temporary fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004455 Object* object;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004456 { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004457 if (!maybe_object->ToObject(&object)) return maybe_object;
4458 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004459 FixedArray* key_array = FixedArray::cast(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004460
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004461 int capacity = dict->Capacity();
4462 int pos = 0;
4463 // Copy the elements from the JSArray to the temporary fixed array.
4464 for (int i = 0; i < capacity; i++) {
4465 if (dict->IsKey(dict->KeyAt(i))) {
4466 key_array->set(pos++, dict->ValueAt(i));
4467 }
4468 }
4469 // Compute the union of this and the temporary fixed array.
4470 return UnionOfKeys(key_array);
ager@chromium.org5ec48922009-05-05 07:25:34 +00004471 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004472 default:
4473 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004474 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004475 UNREACHABLE();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004476 return GetHeap()->null_value(); // Failure case needs to "return" a value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477}
4478
4479
lrn@chromium.org303ada72010-10-27 09:33:13 +00004480MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 int len0 = length();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004482#ifdef DEBUG
4483 if (FLAG_enable_slow_asserts) {
4484 for (int i = 0; i < len0; i++) {
4485 ASSERT(get(i)->IsString() || get(i)->IsNumber());
4486 }
4487 }
4488#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 int len1 = other->length();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004490 // Optimize if 'other' is empty.
4491 // We cannot optimize if 'this' is empty, as other may have holes
4492 // or non keys.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493 if (len1 == 0) return this;
4494
4495 // Compute how many elements are not in this.
4496 int extra = 0;
4497 for (int y = 0; y < len1; y++) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004498 Object* value = other->get(y);
4499 if (!value->IsTheHole() && !HasKey(this, value)) extra++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004500 }
4501
ager@chromium.org5ec48922009-05-05 07:25:34 +00004502 if (extra == 0) return this;
4503
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004504 // Allocate the result
lrn@chromium.org303ada72010-10-27 09:33:13 +00004505 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004506 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004507 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4508 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004509 // Fill in the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004510 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004511 FixedArray* result = FixedArray::cast(obj);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004512 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513 for (int i = 0; i < len0; i++) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004514 Object* e = get(i);
4515 ASSERT(e->IsString() || e->IsNumber());
4516 result->set(i, e, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004517 }
4518 // Fill in the extra keys.
4519 int index = 0;
4520 for (int y = 0; y < len1; y++) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004521 Object* value = other->get(y);
4522 if (!value->IsTheHole() && !HasKey(this, value)) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004523 Object* e = other->get(y);
4524 ASSERT(e->IsString() || e->IsNumber());
4525 result->set(len0 + index, e, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004526 index++;
4527 }
4528 }
4529 ASSERT(extra == index);
4530 return result;
4531}
4532
4533
lrn@chromium.org303ada72010-10-27 09:33:13 +00004534MaybeObject* FixedArray::CopySize(int new_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004535 Heap* heap = GetHeap();
4536 if (new_length == 0) return heap->empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004537 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004538 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004539 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4540 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004541 FixedArray* result = FixedArray::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004542 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004543 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004544 int len = length();
4545 if (new_length < len) len = new_length;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004546 result->set_map(map());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004547 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004548 for (int i = 0; i < len; i++) {
4549 result->set(i, get(i), mode);
4550 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004551 return result;
4552}
4553
4554
4555void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004556 AssertNoAllocation no_gc;
4557 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004558 for (int index = 0; index < len; index++) {
4559 dest->set(dest_pos+index, get(pos+index), mode);
4560 }
4561}
4562
4563
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004564#ifdef DEBUG
4565bool FixedArray::IsEqualTo(FixedArray* other) {
4566 if (length() != other->length()) return false;
4567 for (int i = 0 ; i < length(); ++i) {
4568 if (get(i) != other->get(i)) return false;
4569 }
4570 return true;
4571}
4572#endif
4573
4574
lrn@chromium.org303ada72010-10-27 09:33:13 +00004575MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004576 Heap* heap = Isolate::Current()->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004577 if (number_of_descriptors == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 return heap->empty_descriptor_array();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004579 }
4580 // Allocate the array of keys.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004581 Object* array;
4582 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004583 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004584 if (!maybe_array->ToObject(&array)) return maybe_array;
4585 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004586 // Do not use DescriptorArray::cast on incomplete object.
4587 FixedArray* result = FixedArray::cast(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004588
4589 // Allocate the content array and set it in the descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004590 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004591 heap->AllocateFixedArray(number_of_descriptors << 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004592 if (!maybe_array->ToObject(&array)) return maybe_array;
4593 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004594 result->set(kBitField3StorageIndex, Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595 result->set(kContentArrayIndex, array);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004596 result->set(kEnumerationIndexIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004597 Smi::FromInt(PropertyDetails::kInitialIndex));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598 return result;
4599}
4600
4601
4602void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
4603 FixedArray* new_cache) {
4604 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4605 if (HasEnumCache()) {
4606 FixedArray::cast(get(kEnumerationIndexIndex))->
4607 set(kEnumCacheBridgeCacheIndex, new_cache);
4608 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004609 if (IsEmpty()) return; // Do nothing for empty descriptor array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610 FixedArray::cast(bridge_storage)->
4611 set(kEnumCacheBridgeCacheIndex, new_cache);
4612 fast_set(FixedArray::cast(bridge_storage),
4613 kEnumCacheBridgeEnumIndex,
4614 get(kEnumerationIndexIndex));
4615 set(kEnumerationIndexIndex, bridge_storage);
4616 }
4617}
4618
4619
lrn@chromium.org303ada72010-10-27 09:33:13 +00004620MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4621 TransitionFlag transition_flag) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004622 // Transitions are only kept when inserting another transition.
4623 // This precondition is not required by this function's implementation, but
4624 // is currently required by the semantics of maps, so we check it.
4625 // Conversely, we filter after replacing, so replacing a transition and
4626 // removing all other transitions is not supported.
4627 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
4628 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
4629 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004630
4631 // Ensure the key is a symbol.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004632 Object* result;
4633 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
4634 if (!maybe_result->ToObject(&result)) return maybe_result;
4635 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004636
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004637 int transitions = 0;
4638 int null_descriptors = 0;
4639 if (remove_transitions) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004640 for (int i = 0; i < number_of_descriptors(); i++) {
4641 if (IsTransition(i)) transitions++;
4642 if (IsNullDescriptor(i)) null_descriptors++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004643 }
4644 } else {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004645 for (int i = 0; i < number_of_descriptors(); i++) {
4646 if (IsNullDescriptor(i)) null_descriptors++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004647 }
4648 }
4649 int new_size = number_of_descriptors() - transitions - null_descriptors;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004650
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004651 // If key is in descriptor, we replace it in-place when filtering.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004652 // Count a null descriptor for key as inserted, not replaced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004653 int index = Search(descriptor->GetKey());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004654 const bool inserting = (index == kNotFound);
4655 const bool replacing = !inserting;
4656 bool keep_enumeration_index = false;
4657 if (inserting) {
4658 ++new_size;
4659 }
4660 if (replacing) {
4661 // We are replacing an existing descriptor. We keep the enumeration
4662 // index of a visible property.
4663 PropertyType t = PropertyDetails(GetDetails(index)).type();
4664 if (t == CONSTANT_FUNCTION ||
4665 t == FIELD ||
4666 t == CALLBACKS ||
4667 t == INTERCEPTOR) {
4668 keep_enumeration_index = true;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004669 } else if (remove_transitions) {
4670 // Replaced descriptor has been counted as removed if it is
4671 // a transition that will be replaced. Adjust count in this case.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004672 ++new_size;
4673 }
4674 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004675 { MaybeObject* maybe_result = Allocate(new_size);
4676 if (!maybe_result->ToObject(&result)) return maybe_result;
4677 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004678 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004679 // Set the enumeration index in the descriptors and set the enumeration index
4680 // in the result.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004681 int enumeration_index = NextEnumerationIndex();
4682 if (!descriptor->GetDetails().IsTransition()) {
4683 if (keep_enumeration_index) {
4684 descriptor->SetEnumerationIndex(
4685 PropertyDetails(GetDetails(index)).index());
4686 } else {
4687 descriptor->SetEnumerationIndex(enumeration_index);
4688 ++enumeration_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004691 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4692
4693 // Copy the descriptors, filtering out transitions and null descriptors,
4694 // and inserting or replacing a descriptor.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004695 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004696 int from_index = 0;
4697 int to_index = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004698
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004699 for (; from_index < number_of_descriptors(); from_index++) {
4700 String* key = GetKey(from_index);
4701 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4702 break;
4703 }
4704 if (IsNullDescriptor(from_index)) continue;
4705 if (remove_transitions && IsTransition(from_index)) continue;
4706 new_descriptors->CopyFrom(to_index++, this, from_index);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004707 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004708
4709 new_descriptors->Set(to_index++, descriptor);
4710 if (replacing) from_index++;
4711
4712 for (; from_index < number_of_descriptors(); from_index++) {
4713 if (IsNullDescriptor(from_index)) continue;
4714 if (remove_transitions && IsTransition(from_index)) continue;
4715 new_descriptors->CopyFrom(to_index++, this, from_index);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004716 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004717
4718 ASSERT(to_index == new_descriptors->number_of_descriptors());
4719 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004720
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004721 return new_descriptors;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722}
4723
4724
lrn@chromium.org303ada72010-10-27 09:33:13 +00004725MaybeObject* DescriptorArray::RemoveTransitions() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004726 // Remove all transitions and null descriptors. Return a copy of the array
4727 // with all transitions removed, or a Failure object if the new array could
4728 // not be allocated.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004729
4730 // Compute the size of the map transition entries to be removed.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004731 int num_removed = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004732 for (int i = 0; i < number_of_descriptors(); i++) {
4733 if (!IsProperty(i)) num_removed++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004734 }
4735
4736 // Allocate the new descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004737 Object* result;
4738 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
4739 if (!maybe_result->ToObject(&result)) return maybe_result;
4740 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004741 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4742
4743 // Copy the content.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004744 int next_descriptor = 0;
4745 for (int i = 0; i < number_of_descriptors(); i++) {
4746 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004747 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004748 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004749
4750 return new_descriptors;
4751}
4752
4753
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004754void DescriptorArray::SortUnchecked() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755 // In-place heap sort.
4756 int len = number_of_descriptors();
4757
4758 // Bottom-up max-heap construction.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004759 // Index of the last node with children
4760 const int max_parent_index = (len / 2) - 1;
4761 for (int i = max_parent_index; i >= 0; --i) {
4762 int parent_index = i;
4763 const uint32_t parent_hash = GetKey(i)->Hash();
4764 while (parent_index <= max_parent_index) {
4765 int child_index = 2 * parent_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004766 uint32_t child_hash = GetKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004767 if (child_index + 1 < len) {
4768 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4769 if (right_child_hash > child_hash) {
4770 child_index++;
4771 child_hash = right_child_hash;
4772 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004773 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004774 if (child_hash <= parent_hash) break;
4775 Swap(parent_index, child_index);
4776 // Now element at child_index could be < its children.
4777 parent_index = child_index; // parent_hash remains correct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004778 }
4779 }
4780
4781 // Extract elements and create sorted array.
4782 for (int i = len - 1; i > 0; --i) {
4783 // Put max element at the back of the array.
4784 Swap(0, i);
4785 // Sift down the new top element.
4786 int parent_index = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004787 const uint32_t parent_hash = GetKey(parent_index)->Hash();
4788 const int max_parent_index = (i / 2) - 1;
4789 while (parent_index <= max_parent_index) {
4790 int child_index = parent_index * 2 + 1;
4791 uint32_t child_hash = GetKey(child_index)->Hash();
4792 if (child_index + 1 < i) {
4793 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4794 if (right_child_hash > child_hash) {
4795 child_index++;
4796 child_hash = right_child_hash;
4797 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004799 if (child_hash <= parent_hash) break;
4800 Swap(parent_index, child_index);
4801 parent_index = child_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802 }
4803 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004804}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004805
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004806
4807void DescriptorArray::Sort() {
4808 SortUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004809 SLOW_ASSERT(IsSortedNoDuplicates());
4810}
4811
4812
4813int DescriptorArray::BinarySearch(String* name, int low, int high) {
4814 uint32_t hash = name->Hash();
4815
4816 while (low <= high) {
4817 int mid = (low + high) / 2;
4818 String* mid_name = GetKey(mid);
4819 uint32_t mid_hash = mid_name->Hash();
4820
4821 if (mid_hash > hash) {
4822 high = mid - 1;
4823 continue;
4824 }
4825 if (mid_hash < hash) {
4826 low = mid + 1;
4827 continue;
4828 }
4829 // Found an element with the same hash-code.
4830 ASSERT(hash == mid_hash);
4831 // There might be more, so we find the first one and
4832 // check them all to see if we have a match.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004833 if (name == mid_name && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004834 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
4835 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004836 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004837 }
4838 break;
4839 }
4840 return kNotFound;
4841}
4842
4843
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004844int DescriptorArray::LinearSearch(String* name, int len) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00004845 uint32_t hash = name->Hash();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004846 for (int number = 0; number < len; number++) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00004847 String* entry = GetKey(number);
4848 if ((entry->Hash() == hash) &&
4849 name->Equals(entry) &&
4850 !is_null_descriptor(number)) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004851 return number;
4852 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004853 }
4854 return kNotFound;
4855}
4856
4857
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004858MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
4859 PretenureFlag pretenure) {
4860 ASSERT(deopt_entry_count > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004861 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004862 pretenure);
4863}
4864
4865
4866MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
4867 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004868 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
4869 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004870 pretenure);
4871}
4872
4873
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004874#ifdef DEBUG
4875bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
4876 if (IsEmpty()) return other->IsEmpty();
4877 if (other->IsEmpty()) return false;
4878 if (length() != other->length()) return false;
4879 for (int i = 0; i < length(); ++i) {
4880 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
4881 }
4882 return GetContentArray()->IsEqualTo(other->GetContentArray());
4883}
4884#endif
4885
4886
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004887bool String::LooksValid() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004888 if (!Isolate::Current()->heap()->Contains(this)) return false;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004889 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890}
4891
4892
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004893int String::Utf8Length() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004894 if (IsAsciiRepresentation()) return length();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004895 // Attempt to flatten before accessing the string. It probably
4896 // doesn't make Utf8Length faster, but it is very likely that
4897 // the string will be accessed later (for example by WriteUtf8)
4898 // so it's still a good idea.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004899 Heap* heap = GetHeap();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004900 TryFlatten();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004901 Access<StringInputBuffer> buffer(
4902 heap->isolate()->objects_string_input_buffer());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004903 buffer->Reset(0, this);
4904 int result = 0;
4905 while (buffer->has_more())
4906 result += unibrow::Utf8::Length(buffer->GetNext());
4907 return result;
4908}
4909
4910
ager@chromium.org7c537e22008-10-16 08:43:32 +00004911Vector<const char> String::ToAsciiVector() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004912 ASSERT(IsAsciiRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004913 ASSERT(IsFlat());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004914
4915 int offset = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004916 int length = this->length();
4917 StringRepresentationTag string_tag = StringShape(this).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004918 String* string = this;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004919 if (string_tag == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004920 ConsString* cons = ConsString::cast(string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004921 ASSERT(cons->second()->length() == 0);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004922 string = cons->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004923 string_tag = StringShape(string).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004924 }
4925 if (string_tag == kSeqStringTag) {
4926 SeqAsciiString* seq = SeqAsciiString::cast(string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004927 char* start = seq->GetChars();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004928 return Vector<const char>(start + offset, length);
4929 }
4930 ASSERT(string_tag == kExternalStringTag);
4931 ExternalAsciiString* ext = ExternalAsciiString::cast(string);
4932 const char* start = ext->resource()->data();
4933 return Vector<const char>(start + offset, length);
4934}
4935
4936
4937Vector<const uc16> String::ToUC16Vector() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004938 ASSERT(IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004939 ASSERT(IsFlat());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004940
4941 int offset = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004942 int length = this->length();
4943 StringRepresentationTag string_tag = StringShape(this).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004944 String* string = this;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004945 if (string_tag == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004946 ConsString* cons = ConsString::cast(string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004947 ASSERT(cons->second()->length() == 0);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004948 string = cons->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004949 string_tag = StringShape(string).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004950 }
4951 if (string_tag == kSeqStringTag) {
4952 SeqTwoByteString* seq = SeqTwoByteString::cast(string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004953 return Vector<const uc16>(seq->GetChars() + offset, length);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004954 }
4955 ASSERT(string_tag == kExternalStringTag);
4956 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
4957 const uc16* start =
4958 reinterpret_cast<const uc16*>(ext->resource()->data());
4959 return Vector<const uc16>(start + offset, length);
4960}
4961
4962
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004963SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
4964 RobustnessFlag robust_flag,
4965 int offset,
4966 int length,
4967 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004968 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
4969 return SmartPointer<char>(NULL);
4970 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004971 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004972
4973 // Negative length means the to the end of the string.
4974 if (length < 0) length = kMaxInt - offset;
4975
4976 // Compute the size of the UTF-8 string. Start at the specified offset.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 Access<StringInputBuffer> buffer(
4978 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004979 buffer->Reset(offset, this);
4980 int character_position = offset;
4981 int utf8_bytes = 0;
4982 while (buffer->has_more()) {
4983 uint16_t character = buffer->GetNext();
4984 if (character_position < offset + length) {
4985 utf8_bytes += unibrow::Utf8::Length(character);
4986 }
4987 character_position++;
4988 }
4989
4990 if (length_return) {
4991 *length_return = utf8_bytes;
4992 }
4993
4994 char* result = NewArray<char>(utf8_bytes + 1);
4995
4996 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
4997 buffer->Rewind();
4998 buffer->Seek(offset);
4999 character_position = offset;
5000 int utf8_byte_position = 0;
5001 while (buffer->has_more()) {
5002 uint16_t character = buffer->GetNext();
5003 if (character_position < offset + length) {
5004 if (allow_nulls == DISALLOW_NULLS && character == 0) {
5005 character = ' ';
5006 }
5007 utf8_byte_position +=
5008 unibrow::Utf8::Encode(result + utf8_byte_position, character);
5009 }
5010 character_position++;
5011 }
5012 result[utf8_byte_position] = 0;
5013 return SmartPointer<char>(result);
5014}
5015
5016
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00005017SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5018 RobustnessFlag robust_flag,
5019 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005020 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
5021}
5022
5023
5024const uc16* String::GetTwoByteData() {
5025 return GetTwoByteData(0);
5026}
5027
5028
5029const uc16* String::GetTwoByteData(unsigned start) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005030 ASSERT(!IsAsciiRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005031 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005032 case kSeqStringTag:
ager@chromium.org7c537e22008-10-16 08:43:32 +00005033 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005034 case kExternalStringTag:
5035 return ExternalTwoByteString::cast(this)->
5036 ExternalTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005037 case kConsStringTag:
5038 UNREACHABLE();
5039 return NULL;
5040 }
5041 UNREACHABLE();
5042 return NULL;
5043}
5044
5045
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005046SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005047 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005048 return SmartPointer<uc16>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005049 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005050 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005052 Access<StringInputBuffer> buffer(
5053 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005054 buffer->Reset(this);
5055
5056 uc16* result = NewArray<uc16>(length() + 1);
5057
5058 int i = 0;
5059 while (buffer->has_more()) {
5060 uint16_t character = buffer->GetNext();
5061 result[i++] = character;
5062 }
5063 result[i] = 0;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005064 return SmartPointer<uc16>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005065}
5066
5067
ager@chromium.org7c537e22008-10-16 08:43:32 +00005068const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005069 return reinterpret_cast<uc16*>(
5070 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
5071}
5072
5073
ager@chromium.org7c537e22008-10-16 08:43:32 +00005074void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00005075 unsigned* offset_ptr,
5076 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005077 unsigned chars_read = 0;
5078 unsigned offset = *offset_ptr;
5079 while (chars_read < max_chars) {
5080 uint16_t c = *reinterpret_cast<uint16_t*>(
5081 reinterpret_cast<char*>(this) -
5082 kHeapObjectTag + kHeaderSize + offset * kShortSize);
5083 if (c <= kMaxAsciiCharCode) {
5084 // Fast case for ASCII characters. Cursor is an input output argument.
5085 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5086 rbb->util_buffer,
5087 rbb->capacity,
5088 rbb->cursor)) {
5089 break;
5090 }
5091 } else {
5092 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5093 rbb->util_buffer,
5094 rbb->capacity,
5095 rbb->cursor)) {
5096 break;
5097 }
5098 }
5099 offset++;
5100 chars_read++;
5101 }
5102 *offset_ptr = offset;
5103 rbb->remaining += chars_read;
5104}
5105
5106
ager@chromium.org7c537e22008-10-16 08:43:32 +00005107const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
5108 unsigned* remaining,
5109 unsigned* offset_ptr,
5110 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005111 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
5112 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
5113 *remaining = max_chars;
5114 *offset_ptr += max_chars;
5115 return b;
5116}
5117
5118
5119// This will iterate unless the block of string data spans two 'halves' of
5120// a ConsString, in which case it will recurse. Since the block of string
5121// data to be read has a maximum size this limits the maximum recursion
5122// depth to something sane. Since C++ does not have tail call recursion
5123// elimination, the iteration must be explicit. Since this is not an
5124// -IntoBuffer method it can delegate to one of the efficient
5125// *AsciiStringReadBlock routines.
5126const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
5127 unsigned* offset_ptr,
5128 unsigned max_chars) {
5129 ConsString* current = this;
5130 unsigned offset = *offset_ptr;
5131 int offset_correction = 0;
5132
5133 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005134 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005135 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005136 if (left_length > offset &&
5137 (max_chars <= left_length - offset ||
5138 (rbb->capacity <= left_length - offset &&
5139 (max_chars = left_length - offset, true)))) { // comma operator!
5140 // Left hand side only - iterate unless we have reached the bottom of
5141 // the cons tree. The assignment on the left of the comma operator is
5142 // in order to make use of the fact that the -IntoBuffer routines can
5143 // produce at most 'capacity' characters. This enables us to postpone
5144 // the point where we switch to the -IntoBuffer routines (below) in order
5145 // to maximize the chances of delegating a big chunk of work to the
5146 // efficient *AsciiStringReadBlock routines.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005147 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005148 current = ConsString::cast(left);
5149 continue;
5150 } else {
5151 const unibrow::byte* answer =
5152 String::ReadBlock(left, rbb, &offset, max_chars);
5153 *offset_ptr = offset + offset_correction;
5154 return answer;
5155 }
5156 } else if (left_length <= offset) {
5157 // Right hand side only - iterate unless we have reached the bottom of
5158 // the cons tree.
ager@chromium.org870a0b62008-11-04 11:43:05 +00005159 String* right = current->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005160 offset -= left_length;
5161 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005162 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005163 current = ConsString::cast(right);
5164 continue;
5165 } else {
5166 const unibrow::byte* answer =
5167 String::ReadBlock(right, rbb, &offset, max_chars);
5168 *offset_ptr = offset + offset_correction;
5169 return answer;
5170 }
5171 } else {
5172 // The block to be read spans two sides of the ConsString, so we call the
5173 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
5174 // are able to assemble data from several part strings because they use
5175 // the util_buffer to store their data and never return direct pointers
5176 // to their storage. We don't try to read more than the buffer capacity
5177 // here or we can get too much recursion.
5178 ASSERT(rbb->remaining == 0);
5179 ASSERT(rbb->cursor == 0);
5180 current->ConsStringReadBlockIntoBuffer(
5181 rbb,
5182 &offset,
5183 max_chars > rbb->capacity ? rbb->capacity : max_chars);
5184 *offset_ptr = offset + offset_correction;
5185 return rbb->util_buffer;
5186 }
5187 }
5188}
5189
5190
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005191uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
5192 ASSERT(index >= 0 && index < length());
5193 return resource()->data()[index];
5194}
5195
5196
5197const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
5198 unsigned* remaining,
5199 unsigned* offset_ptr,
5200 unsigned max_chars) {
5201 // Cast const char* to unibrow::byte* (signedness difference).
5202 const unibrow::byte* b =
5203 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
5204 *remaining = max_chars;
5205 *offset_ptr += max_chars;
5206 return b;
5207}
5208
5209
5210const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
5211 unsigned start) {
5212 return resource()->data() + start;
5213}
5214
5215
5216uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
5217 ASSERT(index >= 0 && index < length());
5218 return resource()->data()[index];
5219}
5220
5221
5222void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
5223 ReadBlockBuffer* rbb,
5224 unsigned* offset_ptr,
5225 unsigned max_chars) {
5226 unsigned chars_read = 0;
5227 unsigned offset = *offset_ptr;
5228 const uint16_t* data = resource()->data();
5229 while (chars_read < max_chars) {
5230 uint16_t c = data[offset];
5231 if (c <= kMaxAsciiCharCode) {
ager@chromium.org80787b72009-04-17 10:24:24 +00005232 // Fast case for ASCII characters. Cursor is an input output argument.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005233 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5234 rbb->util_buffer,
5235 rbb->capacity,
5236 rbb->cursor))
5237 break;
5238 } else {
5239 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5240 rbb->util_buffer,
5241 rbb->capacity,
5242 rbb->cursor))
5243 break;
5244 }
5245 offset++;
5246 chars_read++;
5247 }
5248 *offset_ptr = offset;
5249 rbb->remaining += chars_read;
5250}
5251
5252
ager@chromium.org7c537e22008-10-16 08:43:32 +00005253void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005254 unsigned* offset_ptr,
5255 unsigned max_chars) {
5256 unsigned capacity = rbb->capacity - rbb->cursor;
5257 if (max_chars > capacity) max_chars = capacity;
5258 memcpy(rbb->util_buffer + rbb->cursor,
5259 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
5260 *offset_ptr * kCharSize,
5261 max_chars);
5262 rbb->remaining += max_chars;
5263 *offset_ptr += max_chars;
5264 rbb->cursor += max_chars;
5265}
5266
5267
5268void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
5269 ReadBlockBuffer* rbb,
5270 unsigned* offset_ptr,
5271 unsigned max_chars) {
5272 unsigned capacity = rbb->capacity - rbb->cursor;
5273 if (max_chars > capacity) max_chars = capacity;
5274 memcpy(rbb->util_buffer + rbb->cursor,
5275 resource()->data() + *offset_ptr,
5276 max_chars);
5277 rbb->remaining += max_chars;
5278 *offset_ptr += max_chars;
5279 rbb->cursor += max_chars;
5280}
5281
5282
5283// This method determines the type of string involved and then copies
5284// a whole chunk of characters into a buffer, or returns a pointer to a buffer
5285// where they can be found. The pointer is not necessarily valid across a GC
5286// (see AsciiStringReadBlock).
5287const unibrow::byte* String::ReadBlock(String* input,
5288 ReadBlockBuffer* rbb,
5289 unsigned* offset_ptr,
5290 unsigned max_chars) {
5291 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
5292 if (max_chars == 0) {
5293 rbb->remaining = 0;
5294 return NULL;
5295 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005296 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005297 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005298 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005299 SeqAsciiString* str = SeqAsciiString::cast(input);
5300 return str->SeqAsciiStringReadBlock(&rbb->remaining,
5301 offset_ptr,
5302 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005303 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005304 SeqTwoByteString* str = SeqTwoByteString::cast(input);
5305 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5306 offset_ptr,
5307 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005308 return rbb->util_buffer;
5309 }
5310 case kConsStringTag:
5311 return ConsString::cast(input)->ConsStringReadBlock(rbb,
5312 offset_ptr,
5313 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005314 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005315 if (input->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005316 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
5317 &rbb->remaining,
5318 offset_ptr,
5319 max_chars);
5320 } else {
5321 ExternalTwoByteString::cast(input)->
5322 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5323 offset_ptr,
5324 max_chars);
5325 return rbb->util_buffer;
5326 }
5327 default:
5328 break;
5329 }
5330
5331 UNREACHABLE();
5332 return 0;
5333}
5334
5335
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005336void Relocatable::PostGarbageCollectionProcessing() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005337 Isolate* isolate = Isolate::Current();
5338 Relocatable* current = isolate->relocatable_top();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005339 while (current != NULL) {
5340 current->PostGarbageCollection();
5341 current = current->prev_;
5342 }
5343}
5344
5345
5346// Reserve space for statics needing saving and restoring.
5347int Relocatable::ArchiveSpacePerThread() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005348 return sizeof(Isolate::Current()->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005349}
5350
5351
5352// Archive statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005353char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005354 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
5355 isolate->set_relocatable_top(NULL);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005356 return to + ArchiveSpacePerThread();
5357}
5358
5359
5360// Restore statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005361char* Relocatable::RestoreState(Isolate* isolate, char* from) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005362 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005363 return from + ArchiveSpacePerThread();
5364}
5365
5366
5367char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
5368 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
5369 Iterate(v, top);
5370 return thread_storage + ArchiveSpacePerThread();
5371}
5372
5373
5374void Relocatable::Iterate(ObjectVisitor* v) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005375 Isolate* isolate = Isolate::Current();
5376 Iterate(v, isolate->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005377}
5378
5379
5380void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
5381 Relocatable* current = top;
5382 while (current != NULL) {
5383 current->IterateInstance(v);
5384 current = current->prev_;
5385 }
5386}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005387
5388
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005389FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
5390 : Relocatable(isolate),
5391 str_(str.location()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005392 length_(str->length()) {
5393 PostGarbageCollection();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005394}
5395
5396
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005397FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
5398 : Relocatable(isolate),
5399 str_(0),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005400 is_ascii_(true),
5401 length_(input.length()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005402 start_(input.start()) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005403
5404
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005405void FlatStringReader::PostGarbageCollection() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005406 if (str_ == NULL) return;
5407 Handle<String> str(str_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005408 ASSERT(str->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00005409 is_ascii_ = str->IsAsciiRepresentation();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005410 if (is_ascii_) {
5411 start_ = str->ToAsciiVector().start();
5412 } else {
5413 start_ = str->ToUC16Vector().start();
5414 }
5415}
5416
5417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005418void StringInputBuffer::Seek(unsigned pos) {
5419 Reset(pos, input_);
5420}
5421
5422
5423void SafeStringInputBuffer::Seek(unsigned pos) {
5424 Reset(pos, input_);
5425}
5426
5427
5428// This method determines the type of string involved and then copies
5429// a whole chunk of characters into a buffer. It can be used with strings
5430// that have been glued together to form a ConsString and which must cooperate
5431// to fill up a buffer.
5432void String::ReadBlockIntoBuffer(String* input,
5433 ReadBlockBuffer* rbb,
5434 unsigned* offset_ptr,
5435 unsigned max_chars) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005436 ASSERT(*offset_ptr <= (unsigned)input->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005437 if (max_chars == 0) return;
5438
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005440 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005441 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005442 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005443 offset_ptr,
5444 max_chars);
5445 return;
5446 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005447 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005448 offset_ptr,
5449 max_chars);
5450 return;
5451 }
5452 case kConsStringTag:
5453 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5454 offset_ptr,
5455 max_chars);
5456 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005458 if (input->IsAsciiRepresentation()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005459 ExternalAsciiString::cast(input)->
5460 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5461 } else {
5462 ExternalTwoByteString::cast(input)->
5463 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5464 offset_ptr,
5465 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005466 }
5467 return;
5468 default:
5469 break;
5470 }
5471
5472 UNREACHABLE();
5473 return;
5474}
5475
5476
5477const unibrow::byte* String::ReadBlock(String* input,
5478 unibrow::byte* util_buffer,
5479 unsigned capacity,
5480 unsigned* remaining,
5481 unsigned* offset_ptr) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005482 ASSERT(*offset_ptr <= (unsigned)input->length());
5483 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005484 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5485 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005486 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005487 *remaining = rbb.remaining;
5488 return answer;
5489}
5490
5491
5492const unibrow::byte* String::ReadBlock(String** raw_input,
5493 unibrow::byte* util_buffer,
5494 unsigned capacity,
5495 unsigned* remaining,
5496 unsigned* offset_ptr) {
5497 Handle<String> input(raw_input);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005498 ASSERT(*offset_ptr <= (unsigned)input->length());
5499 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005500 if (chars > capacity) chars = capacity;
5501 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5502 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005503 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 *remaining = rbb.remaining;
5505 return rbb.util_buffer;
5506}
5507
5508
5509// This will iterate unless the block of string data spans two 'halves' of
5510// a ConsString, in which case it will recurse. Since the block of string
5511// data to be read has a maximum size this limits the maximum recursion
5512// depth to something sane. Since C++ does not have tail call recursion
5513// elimination, the iteration must be explicit.
5514void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5515 unsigned* offset_ptr,
5516 unsigned max_chars) {
5517 ConsString* current = this;
5518 unsigned offset = *offset_ptr;
5519 int offset_correction = 0;
5520
5521 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005522 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005523 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005524 if (left_length > offset &&
5525 max_chars <= left_length - offset) {
5526 // Left hand side only - iterate unless we have reached the bottom of
5527 // the cons tree.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005528 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005529 current = ConsString::cast(left);
5530 continue;
5531 } else {
5532 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5533 *offset_ptr = offset + offset_correction;
5534 return;
5535 }
5536 } else if (left_length <= offset) {
5537 // Right hand side only - iterate unless we have reached the bottom of
5538 // the cons tree.
5539 offset -= left_length;
5540 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005541 String* right = current->second();
5542 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005543 current = ConsString::cast(right);
5544 continue;
5545 } else {
5546 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5547 *offset_ptr = offset + offset_correction;
5548 return;
5549 }
5550 } else {
5551 // The block to be read spans two sides of the ConsString, so we recurse.
5552 // First recurse on the left.
5553 max_chars -= left_length - offset;
5554 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5555 // We may have reached the max or there may not have been enough space
5556 // in the buffer for the characters in the left hand side.
5557 if (offset == left_length) {
5558 // Recurse on the right.
5559 String* right = String::cast(current->second());
5560 offset -= left_length;
5561 offset_correction += left_length;
5562 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5563 }
5564 *offset_ptr = offset + offset_correction;
5565 return;
5566 }
5567 }
5568}
5569
5570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005571uint16_t ConsString::ConsStringGet(int index) {
5572 ASSERT(index >= 0 && index < this->length());
5573
5574 // Check for a flattened cons string
ager@chromium.org870a0b62008-11-04 11:43:05 +00005575 if (second()->length() == 0) {
5576 String* left = first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005577 return left->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005578 }
5579
5580 String* string = String::cast(this);
5581
5582 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005583 if (StringShape(string).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005584 ConsString* cons_string = ConsString::cast(string);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005585 String* left = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005586 if (left->length() > index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005587 string = left;
5588 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005589 index -= left->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005590 string = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005591 }
5592 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005593 return string->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005594 }
5595 }
5596
5597 UNREACHABLE();
5598 return 0;
5599}
5600
5601
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005602template <typename sinkchar>
5603void String::WriteToFlat(String* src,
5604 sinkchar* sink,
5605 int f,
5606 int t) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 String* source = src;
5608 int from = f;
5609 int to = t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005610 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005611 ASSERT(0 <= from && from <= to && to <= source->length());
5612 switch (StringShape(source).full_representation_tag()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005613 case kAsciiStringTag | kExternalStringTag: {
5614 CopyChars(sink,
5615 ExternalAsciiString::cast(source)->resource()->data() + from,
5616 to - from);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005617 return;
5618 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005619 case kTwoByteStringTag | kExternalStringTag: {
5620 const uc16* data =
5621 ExternalTwoByteString::cast(source)->resource()->data();
5622 CopyChars(sink,
5623 data + from,
5624 to - from);
5625 return;
5626 }
5627 case kAsciiStringTag | kSeqStringTag: {
5628 CopyChars(sink,
5629 SeqAsciiString::cast(source)->GetChars() + from,
5630 to - from);
5631 return;
5632 }
5633 case kTwoByteStringTag | kSeqStringTag: {
5634 CopyChars(sink,
5635 SeqTwoByteString::cast(source)->GetChars() + from,
5636 to - from);
5637 return;
5638 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005639 case kAsciiStringTag | kConsStringTag:
5640 case kTwoByteStringTag | kConsStringTag: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005641 ConsString* cons_string = ConsString::cast(source);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005642 String* first = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005643 int boundary = first->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005644 if (to - boundary >= boundary - from) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005645 // Right hand side is longer. Recurse over left.
5646 if (from < boundary) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005647 WriteToFlat(first, sink, from, boundary);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005648 sink += boundary - from;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005649 from = 0;
5650 } else {
5651 from -= boundary;
5652 }
5653 to -= boundary;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005654 source = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005655 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005656 // Left hand side is longer. Recurse over right.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005657 if (to > boundary) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005658 String* second = cons_string->second();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005659 WriteToFlat(second,
5660 sink + boundary - from,
5661 0,
5662 to - boundary);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005663 to = boundary;
5664 }
5665 source = first;
5666 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005667 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005668 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005669 }
5670 }
5671}
5672
5673
ager@chromium.org7c537e22008-10-16 08:43:32 +00005674template <typename IteratorA, typename IteratorB>
5675static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5676 // General slow case check. We know that the ia and ib iterators
5677 // have the same length.
5678 while (ia->has_more()) {
5679 uc32 ca = ia->GetNext();
5680 uc32 cb = ib->GetNext();
5681 if (ca != cb)
5682 return false;
5683 }
5684 return true;
5685}
5686
5687
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005688// Compares the contents of two strings by reading and comparing
5689// int-sized blocks of characters.
5690template <typename Char>
5691static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5692 int length = a.length();
5693 ASSERT_EQ(length, b.length());
5694 const Char* pa = a.start();
5695 const Char* pb = b.start();
5696 int i = 0;
ager@chromium.org9085a012009-05-11 19:22:57 +00005697#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005698 // If this architecture isn't comfortable reading unaligned ints
5699 // then we have to check that the strings are aligned before
5700 // comparing them blockwise.
5701 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5702 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5703 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005704 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005705#endif
5706 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5707 int endpoint = length - kStepSize;
5708 // Compare blocks until we reach near the end of the string.
5709 for (; i <= endpoint; i += kStepSize) {
5710 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5711 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5712 if (wa != wb) {
5713 return false;
5714 }
5715 }
ager@chromium.org9085a012009-05-11 19:22:57 +00005716#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005717 }
5718#endif
5719 // Compare the remaining characters that didn't fit into a block.
5720 for (; i < length; i++) {
5721 if (a[i] != b[i]) {
5722 return false;
5723 }
5724 }
5725 return true;
5726}
5727
5728
ager@chromium.org7c537e22008-10-16 08:43:32 +00005729template <typename IteratorA>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005730static inline bool CompareStringContentsPartial(Isolate* isolate,
5731 IteratorA* ia,
5732 String* b) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005733 if (b->IsFlat()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005734 if (b->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005735 VectorIterator<char> ib(b->ToAsciiVector());
5736 return CompareStringContents(ia, &ib);
5737 } else {
ager@chromium.org9085a012009-05-11 19:22:57 +00005738 VectorIterator<uc16> ib(b->ToUC16Vector());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005739 return CompareStringContents(ia, &ib);
5740 }
5741 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005742 isolate->objects_string_compare_buffer_b()->Reset(0, b);
5743 return CompareStringContents(ia,
5744 isolate->objects_string_compare_buffer_b());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005745 }
5746}
5747
5748
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005749bool String::SlowEquals(String* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005750 // Fast check: negative check with lengths.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005751 int len = length();
5752 if (len != other->length()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005753 if (len == 0) return true;
5754
5755 // Fast check: if hash code is computed for both strings
5756 // a fast negative check can be performed.
5757 if (HasHashCode() && other->HasHashCode()) {
5758 if (Hash() != other->Hash()) return false;
5759 }
5760
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005761 // We know the strings are both non-empty. Compare the first chars
5762 // before we try to flatten the strings.
5763 if (this->Get(0) != other->Get(0)) return false;
5764
5765 String* lhs = this->TryFlattenGetString();
5766 String* rhs = other->TryFlattenGetString();
5767
5768 if (StringShape(lhs).IsSequentialAscii() &&
5769 StringShape(rhs).IsSequentialAscii()) {
5770 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
5771 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005772 return CompareRawStringContents(Vector<const char>(str1, len),
5773 Vector<const char>(str2, len));
5774 }
5775
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005776 Isolate* isolate = GetIsolate();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005777 if (lhs->IsFlat()) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00005778 if (lhs->IsAsciiRepresentation()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005779 Vector<const char> vec1 = lhs->ToAsciiVector();
5780 if (rhs->IsFlat()) {
5781 if (rhs->IsAsciiRepresentation()) {
5782 Vector<const char> vec2 = rhs->ToAsciiVector();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005783 return CompareRawStringContents(vec1, vec2);
5784 } else {
5785 VectorIterator<char> buf1(vec1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005786 VectorIterator<uc16> ib(rhs->ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005787 return CompareStringContents(&buf1, &ib);
5788 }
5789 } else {
5790 VectorIterator<char> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005791 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5792 return CompareStringContents(&buf1,
5793 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005794 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005795 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005796 Vector<const uc16> vec1 = lhs->ToUC16Vector();
5797 if (rhs->IsFlat()) {
5798 if (rhs->IsAsciiRepresentation()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005799 VectorIterator<uc16> buf1(vec1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005800 VectorIterator<char> ib(rhs->ToAsciiVector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005801 return CompareStringContents(&buf1, &ib);
5802 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005803 Vector<const uc16> vec2(rhs->ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005804 return CompareRawStringContents(vec1, vec2);
5805 }
5806 } else {
5807 VectorIterator<uc16> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005808 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5809 return CompareStringContents(&buf1,
5810 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005811 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005812 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005813 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005814 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
5815 return CompareStringContentsPartial(isolate,
5816 isolate->objects_string_compare_buffer_a(), rhs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005817 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005818}
5819
5820
5821bool String::MarkAsUndetectable() {
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005822 if (StringShape(this).IsSymbol()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005823
5824 Map* map = this->map();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005825 Heap* heap = map->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005826 if (map == heap->string_map()) {
5827 this->set_map(heap->undetectable_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005828 return true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005829 } else if (map == heap->ascii_string_map()) {
5830 this->set_map(heap->undetectable_ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005831 return true;
5832 }
5833 // Rest cannot be marked as undetectable
5834 return false;
5835}
5836
5837
5838bool String::IsEqualTo(Vector<const char> str) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005839 Isolate* isolate = GetIsolate();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005840 int slen = length();
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005841 Access<UnicodeCache::Utf8Decoder>
5842 decoder(isolate->unicode_cache()->utf8_decoder());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005843 decoder->Reset(str.start(), str.length());
5844 int i;
5845 for (i = 0; i < slen && decoder->has_more(); i++) {
5846 uc32 r = decoder->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005847 if (Get(i) != r) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005848 }
5849 return i == slen && !decoder->has_more();
5850}
5851
5852
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005853bool String::IsAsciiEqualTo(Vector<const char> str) {
5854 int slen = length();
5855 if (str.length() != slen) return false;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005856 if (IsFlat() && IsAsciiRepresentation()) {
5857 return CompareChars(ToAsciiVector().start(), str.start(), slen) == 0;
5858 }
5859 for (int i = 0; i < slen; i++) {
5860 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005861 }
5862 return true;
5863}
5864
5865
5866bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
5867 int slen = length();
5868 if (str.length() != slen) return false;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005869 if (IsFlat() && IsTwoByteRepresentation()) {
5870 return CompareChars(ToUC16Vector().start(), str.start(), slen) == 0;
5871 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005872 for (int i = 0; i < slen; i++) {
5873 if (Get(i) != str[i]) return false;
5874 }
5875 return true;
5876}
5877
5878
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005879uint32_t String::ComputeAndSetHash() {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005880 // Should only be called if hash code has not yet been computed.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005881 ASSERT(!HasHashCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005882
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00005883 const int len = length();
5884
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005885 // Compute the hash code.
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00005886 uint32_t field = 0;
5887 if (StringShape(this).IsSequentialAscii()) {
5888 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
5889 } else if (StringShape(this).IsSequentialTwoByte()) {
5890 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
5891 } else {
5892 StringInputBuffer buffer(this);
5893 field = ComputeHashField(&buffer, len);
5894 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895
5896 // Store the hash code in the object.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005897 set_hash_field(field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005898
5899 // Check the hash code is there.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005900 ASSERT(HasHashCode());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005901 uint32_t result = field >> kHashShift;
5902 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
5903 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005904}
5905
5906
5907bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
5908 uint32_t* index,
5909 int length) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005910 if (length == 0 || length > kMaxArrayIndexSize) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911 uc32 ch = buffer->GetNext();
5912
5913 // If the string begins with a '0' character, it must only consist
5914 // of it to be a legal array index.
5915 if (ch == '0') {
5916 *index = 0;
5917 return length == 1;
5918 }
5919
5920 // Convert string to uint32 array index; character by character.
5921 int d = ch - '0';
5922 if (d < 0 || d > 9) return false;
5923 uint32_t result = d;
5924 while (buffer->has_more()) {
5925 d = buffer->GetNext() - '0';
5926 if (d < 0 || d > 9) return false;
5927 // Check that the new result is below the 32 bit limit.
5928 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
5929 result = (result * 10) + d;
5930 }
5931
5932 *index = result;
5933 return true;
5934}
5935
5936
5937bool String::SlowAsArrayIndex(uint32_t* index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005938 if (length() <= kMaxCachedArrayIndexLength) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005939 Hash(); // force computation of hash code
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005940 uint32_t field = hash_field();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00005941 if ((field & kIsNotArrayIndexMask) != 0) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005942 // Isolate the array index form the full hash field.
5943 *index = (kArrayIndexHashMask & field) >> kHashShift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005944 return true;
5945 } else {
5946 StringInputBuffer buffer(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005947 return ComputeArrayIndex(&buffer, index, length());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005948 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005949}
5950
5951
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005952uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005953 // For array indexes mix the length into the hash as an array index could
5954 // be zero.
5955 ASSERT(length > 0);
5956 ASSERT(length <= String::kMaxArrayIndexSize);
5957 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
5958 (1 << String::kArrayIndexValueBits));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005959
5960 value <<= String::kHashShift;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005961 value |= length << String::kArrayIndexHashLengthShift;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005962
5963 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
5964 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
5965 (value & String::kContainsCachedArrayIndexMask) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005966 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967}
5968
5969
ager@chromium.org7c537e22008-10-16 08:43:32 +00005970uint32_t StringHasher::GetHashField() {
5971 ASSERT(is_valid());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005972 if (length_ <= String::kMaxHashCalcLength) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005973 if (is_array_index()) {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005974 return MakeArrayIndexHash(array_index(), length_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005975 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005976 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005977 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005978 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005980}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005983uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
5984 int length) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005985 StringHasher hasher(length);
5986
5987 // Very long strings have a trivial hash that doesn't inspect the
5988 // string contents.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005989 if (hasher.has_trivial_hash()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005990 return hasher.GetHashField();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005991 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005992
5993 // Do the iterative array index computation as long as there is a
5994 // chance this is an array index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005995 while (buffer->has_more() && hasher.is_array_index()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005996 hasher.AddCharacter(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005997 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005998
5999 // Process the remaining characters without updating the array
6000 // index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006001 while (buffer->has_more()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006002 hasher.AddCharacterNoIndex(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006003 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006004
6005 return hasher.GetHashField();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006006}
6007
6008
lrn@chromium.org303ada72010-10-27 09:33:13 +00006009MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006010 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006011 if (start == 0 && end == length()) return this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006012 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006013 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006014}
6015
6016
6017void String::PrintOn(FILE* file) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006018 int length = this->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019 for (int i = 0; i < length; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006020 fprintf(file, "%c", Get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006021 }
6022}
6023
6024
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006025void Map::CreateBackPointers() {
6026 DescriptorArray* descriptors = instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006027 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006028 if (descriptors->GetType(i) == MAP_TRANSITION ||
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006029 descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006030 descriptors->GetType(i) == CONSTANT_TRANSITION) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006031 // Get target.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006032 Map* target = Map::cast(descriptors->GetValue(i));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006033#ifdef DEBUG
6034 // Verify target.
6035 Object* source_prototype = prototype();
6036 Object* target_prototype = target->prototype();
6037 ASSERT(source_prototype->IsJSObject() ||
6038 source_prototype->IsMap() ||
6039 source_prototype->IsNull());
6040 ASSERT(target_prototype->IsJSObject() ||
6041 target_prototype->IsNull());
6042 ASSERT(source_prototype->IsMap() ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006043 source_prototype == target_prototype);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006044#endif
6045 // Point target back to source. set_prototype() will not let us set
6046 // the prototype to a map, as we do here.
6047 *RawField(target, kPrototypeOffset) = this;
6048 }
6049 }
6050}
6051
6052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006053void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006054 // Live DescriptorArray objects will be marked, so we must use
6055 // low-level accessors to get and modify their data.
6056 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
danno@chromium.org40cb8782011-05-25 07:58:50 +00006057 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
6058 if (d->IsEmpty()) return;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006059 Smi* NullDescriptorDetails =
6060 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
6061 FixedArray* contents = reinterpret_cast<FixedArray*>(
6062 d->get(DescriptorArray::kContentArrayIndex));
6063 ASSERT(contents->length() >= 2);
6064 for (int i = 0; i < contents->length(); i += 2) {
6065 // If the pair (value, details) is a map transition,
6066 // check if the target is live. If not, null the descriptor.
6067 // Also drop the back pointer for that map transition, so that this
6068 // map is not reached again by following a back pointer from a
6069 // non-live object.
6070 PropertyDetails details(Smi::cast(contents->get(i + 1)));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006071 if (details.type() == MAP_TRANSITION ||
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006072 details.type() == EXTERNAL_ARRAY_TRANSITION ||
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006073 details.type() == CONSTANT_TRANSITION) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006074 Map* target = reinterpret_cast<Map*>(contents->get(i));
6075 ASSERT(target->IsHeapObject());
6076 if (!target->IsMarked()) {
6077 ASSERT(target->IsMap());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006078 contents->set_unchecked(i + 1, NullDescriptorDetails);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006079 contents->set_null_unchecked(heap, i);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006080 ASSERT(target->prototype() == this ||
6081 target->prototype() == real_prototype);
6082 // Getter prototype() is read-only, set_prototype() has side effects.
6083 *RawField(target, Map::kPrototypeOffset) = real_prototype;
6084 }
6085 }
6086 }
6087}
6088
6089
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00006090int Map::Hash() {
6091 // For performance reasons we only hash the 3 most variable fields of a map:
6092 // constructor, prototype and bit_field2.
6093
6094 // Shift away the tag.
6095 int hash = (static_cast<uint32_t>(
6096 reinterpret_cast<uintptr_t>(constructor())) >> 2);
6097
6098 // XOR-ing the prototype and constructor directly yields too many zero bits
6099 // when the two pointers are close (which is fairly common).
6100 // To avoid this we shift the prototype 4 bits relatively to the constructor.
6101 hash ^= (static_cast<uint32_t>(
6102 reinterpret_cast<uintptr_t>(prototype())) << 2);
6103
6104 return hash ^ (hash >> 16) ^ bit_field2();
6105}
6106
6107
6108bool Map::EquivalentToForNormalization(Map* other,
6109 PropertyNormalizationMode mode) {
6110 return
6111 constructor() == other->constructor() &&
6112 prototype() == other->prototype() &&
6113 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
6114 0 :
6115 other->inobject_properties()) &&
6116 instance_type() == other->instance_type() &&
6117 bit_field() == other->bit_field() &&
6118 bit_field2() == other->bit_field2() &&
6119 (bit_field3() & ~(1<<Map::kIsShared)) ==
6120 (other->bit_field3() & ~(1<<Map::kIsShared));
6121}
6122
6123
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00006124void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
6125 // Iterate over all fields in the body but take care in dealing with
6126 // the code entry.
6127 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
6128 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
6129 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
6130}
6131
6132
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006133void JSFunction::MarkForLazyRecompilation() {
6134 ASSERT(is_compiled() && !IsOptimized());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006135 ASSERT(shared()->allows_lazy_compilation() ||
6136 code()->optimizable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006137 Builtins* builtins = GetIsolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006138 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006139}
6140
6141
6142uint32_t JSFunction::SourceHash() {
6143 uint32_t hash = 0;
6144 Object* script = shared()->script();
6145 if (!script->IsUndefined()) {
6146 Object* source = Script::cast(script)->source();
6147 if (source->IsUndefined()) hash = String::cast(source)->Hash();
6148 }
6149 hash ^= ComputeIntegerHash(shared()->start_position_and_type());
6150 hash += ComputeIntegerHash(shared()->end_position());
6151 return hash;
6152}
6153
6154
6155bool JSFunction::IsInlineable() {
6156 if (IsBuiltin()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00006157 SharedFunctionInfo* shared_info = shared();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006158 // Check that the function has a script associated with it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00006159 if (!shared_info->script()->IsScript()) return false;
6160 if (shared_info->optimization_disabled()) return false;
6161 Code* code = shared_info->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006162 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
6163 // If we never ran this (unlikely) then lets try to optimize it.
6164 if (code->kind() != Code::FUNCTION) return true;
6165 return code->optimizable();
6166}
6167
6168
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006169Object* JSFunction::SetInstancePrototype(Object* value) {
6170 ASSERT(value->IsJSObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006171 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006172 if (has_initial_map()) {
6173 initial_map()->set_prototype(value);
6174 } else {
6175 // Put the value in the initial map field until an initial map is
6176 // needed. At that point, a new initial map is created and the
6177 // prototype is put into the initial map where it belongs.
6178 set_prototype_or_initial_map(value);
6179 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006180 heap->ClearInstanceofCache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006181 return value;
6182}
6183
6184
lrn@chromium.org303ada72010-10-27 09:33:13 +00006185MaybeObject* JSFunction::SetPrototype(Object* value) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006186 ASSERT(should_have_prototype());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006187 Object* construct_prototype = value;
6188
6189 // If the value is not a JSObject, store the value in the map's
6190 // constructor field so it can be accessed. Also, set the prototype
6191 // used for constructing objects to the original object prototype.
6192 // See ECMA-262 13.2.2.
6193 if (!value->IsJSObject()) {
6194 // Copy the map so this does not affect unrelated functions.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006195 // Remove map transitions because they point to maps with a
6196 // different prototype.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006197 Object* new_object;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006198 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006199 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006200 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006201 Map* new_map = Map::cast(new_object);
6202 Heap* heap = new_map->heap();
6203 set_map(new_map);
6204 new_map->set_constructor(value);
6205 new_map->set_non_instance_prototype(true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006206 construct_prototype =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006207 heap->isolate()->context()->global_context()->
6208 initial_object_prototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006209 } else {
6210 map()->set_non_instance_prototype(false);
6211 }
6212
6213 return SetInstancePrototype(construct_prototype);
6214}
6215
6216
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006217Object* JSFunction::RemovePrototype() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006218 Context* global_context = context()->global_context();
6219 Map* no_prototype_map = shared()->strict_mode()
6220 ? global_context->strict_mode_function_without_prototype_map()
6221 : global_context->function_without_prototype_map();
6222
6223 if (map() == no_prototype_map) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006224 // Be idempotent.
6225 return this;
6226 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006227
6228 ASSERT(!shared()->strict_mode() ||
6229 map() == global_context->strict_mode_function_map());
6230 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
6231
6232 set_map(no_prototype_map);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006233 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006234 return this;
6235}
6236
6237
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006238Object* JSFunction::SetInstanceClassName(String* name) {
6239 shared()->set_instance_class_name(name);
6240 return this;
6241}
6242
6243
whesse@chromium.org023421e2010-12-21 12:19:12 +00006244void JSFunction::PrintName(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006245 SmartPointer<char> name = shared()->DebugName()->ToCString();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006246 PrintF(out, "%s", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006247}
6248
6249
ager@chromium.org236ad962008-09-25 09:45:57 +00006250Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
6251 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
6252}
6253
6254
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006255MaybeObject* Oddball::Initialize(const char* to_string,
6256 Object* to_number,
6257 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006258 Object* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006259 { MaybeObject* maybe_symbol =
6260 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006261 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
6262 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006263 set_to_string(String::cast(symbol));
6264 set_to_number(to_number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006265 set_kind(kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266 return this;
6267}
6268
6269
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006270String* SharedFunctionInfo::DebugName() {
6271 Object* n = name();
6272 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
6273 return String::cast(n);
6274}
6275
6276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006277bool SharedFunctionInfo::HasSourceCode() {
6278 return !script()->IsUndefined() &&
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006279 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006280}
6281
6282
6283Object* SharedFunctionInfo::GetSourceCode() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006284 Isolate* isolate = GetIsolate();
6285 if (!HasSourceCode()) return isolate->heap()->undefined_value();
6286 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006287 Object* source = Script::cast(script())->source();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006288 return *SubString(Handle<String>(String::cast(source), isolate),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006289 start_position(), end_position());
6290}
6291
6292
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006293int SharedFunctionInfo::SourceSize() {
6294 return end_position() - start_position();
6295}
6296
6297
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006298int SharedFunctionInfo::CalculateInstanceSize() {
6299 int instance_size =
6300 JSObject::kHeaderSize +
6301 expected_nof_properties() * kPointerSize;
6302 if (instance_size > JSObject::kMaxInstanceSize) {
6303 instance_size = JSObject::kMaxInstanceSize;
6304 }
6305 return instance_size;
6306}
6307
6308
6309int SharedFunctionInfo::CalculateInObjectProperties() {
6310 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
6311}
6312
6313
ager@chromium.org5c838252010-02-19 08:53:10 +00006314bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
6315 // Check the basic conditions for generating inline constructor code.
6316 if (!FLAG_inline_new
6317 || !has_only_simple_this_property_assignments()
6318 || this_property_assignments_count() == 0) {
6319 return false;
6320 }
6321
6322 // If the prototype is null inline constructors cause no problems.
6323 if (!prototype->IsJSObject()) {
6324 ASSERT(prototype->IsNull());
6325 return true;
6326 }
6327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006328 Heap* heap = GetHeap();
6329
ager@chromium.org5c838252010-02-19 08:53:10 +00006330 // Traverse the proposed prototype chain looking for setters for properties of
6331 // the same names as are set by the inline constructor.
6332 for (Object* obj = prototype;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006333 obj != heap->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00006334 obj = obj->GetPrototype()) {
6335 JSObject* js_object = JSObject::cast(obj);
6336 for (int i = 0; i < this_property_assignments_count(); i++) {
6337 LookupResult result;
6338 String* name = GetThisPropertyAssignmentName(i);
6339 js_object->LocalLookupRealNamedProperty(name, &result);
6340 if (result.IsProperty() && result.type() == CALLBACKS) {
6341 return false;
6342 }
6343 }
6344 }
6345
6346 return true;
6347}
6348
6349
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00006350void SharedFunctionInfo::ForbidInlineConstructor() {
6351 set_compiler_hints(BooleanBit::set(compiler_hints(),
6352 kHasOnlySimpleThisPropertyAssignments,
6353 false));
6354}
6355
6356
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006357void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006358 bool only_simple_this_property_assignments,
6359 FixedArray* assignments) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006360 set_compiler_hints(BooleanBit::set(compiler_hints(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006361 kHasOnlySimpleThisPropertyAssignments,
6362 only_simple_this_property_assignments));
6363 set_this_property_assignments(assignments);
6364 set_this_property_assignments_count(assignments->length() / 3);
6365}
6366
6367
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006368void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006369 Heap* heap = GetHeap();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006370 set_compiler_hints(BooleanBit::set(compiler_hints(),
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006371 kHasOnlySimpleThisPropertyAssignments,
6372 false));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006373 set_this_property_assignments(heap->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006374 set_this_property_assignments_count(0);
6375}
6376
6377
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006378String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
6379 Object* obj = this_property_assignments();
6380 ASSERT(obj->IsFixedArray());
6381 ASSERT(index < this_property_assignments_count());
6382 obj = FixedArray::cast(obj)->get(index * 3);
6383 ASSERT(obj->IsString());
6384 return String::cast(obj);
6385}
6386
6387
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006388bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
6389 Object* obj = this_property_assignments();
6390 ASSERT(obj->IsFixedArray());
6391 ASSERT(index < this_property_assignments_count());
6392 obj = FixedArray::cast(obj)->get(index * 3 + 1);
6393 return Smi::cast(obj)->value() != -1;
6394}
6395
6396
6397int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
6398 ASSERT(IsThisPropertyAssignmentArgument(index));
6399 Object* obj =
6400 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
6401 return Smi::cast(obj)->value();
6402}
6403
6404
6405Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
6406 ASSERT(!IsThisPropertyAssignmentArgument(index));
6407 Object* obj =
6408 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
6409 return obj;
6410}
6411
6412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006413// Support function for printing the source code to a StringStream
6414// without any allocation in the heap.
6415void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
6416 int max_length) {
6417 // For some native functions there is no source.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006418 if (!HasSourceCode()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006419 accumulator->Add("<No Source>");
6420 return;
6421 }
6422
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006423 // Get the source for the script which this function came from.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006424 // Don't use String::cast because we don't want more assertion errors while
6425 // we are already creating a stack dump.
6426 String* script_source =
6427 reinterpret_cast<String*>(Script::cast(script())->source());
6428
6429 if (!script_source->LooksValid()) {
6430 accumulator->Add("<Invalid Source>");
6431 return;
6432 }
6433
6434 if (!is_toplevel()) {
6435 accumulator->Add("function ");
6436 Object* name = this->name();
6437 if (name->IsString() && String::cast(name)->length() > 0) {
6438 accumulator->PrintName(name);
6439 }
6440 }
6441
6442 int len = end_position() - start_position();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006443 if (len <= max_length || max_length < 0) {
6444 accumulator->Put(script_source, start_position(), end_position());
6445 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006446 accumulator->Put(script_source,
6447 start_position(),
6448 start_position() + max_length);
6449 accumulator->Add("...\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006450 }
6451}
6452
6453
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006454static bool IsCodeEquivalent(Code* code, Code* recompiled) {
6455 if (code->instruction_size() != recompiled->instruction_size()) return false;
6456 ByteArray* code_relocation = code->relocation_info();
6457 ByteArray* recompiled_relocation = recompiled->relocation_info();
6458 int length = code_relocation->length();
6459 if (length != recompiled_relocation->length()) return false;
6460 int compare = memcmp(code_relocation->GetDataStartAddress(),
6461 recompiled_relocation->GetDataStartAddress(),
6462 length);
6463 return compare == 0;
6464}
6465
6466
6467void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
6468 ASSERT(!has_deoptimization_support());
6469 AssertNoAllocation no_allocation;
6470 Code* code = this->code();
6471 if (IsCodeEquivalent(code, recompiled)) {
6472 // Copy the deoptimization data from the recompiled code.
6473 code->set_deoptimization_data(recompiled->deoptimization_data());
6474 code->set_has_deoptimization_support(true);
6475 } else {
6476 // TODO(3025757): In case the recompiled isn't equivalent to the
6477 // old code, we have to replace it. We should try to avoid this
6478 // altogether because it flushes valuable type feedback by
6479 // effectively resetting all IC state.
6480 set_code(recompiled);
6481 }
6482 ASSERT(has_deoptimization_support());
6483}
6484
6485
ager@chromium.orgea91cc52011-05-23 06:06:11 +00006486void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
6487 // Disable optimization for the shared function info and mark the
6488 // code as non-optimizable. The marker on the shared function info
6489 // is there because we flush non-optimized code thereby loosing the
6490 // non-optimizable information for the code. When the code is
6491 // regenerated and set on the shared function info it is marked as
6492 // non-optimizable if optimization is disabled for the shared
6493 // function info.
6494 set_optimization_disabled(true);
6495 // Code should be the lazy compilation stub or else unoptimized. If the
6496 // latter, disable optimization for the code too.
6497 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
6498 if (code()->kind() == Code::FUNCTION) {
6499 code()->set_optimizable(false);
6500 }
6501 if (FLAG_trace_opt) {
6502 PrintF("[disabled optimization for: ");
6503 function->PrintName();
6504 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
6505 }
6506}
6507
6508
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006509bool SharedFunctionInfo::VerifyBailoutId(int id) {
6510 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
6511 // we are always bailing out on ARM.
6512
6513 ASSERT(id != AstNode::kNoNumber);
6514 Code* unoptimized = code();
6515 DeoptimizationOutputData* data =
6516 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6517 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6518 USE(ignore);
6519 return true; // Return true if there was no ASSERT.
6520}
6521
6522
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006523void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6524 ASSERT(!IsInobjectSlackTrackingInProgress());
6525
6526 // Only initiate the tracking the first time.
6527 if (live_objects_may_exist()) return;
6528 set_live_objects_may_exist(true);
6529
6530 // No tracking during the snapshot construction phase.
6531 if (Serializer::enabled()) return;
6532
6533 if (map->unused_property_fields() == 0) return;
6534
6535 // Nonzero counter is a leftover from the previous attempt interrupted
6536 // by GC, keep it.
6537 if (construction_count() == 0) {
6538 set_construction_count(kGenerousAllocationCount);
6539 }
6540 set_initial_map(map);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006541 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006542 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006543 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006544 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006545}
6546
6547
6548// Called from GC, hence reinterpret_cast and unchecked accessors.
6549void SharedFunctionInfo::DetachInitialMap() {
6550 Map* map = reinterpret_cast<Map*>(initial_map());
6551
6552 // Make the map remember to restore the link if it survives the GC.
6553 map->set_bit_field2(
6554 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6555
6556 // Undo state changes made by StartInobjectTracking (except the
6557 // construction_count). This way if the initial map does not survive the GC
6558 // then StartInobjectTracking will be called again the next time the
6559 // constructor is called. The countdown will continue and (possibly after
6560 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006561 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6562 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006563 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006564 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006565 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006566 // It is safe to clear the flag: it will be set again if the map is live.
6567 set_live_objects_may_exist(false);
6568}
6569
6570
6571// Called from GC, hence reinterpret_cast and unchecked accessors.
6572void SharedFunctionInfo::AttachInitialMap(Map* map) {
6573 map->set_bit_field2(
6574 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6575
6576 // Resume inobject slack tracking.
6577 set_initial_map(map);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006578 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006579 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006580 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006581 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006582 // The map survived the gc, so there may be objects referencing it.
6583 set_live_objects_may_exist(true);
6584}
6585
6586
6587static void GetMinInobjectSlack(Map* map, void* data) {
6588 int slack = map->unused_property_fields();
6589 if (*reinterpret_cast<int*>(data) > slack) {
6590 *reinterpret_cast<int*>(data) = slack;
6591 }
6592}
6593
6594
6595static void ShrinkInstanceSize(Map* map, void* data) {
6596 int slack = *reinterpret_cast<int*>(data);
6597 map->set_inobject_properties(map->inobject_properties() - slack);
6598 map->set_unused_property_fields(map->unused_property_fields() - slack);
6599 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6600
6601 // Visitor id might depend on the instance size, recalculate it.
6602 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6603}
6604
6605
6606void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6607 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6608 Map* map = Map::cast(initial_map());
6609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006610 Heap* heap = map->heap();
6611 set_initial_map(heap->undefined_value());
6612 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006613 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006614 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006615 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006616
6617 int slack = map->unused_property_fields();
6618 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6619 if (slack != 0) {
6620 // Resize the initial map and all maps in its transition tree.
6621 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00006622
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006623 // Give the correct expected_nof_properties to initial maps created later.
6624 ASSERT(expected_nof_properties() >= slack);
6625 set_expected_nof_properties(expected_nof_properties() - slack);
6626 }
6627}
6628
6629
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006631 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00006632 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6633 Object* old_target = target;
6634 VisitPointer(&target);
6635 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006636}
6637
6638
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00006639void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6640 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6641 Object* old_code = code;
6642 VisitPointer(&code);
6643 if (code != old_code) {
6644 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6645 }
6646}
6647
6648
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006649void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6650 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6651 Object* cell = rinfo->target_cell();
6652 Object* old_cell = cell;
6653 VisitPointer(&cell);
6654 if (cell != old_cell) {
6655 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6656 }
6657}
6658
6659
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006660void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00006661 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6662 rinfo->IsPatchedReturnSequence()) ||
6663 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6664 rinfo->IsPatchedDebugBreakSlotSequence()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00006665 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6666 Object* old_target = target;
6667 VisitPointer(&target);
6668 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669}
6670
6671
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006672void Code::InvalidateRelocation() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006673 set_relocation_info(heap()->empty_byte_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006674}
6675
6676
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006677void Code::Relocate(intptr_t delta) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006678 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6679 it.rinfo()->apply(delta);
6680 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006681 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006682}
6683
6684
6685void Code::CopyFrom(const CodeDesc& desc) {
6686 // copy code
6687 memmove(instruction_start(), desc.buffer, desc.instr_size);
6688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006689 // copy reloc info
6690 memmove(relocation_start(),
6691 desc.buffer + desc.buffer_size - desc.reloc_size,
6692 desc.reloc_size);
6693
6694 // unbox handles and relocate
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006695 intptr_t delta = instruction_start() - desc.buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006696 int mode_mask = RelocInfo::kCodeTargetMask |
ager@chromium.org236ad962008-09-25 09:45:57 +00006697 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006698 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006699 RelocInfo::kApplyMask;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006700 Assembler* origin = desc.origin; // Needed to find target_object on X64.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006702 RelocInfo::Mode mode = it.rinfo()->rmode();
6703 if (mode == RelocInfo::EMBEDDED_OBJECT) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006704 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705 it.rinfo()->set_target_object(*p);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006706 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006707 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006708 it.rinfo()->set_target_cell(*cell);
ager@chromium.org236ad962008-09-25 09:45:57 +00006709 } else if (RelocInfo::IsCodeTarget(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006710 // rewrite code handles in inline cache targets to direct
6711 // pointers to the first instruction in the code object
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006712 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006713 Code* code = Code::cast(*p);
6714 it.rinfo()->set_target_address(code->instruction_start());
6715 } else {
6716 it.rinfo()->apply(delta);
6717 }
6718 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006719 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006720}
6721
6722
6723// Locate the source position which is closest to the address in the code. This
6724// is using the source position information embedded in the relocation info.
6725// The position returned is relative to the beginning of the script where the
6726// source for this function is found.
6727int Code::SourcePosition(Address pc) {
6728 int distance = kMaxInt;
ager@chromium.org236ad962008-09-25 09:45:57 +00006729 int position = RelocInfo::kNoPosition; // Initially no position found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006730 // Run through all the relocation info to find the best matching source
6731 // position. All the code needs to be considered as the sequence of the
6732 // instructions in the code does not necessarily follow the same order as the
6733 // source.
6734 RelocIterator it(this, RelocInfo::kPositionMask);
6735 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006736 // Only look at positions after the current pc.
6737 if (it.rinfo()->pc() < pc) {
6738 // Get position and distance.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006739
6740 int dist = static_cast<int>(pc - it.rinfo()->pc());
6741 int pos = static_cast<int>(it.rinfo()->data());
ager@chromium.org236ad962008-09-25 09:45:57 +00006742 // If this position is closer than the current candidate or if it has the
6743 // same distance as the current candidate and the position is higher then
6744 // this position is the new candidate.
6745 if ((dist < distance) ||
6746 (dist == distance && pos > position)) {
6747 position = pos;
6748 distance = dist;
6749 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750 }
6751 it.next();
6752 }
6753 return position;
6754}
6755
6756
6757// Same as Code::SourcePosition above except it only looks for statement
6758// positions.
6759int Code::SourceStatementPosition(Address pc) {
6760 // First find the position as close as possible using all position
6761 // information.
6762 int position = SourcePosition(pc);
6763 // Now find the closest statement position before the position.
6764 int statement_position = 0;
6765 RelocIterator it(this, RelocInfo::kPositionMask);
6766 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006767 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006768 int p = static_cast<int>(it.rinfo()->data());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006769 if (statement_position < p && p <= position) {
6770 statement_position = p;
6771 }
6772 }
6773 it.next();
6774 }
6775 return statement_position;
6776}
6777
6778
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006779SafepointEntry Code::GetSafepointEntry(Address pc) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006780 SafepointTable table(this);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006781 return table.FindEntry(pc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006782}
6783
6784
6785void Code::SetNoStackCheckTable() {
6786 // Indicate the absence of a stack-check table by a table start after the
6787 // end of the instructions. Table start must be aligned, so round up.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006788 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006789}
6790
6791
6792Map* Code::FindFirstMap() {
6793 ASSERT(is_inline_cache_stub());
6794 AssertNoAllocation no_allocation;
6795 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
6796 for (RelocIterator it(this, mask); !it.done(); it.next()) {
6797 RelocInfo* info = it.rinfo();
6798 Object* object = info->target_object();
6799 if (object->IsMap()) return Map::cast(object);
6800 }
6801 return NULL;
6802}
6803
6804
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00006805#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006806
whesse@chromium.org023421e2010-12-21 12:19:12 +00006807#ifdef OBJECT_PRINT
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006808
whesse@chromium.org023421e2010-12-21 12:19:12 +00006809void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006810 disasm::NameConverter converter;
6811 int deopt_count = DeoptCount();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006812 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006813 if (0 == deopt_count) return;
6814
whesse@chromium.org023421e2010-12-21 12:19:12 +00006815 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006816 for (int i = 0; i < deopt_count; i++) {
6817 int command_count = 0;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006818 PrintF(out, "%6d %6d %6d",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006819 i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
6820 int translation_index = TranslationIndex(i)->value();
6821 TranslationIterator iterator(TranslationByteArray(), translation_index);
6822 Translation::Opcode opcode =
6823 static_cast<Translation::Opcode>(iterator.Next());
6824 ASSERT(Translation::BEGIN == opcode);
6825 int frame_count = iterator.Next();
6826 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006827 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
6828 frame_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006829 }
6830
6831 for (int i = 0; i < frame_count; ++i) {
6832 opcode = static_cast<Translation::Opcode>(iterator.Next());
6833 ASSERT(Translation::FRAME == opcode);
6834 int ast_id = iterator.Next();
6835 int function_id = iterator.Next();
6836 JSFunction* function =
6837 JSFunction::cast(LiteralArray()->get(function_id));
6838 unsigned height = iterator.Next();
6839 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006840 PrintF(out, "%24s %s {ast_id=%d, function=",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006841 "", Translation::StringFor(opcode), ast_id);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006842 function->PrintName(out);
6843 PrintF(out, ", height=%u}\n", height);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006844 }
6845
6846 // Size of translation is height plus all incoming arguments including
6847 // receiver.
6848 int size = height + function->shared()->formal_parameter_count() + 1;
6849 command_count += size;
6850 for (int j = 0; j < size; ++j) {
6851 opcode = static_cast<Translation::Opcode>(iterator.Next());
6852 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006853 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006854 }
6855
6856 if (opcode == Translation::DUPLICATE) {
6857 opcode = static_cast<Translation::Opcode>(iterator.Next());
6858 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006859 PrintF(out, "%s ", Translation::StringFor(opcode));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006860 }
6861 --j; // Two commands share the same frame index.
6862 }
6863
6864 switch (opcode) {
6865 case Translation::BEGIN:
6866 case Translation::FRAME:
6867 case Translation::DUPLICATE:
6868 UNREACHABLE();
6869 break;
6870
6871 case Translation::REGISTER: {
6872 int reg_code = iterator.Next();
6873 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006874 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006875 }
6876 break;
6877 }
6878
6879 case Translation::INT32_REGISTER: {
6880 int reg_code = iterator.Next();
6881 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006882 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006883 }
6884 break;
6885 }
6886
6887 case Translation::DOUBLE_REGISTER: {
6888 int reg_code = iterator.Next();
6889 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006890 PrintF(out, "{input=%s}",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006891 DoubleRegister::AllocationIndexToString(reg_code));
6892 }
6893 break;
6894 }
6895
6896 case Translation::STACK_SLOT: {
6897 int input_slot_index = iterator.Next();
6898 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006899 PrintF(out, "{input=%d}", input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006900 }
6901 break;
6902 }
6903
6904 case Translation::INT32_STACK_SLOT: {
6905 int input_slot_index = iterator.Next();
6906 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006907 PrintF(out, "{input=%d}", input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006908 }
6909 break;
6910 }
6911
6912 case Translation::DOUBLE_STACK_SLOT: {
6913 int input_slot_index = iterator.Next();
6914 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006915 PrintF(out, "{input=%d}", input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006916 }
6917 break;
6918 }
6919
6920 case Translation::LITERAL: {
6921 unsigned literal_index = iterator.Next();
6922 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006923 PrintF(out, "{literal_id=%u}", literal_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006924 }
6925 break;
6926 }
6927
6928 case Translation::ARGUMENTS_OBJECT:
6929 break;
6930 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006931 if (FLAG_print_code_verbose) PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006932 }
6933 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006934 if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006935 }
6936}
6937
6938
whesse@chromium.org023421e2010-12-21 12:19:12 +00006939void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
6940 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006941 this->DeoptPoints());
6942 if (this->DeoptPoints() == 0) return;
6943
6944 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
6945 for (int i = 0; i < this->DeoptPoints(); i++) {
6946 int pc_and_state = this->PcAndState(i)->value();
6947 PrintF("%6d %8d %s\n",
6948 this->AstId(i)->value(),
6949 FullCodeGenerator::PcField::decode(pc_and_state),
6950 FullCodeGenerator::State2String(
6951 FullCodeGenerator::StateField::decode(pc_and_state)));
6952 }
6953}
6954
6955#endif
6956
6957
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00006958// Identify kind of code.
6959const char* Code::Kind2String(Kind kind) {
6960 switch (kind) {
6961 case FUNCTION: return "FUNCTION";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006962 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00006963 case STUB: return "STUB";
6964 case BUILTIN: return "BUILTIN";
6965 case LOAD_IC: return "LOAD_IC";
6966 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
6967 case STORE_IC: return "STORE_IC";
6968 case KEYED_STORE_IC: return "KEYED_STORE_IC";
6969 case CALL_IC: return "CALL_IC";
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00006970 case KEYED_CALL_IC: return "KEYED_CALL_IC";
danno@chromium.org40cb8782011-05-25 07:58:50 +00006971 case UNARY_OP_IC: return "UNARY_OP_IC";
6972 case BINARY_OP_IC: return "BINARY_OP_IC";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006973 case COMPARE_IC: return "COMPARE_IC";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00006974 }
6975 UNREACHABLE();
6976 return NULL;
6977}
mads.s.ager31e71382008-08-13 09:32:07 +00006978
6979
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006980const char* Code::ICState2String(InlineCacheState state) {
6981 switch (state) {
6982 case UNINITIALIZED: return "UNINITIALIZED";
6983 case PREMONOMORPHIC: return "PREMONOMORPHIC";
6984 case MONOMORPHIC: return "MONOMORPHIC";
6985 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
6986 case MEGAMORPHIC: return "MEGAMORPHIC";
6987 case DEBUG_BREAK: return "DEBUG_BREAK";
6988 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
6989 }
6990 UNREACHABLE();
6991 return NULL;
6992}
6993
6994
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006995const char* Code::PropertyType2String(PropertyType type) {
6996 switch (type) {
6997 case NORMAL: return "NORMAL";
6998 case FIELD: return "FIELD";
6999 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
7000 case CALLBACKS: return "CALLBACKS";
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00007001 case HANDLER: return "HANDLER";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007002 case INTERCEPTOR: return "INTERCEPTOR";
7003 case MAP_TRANSITION: return "MAP_TRANSITION";
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007004 case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007005 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
7006 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
7007 }
7008 UNREACHABLE();
7009 return NULL;
7010}
7011
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007012
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007013void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
7014 const char* name = NULL;
7015 switch (kind) {
7016 case CALL_IC:
7017 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
7018 name = "STRING_INDEX_OUT_OF_BOUNDS";
7019 }
7020 break;
7021 case STORE_IC:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007022 case KEYED_STORE_IC:
7023 if (extra == kStrictMode) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007024 name = "STRICT";
7025 }
7026 break;
7027 default:
7028 break;
7029 }
7030 if (name != NULL) {
7031 PrintF(out, "extra_ic_state = %s\n", name);
7032 } else {
7033 PrintF(out, "etra_ic_state = %d\n", extra);
7034 }
7035}
7036
7037
whesse@chromium.org023421e2010-12-21 12:19:12 +00007038void Code::Disassemble(const char* name, FILE* out) {
7039 PrintF(out, "kind = %s\n", Kind2String(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007040 if (is_inline_cache_stub()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007041 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007042 PrintExtraICState(out, kind(), extra_ic_state());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007043 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007044 if (ic_state() == MONOMORPHIC) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007045 PrintF(out, "type = %s\n", PropertyType2String(type()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007046 }
7047 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007048 if ((name != NULL) && (name[0] != '\0')) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007049 PrintF(out, "name = %s\n", name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007050 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007051 if (kind() == OPTIMIZED_FUNCTION) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007052 PrintF(out, "stack_slots = %d\n", stack_slots());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007053 }
mads.s.ager31e71382008-08-13 09:32:07 +00007054
whesse@chromium.org023421e2010-12-21 12:19:12 +00007055 PrintF(out, "Instructions (size = %d)\n", instruction_size());
7056 Disassembler::Decode(out, this);
7057 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00007058
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007059 if (kind() == FUNCTION) {
7060 DeoptimizationOutputData* data =
7061 DeoptimizationOutputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007062 data->DeoptimizationOutputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007063 } else if (kind() == OPTIMIZED_FUNCTION) {
7064 DeoptimizationInputData* data =
7065 DeoptimizationInputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007066 data->DeoptimizationInputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007067 }
7068 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007069
7070 if (kind() == OPTIMIZED_FUNCTION) {
7071 SafepointTable table(this);
whesse@chromium.org023421e2010-12-21 12:19:12 +00007072 PrintF(out, "Safepoints (size = %u)\n", table.size());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007073 for (unsigned i = 0; i < table.length(); i++) {
7074 unsigned pc_offset = table.GetPcOffset(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00007075 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007076 table.PrintEntry(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00007077 PrintF(out, " (sp -> fp)");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007078 SafepointEntry entry = table.GetEntry(i);
7079 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
7080 PrintF(out, " %6d", entry.deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007081 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007082 PrintF(out, " <none>");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007083 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007084 if (entry.argument_count() > 0) {
7085 PrintF(out, " argc: %d", entry.argument_count());
7086 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00007087 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007088 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00007089 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007090 } else if (kind() == FUNCTION) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007091 unsigned offset = stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007092 // If there is no stack check table, the "table start" will at or after
7093 // (due to alignment) the end of the instruction stream.
7094 if (static_cast<int>(offset) < instruction_size()) {
7095 unsigned* address =
7096 reinterpret_cast<unsigned*>(instruction_start() + offset);
7097 unsigned length = address[0];
whesse@chromium.org023421e2010-12-21 12:19:12 +00007098 PrintF(out, "Stack checks (size = %u)\n", length);
7099 PrintF(out, "ast_id pc_offset\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007100 for (unsigned i = 0; i < length; ++i) {
7101 unsigned index = (2 * i) + 1;
whesse@chromium.org023421e2010-12-21 12:19:12 +00007102 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007103 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00007104 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007105 }
7106 }
7107
mads.s.ager31e71382008-08-13 09:32:07 +00007108 PrintF("RelocInfo (size = %d)\n", relocation_size());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007109 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
7110 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00007111}
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00007112#endif // ENABLE_DISASSEMBLER
7113
7114
lrn@chromium.org303ada72010-10-27 09:33:13 +00007115MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
7116 int length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007117 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +00007118 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007119 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007120
lrn@chromium.org303ada72010-10-27 09:33:13 +00007121 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007122 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007123 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7124 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007125 FixedArray* elems = FixedArray::cast(obj);
7126
lrn@chromium.org303ada72010-10-27 09:33:13 +00007127 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
7128 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7129 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007130 Map* new_map = Map::cast(obj);
7131
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007132 switch (GetElementsKind()) {
7133 case FAST_ELEMENTS: {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007134 AssertNoAllocation no_gc;
7135 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007136 FixedArray* old_elements = FixedArray::cast(elements());
7137 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
7138 // Fill out the new array with this content and array holes.
7139 for (uint32_t i = 0; i < old_length; i++) {
7140 elems->set(i, old_elements->get(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007141 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007142 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007143 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007144 case FAST_DOUBLE_ELEMENTS: {
7145 FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements());
7146 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
7147 // Fill out the new array with this content and array holes.
7148 for (uint32_t i = 0; i < old_length; i++) {
7149 if (!old_elements->is_the_hole(i)) {
7150 Object* obj;
7151 // Objects must be allocated in the old object space, since the
7152 // overall number of HeapNumbers needed for the conversion might
7153 // exceed the capacity of new space, and we would fail repeatedly
7154 // trying to convert the FixedDoubleArray.
7155 MaybeObject* maybe_value_object =
7156 GetHeap()->AllocateHeapNumber(old_elements->get(i), TENURED);
7157 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
7158 // Force write barrier. It's not worth trying to exploit
7159 // elems->GetWriteBarrierMode(), since it requires an
7160 // AssertNoAllocation stack object that would have to be positioned
7161 // after the HeapNumber allocation anyway.
7162 elems->set(i, obj, UPDATE_WRITE_BARRIER);
7163 }
7164 }
7165 break;
7166 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007167 case DICTIONARY_ELEMENTS: {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007168 AssertNoAllocation no_gc;
7169 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007170 NumberDictionary* dictionary = NumberDictionary::cast(elements());
7171 for (int i = 0; i < dictionary->Capacity(); i++) {
7172 Object* key = dictionary->KeyAt(i);
7173 if (key->IsNumber()) {
7174 uint32_t entry = static_cast<uint32_t>(key->Number());
7175 elems->set(entry, dictionary->ValueAt(i), mode);
7176 }
7177 }
7178 break;
7179 }
7180 default:
7181 UNREACHABLE();
7182 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007183 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007184
7185 set_map(new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007186 set_elements(elems);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007187
7188 if (IsJSArray()) {
7189 JSArray::cast(this)->set_length(Smi::FromInt(length));
7190 }
7191
7192 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007193}
7194
7195
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007196MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
7197 int capacity,
7198 int length) {
7199 Heap* heap = GetHeap();
7200 // We should never end in here with a pixel or external array.
7201 ASSERT(!HasExternalArrayElements());
7202
7203 Object* obj;
7204 { MaybeObject* maybe_obj =
7205 heap->AllocateUninitializedFixedDoubleArray(capacity);
7206 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7207 }
7208 FixedDoubleArray* elems = FixedDoubleArray::cast(obj);
7209
7210 { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap();
7211 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7212 }
7213 Map* new_map = Map::cast(obj);
7214
7215 AssertNoAllocation no_gc;
7216 switch (GetElementsKind()) {
7217 case FAST_ELEMENTS: {
7218 elems->Initialize(FixedArray::cast(elements()));
7219 break;
7220 }
7221 case FAST_DOUBLE_ELEMENTS: {
7222 elems->Initialize(FixedDoubleArray::cast(elements()));
7223 break;
7224 }
7225 case DICTIONARY_ELEMENTS: {
7226 elems->Initialize(NumberDictionary::cast(elements()));
7227 break;
7228 }
7229 default:
7230 UNREACHABLE();
7231 break;
7232 }
7233
7234 set_map(new_map);
7235 set_elements(elems);
7236
7237 if (IsJSArray()) {
7238 JSArray::cast(this)->set_length(Smi::FromInt(length));
7239 }
7240
7241 return this;
7242}
7243
7244
lrn@chromium.org303ada72010-10-27 09:33:13 +00007245MaybeObject* JSObject::SetSlowElements(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +00007246 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007247 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007248
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007249 uint32_t new_length = static_cast<uint32_t>(len->Number());
7250
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007251 switch (GetElementsKind()) {
7252 case FAST_ELEMENTS: {
7253 // Make sure we never try to shrink dense arrays into sparse arrays.
7254 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
7255 new_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007256 Object* obj;
7257 { MaybeObject* maybe_obj = NormalizeElements();
7258 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7259 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007260
7261 // Update length for JSArrays.
7262 if (IsJSArray()) JSArray::cast(this)->set_length(len);
7263 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007264 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007265 case DICTIONARY_ELEMENTS: {
7266 if (IsJSArray()) {
7267 uint32_t old_length =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007268 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007269 element_dictionary()->RemoveNumberEntries(new_length, old_length),
7270 JSArray::cast(this)->set_length(len);
7271 }
7272 break;
7273 }
7274 default:
7275 UNREACHABLE();
7276 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007277 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007278 return this;
7279}
7280
7281
lrn@chromium.org303ada72010-10-27 09:33:13 +00007282MaybeObject* JSArray::Initialize(int capacity) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007283 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007284 ASSERT(capacity >= 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007285 set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007286 FixedArray* new_elements;
7287 if (capacity == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007288 new_elements = heap->empty_fixed_array();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007289 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007290 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007291 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007292 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7293 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294 new_elements = FixedArray::cast(obj);
7295 }
7296 set_elements(new_elements);
7297 return this;
7298}
7299
7300
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007301void JSArray::Expand(int required_size) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007302 Handle<JSArray> self(this);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007303 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007304 int old_size = old_backing->length();
ager@chromium.org6141cbe2009-11-20 12:14:52 +00007305 int new_size = required_size > old_size ? required_size : old_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007307 // Can't use this any more now because we may have had a GC!
7308 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
7309 self->SetContent(*new_backing);
7310}
7311
7312
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313static Failure* ArrayLengthRangeError(Heap* heap) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314 HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007315 return heap->isolate()->Throw(
7316 *FACTORY->NewRangeError("invalid_array_length",
7317 HandleVector<Object>(NULL, 0)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007318}
7319
7320
lrn@chromium.org303ada72010-10-27 09:33:13 +00007321MaybeObject* JSObject::SetElementsLength(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +00007322 // We should never end in here with a pixel or external array.
ager@chromium.org5c838252010-02-19 08:53:10 +00007323 ASSERT(AllowsSetElementsLength());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007324
lrn@chromium.org303ada72010-10-27 09:33:13 +00007325 MaybeObject* maybe_smi_length = len->ToSmi();
7326 Object* smi_length = Smi::FromInt(0);
7327 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007328 const int value = Smi::cast(smi_length)->value();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007329 if (value < 0) return ArrayLengthRangeError(GetHeap());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007330 switch (GetElementsKind()) {
7331 case FAST_ELEMENTS: {
7332 int old_capacity = FixedArray::cast(elements())->length();
7333 if (value <= old_capacity) {
7334 if (IsJSArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007335 Object* obj;
7336 { MaybeObject* maybe_obj = EnsureWritableFastElements();
7337 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7338 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007339 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
7340 // NOTE: We may be able to optimize this by removing the
7341 // last part of the elements backing storage array and
7342 // setting the capacity to the new size.
7343 for (int i = value; i < old_length; i++) {
7344 FixedArray::cast(elements())->set_the_hole(i);
7345 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007346 JSArray::cast(this)->set_length(Smi::cast(smi_length));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007347 }
7348 return this;
7349 }
7350 int min = NewElementsCapacity(old_capacity);
7351 int new_capacity = value > min ? value : min;
7352 if (new_capacity <= kMaxFastElementsLength ||
7353 !ShouldConvertToSlowElements(new_capacity)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007354 Object* obj;
7355 { MaybeObject* maybe_obj =
7356 SetFastElementsCapacityAndLength(new_capacity, value);
7357 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7358 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007359 return this;
7360 }
7361 break;
7362 }
7363 case DICTIONARY_ELEMENTS: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364 if (IsJSArray()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007365 if (value == 0) {
7366 // If the length of a slow array is reset to zero, we clear
7367 // the array and flush backing storage. This has the added
7368 // benefit that the array returns to fast mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007369 Object* obj;
7370 { MaybeObject* maybe_obj = ResetElements();
7371 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7372 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007373 } else {
7374 // Remove deleted elements.
7375 uint32_t old_length =
7376 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
7377 element_dictionary()->RemoveNumberEntries(value, old_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007378 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007379 JSArray::cast(this)->set_length(Smi::cast(smi_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380 }
7381 return this;
7382 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007383 default:
7384 UNREACHABLE();
7385 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386 }
7387 }
7388
7389 // General slow case.
7390 if (len->IsNumber()) {
7391 uint32_t length;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007392 if (len->ToArrayIndex(&length)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393 return SetSlowElements(len);
7394 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007395 return ArrayLengthRangeError(GetHeap());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007396 }
7397 }
7398
7399 // len is not a number so make the array size one and
7400 // set only element to len.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007401 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007402 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007403 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7404 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007405 FixedArray::cast(obj)->set(0, len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007406 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407 set_elements(FixedArray::cast(obj));
7408 return this;
7409}
7410
7411
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007412Object* Map::GetPrototypeTransition(Object* prototype) {
7413 FixedArray* cache = prototype_transitions();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007414 int number_of_transitions = NumberOfProtoTransitions();
7415 const int proto_offset =
7416 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
7417 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
7418 const int step = kProtoTransitionElementsPerEntry;
7419 for (int i = 0; i < number_of_transitions; i++) {
7420 if (cache->get(proto_offset + i * step) == prototype) {
7421 Object* map = cache->get(map_offset + i * step);
7422 ASSERT(map->IsMap());
7423 return map;
7424 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007425 }
7426 return NULL;
7427}
7428
7429
7430MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007431 ASSERT(map->IsMap());
7432 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007433 // Don't cache prototype transition if this map is shared.
7434 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
7435
7436 FixedArray* cache = prototype_transitions();
7437
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007438 const int step = kProtoTransitionElementsPerEntry;
7439 const int header = kProtoTransitionHeaderSize;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007440
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007441 int capacity = (cache->length() - header) / step;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007442
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007443 int transitions = NumberOfProtoTransitions() + 1;
7444
7445 if (transitions > capacity) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007446 if (capacity > kMaxCachedPrototypeTransitions) return this;
7447
7448 FixedArray* new_cache;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007449 // Grow array by factor 2 over and above what we need.
7450 { MaybeObject* maybe_cache =
7451 heap()->AllocateFixedArray(transitions * 2 * step + header);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007452 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
7453 }
7454
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007455 for (int i = 0; i < capacity * step; i++) {
7456 new_cache->set(i + header, cache->get(i + header));
7457 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007458 cache = new_cache;
7459 set_prototype_transitions(cache);
7460 }
7461
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007462 int last = transitions - 1;
7463
7464 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
7465 cache->set(header + last * step + kProtoTransitionMapOffset, map);
7466 SetNumberOfProtoTransitions(transitions);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007467
7468 return cache;
7469}
7470
7471
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007472MaybeObject* JSReceiver::SetPrototype(Object* value,
7473 bool skip_hidden_prototypes) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007474#ifdef DEBUG
7475 int size = Size();
7476#endif
7477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007478 Heap* heap = GetHeap();
ager@chromium.org5c838252010-02-19 08:53:10 +00007479 // Silently ignore the change if value is not a JSObject or null.
7480 // SpiderMonkey behaves this way.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007481 if (!value->IsJSReceiver() && !value->IsNull()) return value;
ager@chromium.org5c838252010-02-19 08:53:10 +00007482
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007483 // From 8.6.2 Object Internal Methods
7484 // ...
7485 // In addition, if [[Extensible]] is false the value of the [[Class]] and
7486 // [[Prototype]] internal properties of the object may not be modified.
7487 // ...
7488 // Implementation specific extensions that modify [[Class]], [[Prototype]]
7489 // or [[Extensible]] must not violate the invariants defined in the preceding
7490 // paragraph.
7491 if (!this->map()->is_extensible()) {
7492 HandleScope scope;
7493 Handle<Object> handle(this, heap->isolate());
7494 return heap->isolate()->Throw(
7495 *FACTORY->NewTypeError("non_extensible_proto",
7496 HandleVector<Object>(&handle, 1)));
7497 }
7498
ager@chromium.org5c838252010-02-19 08:53:10 +00007499 // Before we can set the prototype we need to be sure
7500 // prototype cycles are prevented.
7501 // It is sufficient to validate that the receiver is not in the new prototype
7502 // chain.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007503 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00007504 if (JSObject::cast(pt) == this) {
7505 // Cycle detected.
7506 HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007507 return heap->isolate()->Throw(
7508 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
ager@chromium.org5c838252010-02-19 08:53:10 +00007509 }
7510 }
7511
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007512 JSReceiver* real_receiver = this;
ager@chromium.org5c838252010-02-19 08:53:10 +00007513
7514 if (skip_hidden_prototypes) {
7515 // Find the first object in the chain whose prototype object is not
7516 // hidden and set the new prototype on that object.
7517 Object* current_proto = real_receiver->GetPrototype();
7518 while (current_proto->IsJSObject() &&
7519 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
7520 real_receiver = JSObject::cast(current_proto);
7521 current_proto = current_proto->GetPrototype();
7522 }
7523 }
7524
7525 // Set the new prototype of the object.
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007526 Map* map = real_receiver->map();
7527
7528 // Nothing to do if prototype is already set.
7529 if (map->prototype() == value) return value;
7530
7531 Object* new_map = map->GetPrototypeTransition(value);
7532 if (new_map == NULL) {
7533 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
7534 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
7535 }
7536
7537 { MaybeObject* maybe_new_cache =
7538 map->PutPrototypeTransition(value, Map::cast(new_map));
7539 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
7540 }
7541
7542 Map::cast(new_map)->set_prototype(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007543 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007544 ASSERT(Map::cast(new_map)->prototype() == value);
ager@chromium.org5c838252010-02-19 08:53:10 +00007545 real_receiver->set_map(Map::cast(new_map));
7546
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007547 heap->ClearInstanceofCache();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007548 ASSERT(size == Size());
ager@chromium.org5c838252010-02-19 08:53:10 +00007549 return value;
7550}
7551
7552
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007553bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007554 switch (GetElementsKind()) {
7555 case FAST_ELEMENTS: {
7556 uint32_t length = IsJSArray() ?
7557 static_cast<uint32_t>
7558 (Smi::cast(JSArray::cast(this)->length())->value()) :
7559 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7560 if ((index < length) &&
7561 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7562 return true;
7563 }
7564 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007565 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007566 case EXTERNAL_PIXEL_ELEMENTS: {
7567 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007568 if (index < static_cast<uint32_t>(pixels->length())) {
7569 return true;
7570 }
7571 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007572 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007573 case EXTERNAL_BYTE_ELEMENTS:
7574 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7575 case EXTERNAL_SHORT_ELEMENTS:
7576 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7577 case EXTERNAL_INT_ELEMENTS:
7578 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007579 case EXTERNAL_FLOAT_ELEMENTS:
7580 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00007581 ExternalArray* array = ExternalArray::cast(elements());
7582 if (index < static_cast<uint32_t>(array->length())) {
7583 return true;
7584 }
7585 break;
7586 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007587 case DICTIONARY_ELEMENTS: {
7588 if (element_dictionary()->FindEntry(index)
7589 != NumberDictionary::kNotFound) {
7590 return true;
7591 }
7592 break;
7593 }
7594 default:
7595 UNREACHABLE();
7596 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007597 }
7598
7599 // Handle [] on String objects.
7600 if (this->IsStringObjectWithCharacterAt(index)) return true;
7601
7602 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007603 if (pt->IsNull()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007604 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7605}
7606
7607
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007608bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007609 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007610 // Make sure that the top context does not change when doing
7611 // callbacks or interceptor calls.
7612 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007613 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007614 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007615 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007616 Handle<JSObject> holder_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007617 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007618 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007619 if (!interceptor->query()->IsUndefined()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007620 v8::IndexedPropertyQuery query =
7621 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007622 LOG(isolate,
7623 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007624 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007625 {
7626 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007627 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007628 result = query(index, info);
7629 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007630 if (!result.IsEmpty()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007631 ASSERT(result->IsInt32());
7632 return true; // absence of property is signaled by empty handle.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007633 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007634 } else if (!interceptor->getter()->IsUndefined()) {
7635 v8::IndexedPropertyGetter getter =
7636 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007637 LOG(isolate,
7638 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007639 v8::Handle<v8::Value> result;
7640 {
7641 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007642 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007643 result = getter(index, info);
7644 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007645 if (!result.IsEmpty()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007646 }
7647 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
7648}
7649
7650
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007651JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007652 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007653 if (IsAccessCheckNeeded()) {
7654 Heap* heap = GetHeap();
7655 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7656 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7657 return UNDEFINED_ELEMENT;
7658 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007659 }
7660
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007661 if (IsJSGlobalProxy()) {
7662 Object* proto = GetPrototype();
7663 if (proto->IsNull()) return UNDEFINED_ELEMENT;
7664 ASSERT(proto->IsJSGlobalObject());
7665 return JSObject::cast(proto)->HasLocalElement(index);
7666 }
7667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007668 // Check for lookup interceptor
7669 if (HasIndexedInterceptor()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007670 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
7671 : UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007672 }
7673
7674 // Handle [] on String objects.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007675 if (this->IsStringObjectWithCharacterAt(index)) {
7676 return STRING_CHARACTER_ELEMENT;
7677 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007678
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007679 switch (GetElementsKind()) {
7680 case FAST_ELEMENTS: {
7681 uint32_t length = IsJSArray() ?
7682 static_cast<uint32_t>
7683 (Smi::cast(JSArray::cast(this)->length())->value()) :
7684 static_cast<uint32_t>(FixedArray::cast(elements())->length());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007685 if ((index < length) &&
7686 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7687 return FAST_ELEMENT;
7688 }
7689 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007690 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007691 case EXTERNAL_PIXEL_ELEMENTS: {
7692 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007693 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
7694 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007695 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007696 case EXTERNAL_BYTE_ELEMENTS:
7697 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7698 case EXTERNAL_SHORT_ELEMENTS:
7699 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7700 case EXTERNAL_INT_ELEMENTS:
7701 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007702 case EXTERNAL_FLOAT_ELEMENTS:
7703 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00007704 ExternalArray* array = ExternalArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007705 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
7706 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00007707 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007708 case DICTIONARY_ELEMENTS: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007709 if (element_dictionary()->FindEntry(index) !=
7710 NumberDictionary::kNotFound) {
7711 return DICTIONARY_ELEMENT;
7712 }
7713 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007714 }
7715 default:
7716 UNREACHABLE();
7717 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007718 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007719
7720 return UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007721}
7722
7723
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007724bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007725 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007726 if (IsAccessCheckNeeded()) {
7727 Heap* heap = GetHeap();
7728 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7729 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7730 return false;
7731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007732 }
7733
7734 // Check for lookup interceptor
7735 if (HasIndexedInterceptor()) {
7736 return HasElementWithInterceptor(receiver, index);
7737 }
7738
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007739 switch (GetElementsKind()) {
7740 case FAST_ELEMENTS: {
7741 uint32_t length = IsJSArray() ?
7742 static_cast<uint32_t>
7743 (Smi::cast(JSArray::cast(this)->length())->value()) :
7744 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7745 if ((index < length) &&
7746 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
7747 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007748 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007749 case EXTERNAL_PIXEL_ELEMENTS: {
7750 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007751 if (index < static_cast<uint32_t>(pixels->length())) {
7752 return true;
7753 }
7754 break;
7755 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007756 case EXTERNAL_BYTE_ELEMENTS:
7757 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7758 case EXTERNAL_SHORT_ELEMENTS:
7759 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7760 case EXTERNAL_INT_ELEMENTS:
7761 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007762 case EXTERNAL_FLOAT_ELEMENTS:
7763 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00007764 ExternalArray* array = ExternalArray::cast(elements());
7765 if (index < static_cast<uint32_t>(array->length())) {
7766 return true;
7767 }
7768 break;
7769 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007770 case DICTIONARY_ELEMENTS: {
7771 if (element_dictionary()->FindEntry(index)
7772 != NumberDictionary::kNotFound) {
7773 return true;
7774 }
7775 break;
7776 }
7777 default:
7778 UNREACHABLE();
7779 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007780 }
7781
7782 // Handle [] on String objects.
7783 if (this->IsStringObjectWithCharacterAt(index)) return true;
7784
7785 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007786 if (pt->IsNull()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007787 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7788}
7789
7790
lrn@chromium.org303ada72010-10-27 09:33:13 +00007791MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007792 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007793 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007794 bool check_prototype) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007795 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007796 // Make sure that the top context does not change when doing
7797 // callbacks or interceptor calls.
7798 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007799 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007800 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
7801 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007802 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007803 if (!interceptor->setter()->IsUndefined()) {
7804 v8::IndexedPropertySetter setter =
7805 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007806 LOG(isolate,
7807 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
7808 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007809 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007810 v8::Handle<v8::Value> result;
7811 {
7812 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007813 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007814 result = setter(index, v8::Utils::ToLocal(value_handle), info);
7815 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007816 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007817 if (!result.IsEmpty()) return *value_handle;
7818 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007819 MaybeObject* raw_result =
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007820 this_handle->SetElementWithoutInterceptor(index,
7821 *value_handle,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007822 strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007823 check_prototype);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007824 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007825 return raw_result;
7826}
7827
7828
lrn@chromium.org303ada72010-10-27 09:33:13 +00007829MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
7830 Object* structure,
7831 uint32_t index,
7832 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007833 Isolate* isolate = GetIsolate();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00007834 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007835
7836 // api style callbacks.
7837 if (structure->IsAccessorInfo()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007838 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007839 Object* fun_obj = data->getter();
7840 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007841 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007842 Handle<JSObject> self(JSObject::cast(receiver));
7843 Handle<JSObject> holder_handle(JSObject::cast(holder));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007844 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7845 Handle<String> key(isolate->factory()->NumberToString(number));
7846 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
7847 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007848 v8::AccessorInfo info(args.end());
7849 v8::Handle<v8::Value> result;
7850 {
7851 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007852 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007853 result = call_fun(v8::Utils::ToLocal(key), info);
7854 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007855 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
7856 if (result.IsEmpty()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007857 return *v8::Utils::OpenHandle(*result);
7858 }
7859
7860 // __defineGetter__ callback
7861 if (structure->IsFixedArray()) {
7862 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
7863 if (getter->IsJSFunction()) {
7864 return Object::GetPropertyWithDefinedGetter(receiver,
7865 JSFunction::cast(getter));
7866 }
7867 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007868 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007869 }
7870
7871 UNREACHABLE();
7872 return NULL;
7873}
7874
7875
lrn@chromium.org303ada72010-10-27 09:33:13 +00007876MaybeObject* JSObject::SetElementWithCallback(Object* structure,
7877 uint32_t index,
7878 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007879 JSObject* holder,
7880 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007881 Isolate* isolate = GetIsolate();
7882 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007883
7884 // We should never get here to initialize a const with the hole
7885 // value since a const declaration would conflict with the setter.
7886 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007887 Handle<Object> value_handle(value, isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007888
7889 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00007890 // data structure used to store the callbacks. Eventually foreign
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007891 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00007892 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007893
7894 if (structure->IsAccessorInfo()) {
7895 // api style callbacks
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007896 Handle<JSObject> self(this);
7897 Handle<JSObject> holder_handle(JSObject::cast(holder));
7898 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007899 Object* call_obj = data->setter();
7900 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
7901 if (call_fun == NULL) return value;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007902 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7903 Handle<String> key(isolate->factory()->NumberToString(number));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007904 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
7905 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007906 v8::AccessorInfo info(args.end());
7907 {
7908 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007909 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007910 call_fun(v8::Utils::ToLocal(key),
7911 v8::Utils::ToLocal(value_handle),
7912 info);
7913 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007914 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007915 return *value_handle;
7916 }
7917
7918 if (structure->IsFixedArray()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007919 Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007920 if (setter->IsJSFunction()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007921 return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007922 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007923 if (strict_mode == kNonStrictMode) {
7924 return value;
7925 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007926 Handle<Object> holder_handle(holder, isolate);
7927 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007928 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007929 return isolate->Throw(
7930 *isolate->factory()->NewTypeError("no_setter_in_callback",
7931 HandleVector(args, 2)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007932 }
7933 }
7934
7935 UNREACHABLE();
7936 return NULL;
7937}
7938
7939
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007940// Adding n elements in fast case is O(n*n).
7941// Note: revisit design to have dual undefined values to capture absent
7942// elements.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007943MaybeObject* JSObject::SetFastElement(uint32_t index,
7944 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007945 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007946 bool check_prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007947 ASSERT(HasFastElements());
7948
lrn@chromium.org303ada72010-10-27 09:33:13 +00007949 Object* elms_obj;
7950 { MaybeObject* maybe_elms_obj = EnsureWritableFastElements();
7951 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
7952 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007953 FixedArray* elms = FixedArray::cast(elms_obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954 uint32_t elms_length = static_cast<uint32_t>(elms->length());
7955
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007956 if (check_prototype &&
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007957 (index >= elms_length || elms->get(index)->IsTheHole())) {
7958 bool found;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007959 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
7960 value,
7961 &found,
7962 strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007963 if (found) return result;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007964 }
7965
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007966 // Check whether there is extra space in fixed array..
7967 if (index < elms_length) {
7968 elms->set(index, value);
7969 if (IsJSArray()) {
7970 // Update the length of the array if needed.
7971 uint32_t array_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007972 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007973 if (index >= array_length) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007974 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007975 }
7976 }
ager@chromium.orgbdf2f942008-10-17 07:23:00 +00007977 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007978 }
7979
7980 // Allow gap in fast case.
7981 if ((index - elms_length) < kMaxGap) {
7982 // Try allocating extra space.
7983 int new_capacity = NewElementsCapacity(index+1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007984 if (new_capacity <= kMaxFastElementsLength ||
7985 !ShouldConvertToSlowElements(new_capacity)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007986 ASSERT(static_cast<uint32_t>(new_capacity) > index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007987 Object* obj;
7988 { MaybeObject* maybe_obj =
7989 SetFastElementsCapacityAndLength(new_capacity, index + 1);
7990 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7991 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007992 FixedArray::cast(elements())->set(index, value);
ager@chromium.orgbdf2f942008-10-17 07:23:00 +00007993 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007994 }
7995 }
7996
7997 // Otherwise default to slow case.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007998 Object* obj;
7999 { MaybeObject* maybe_obj = NormalizeElements();
8000 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8001 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008002 ASSERT(HasDictionaryElements());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008003 return SetElement(index, value, strict_mode, check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008004}
8005
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008006
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008007MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
8008 uint32_t index,
8009 Object* value,
8010 StrictModeFlag strict_mode,
8011 bool check_prototype) {
8012 ASSERT(HasFastDoubleElements());
8013
8014 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8015 uint32_t elms_length = static_cast<uint32_t>(elms->length());
8016
8017 // If storing to an element that isn't in the array, pass the store request
8018 // up the prototype chain before storing in the receiver's elements.
8019 if (check_prototype &&
8020 (index >= elms_length || elms->is_the_hole(index))) {
8021 bool found;
8022 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8023 value,
8024 &found,
8025 strict_mode);
8026 if (found) return result;
8027 }
8028
8029 // If the value object is not a heap number, switch to fast elements and try
8030 // again.
8031 bool value_is_smi = value->IsSmi();
8032 if (!value->IsNumber()) {
8033 Object* obj;
8034 uint32_t length = elms_length;
8035 if (IsJSArray()) {
8036 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
8037 }
8038 MaybeObject* maybe_obj =
8039 SetFastElementsCapacityAndLength(elms_length, length);
8040 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8041 return SetFastElement(index, value, strict_mode, check_prototype);
8042 }
8043
8044 double double_value = value_is_smi
8045 ? static_cast<double>(Smi::cast(value)->value())
8046 : HeapNumber::cast(value)->value();
8047
8048 // Check whether there is extra space in the fixed array.
8049 if (index < elms_length) {
8050 elms->set(index, double_value);
8051 if (IsJSArray()) {
8052 // Update the length of the array if needed.
8053 uint32_t array_length = 0;
8054 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
8055 if (index >= array_length) {
8056 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
8057 }
8058 }
8059 return value;
8060 }
8061
8062 // Allow gap in fast case.
8063 if ((index - elms_length) < kMaxGap) {
8064 // Try allocating extra space.
8065 int new_capacity = NewElementsCapacity(index+1);
8066 if (new_capacity <= kMaxFastElementsLength ||
8067 !ShouldConvertToSlowElements(new_capacity)) {
8068 ASSERT(static_cast<uint32_t>(new_capacity) > index);
8069 Object* obj;
8070 { MaybeObject* maybe_obj =
8071 SetFastDoubleElementsCapacityAndLength(new_capacity,
8072 index + 1);
8073 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8074 }
8075 FixedDoubleArray::cast(elements())->set(index, double_value);
8076 return value;
8077 }
8078 }
8079
8080 // Otherwise default to slow case.
8081 Object* obj;
8082 { MaybeObject* maybe_obj = NormalizeElements();
8083 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8084 }
8085 ASSERT(HasDictionaryElements());
8086 return SetElement(index, value, strict_mode, check_prototype);
8087}
8088
8089
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008090MaybeObject* JSObject::SetElement(uint32_t index,
8091 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008092 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008093 bool check_prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008094 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008095 if (IsAccessCheckNeeded()) {
8096 Heap* heap = GetHeap();
8097 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
8098 HandleScope scope;
8099 Handle<Object> value_handle(value);
8100 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
8101 return *value_handle;
8102 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008103 }
8104
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008105 if (IsJSGlobalProxy()) {
8106 Object* proto = GetPrototype();
8107 if (proto->IsNull()) return value;
8108 ASSERT(proto->IsJSGlobalObject());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008109 return JSObject::cast(proto)->SetElement(index,
8110 value,
8111 strict_mode,
8112 check_prototype);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008113 }
8114
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008115 // Check for lookup interceptor
8116 if (HasIndexedInterceptor()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008117 return SetElementWithInterceptor(index,
8118 value,
8119 strict_mode,
8120 check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008121 }
8122
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008123 return SetElementWithoutInterceptor(index,
8124 value,
8125 strict_mode,
8126 check_prototype);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008127}
8128
8129
lrn@chromium.org303ada72010-10-27 09:33:13 +00008130MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008131 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008132 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008133 bool check_prototype) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008134 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008135 switch (GetElementsKind()) {
8136 case FAST_ELEMENTS:
8137 // Fast case.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008138 return SetFastElement(index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008139 case FAST_DOUBLE_ELEMENTS:
8140 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008141 case EXTERNAL_PIXEL_ELEMENTS: {
8142 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008143 return pixels->SetValue(index, value);
8144 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008145 case EXTERNAL_BYTE_ELEMENTS: {
8146 ExternalByteArray* array = ExternalByteArray::cast(elements());
8147 return array->SetValue(index, value);
8148 }
8149 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8150 ExternalUnsignedByteArray* array =
8151 ExternalUnsignedByteArray::cast(elements());
8152 return array->SetValue(index, value);
8153 }
8154 case EXTERNAL_SHORT_ELEMENTS: {
8155 ExternalShortArray* array = ExternalShortArray::cast(elements());
8156 return array->SetValue(index, value);
8157 }
8158 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8159 ExternalUnsignedShortArray* array =
8160 ExternalUnsignedShortArray::cast(elements());
8161 return array->SetValue(index, value);
8162 }
8163 case EXTERNAL_INT_ELEMENTS: {
8164 ExternalIntArray* array = ExternalIntArray::cast(elements());
8165 return array->SetValue(index, value);
8166 }
8167 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8168 ExternalUnsignedIntArray* array =
8169 ExternalUnsignedIntArray::cast(elements());
8170 return array->SetValue(index, value);
8171 }
8172 case EXTERNAL_FLOAT_ELEMENTS: {
8173 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
8174 return array->SetValue(index, value);
8175 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008176 case EXTERNAL_DOUBLE_ELEMENTS: {
8177 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
8178 return array->SetValue(index, value);
8179 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008180 case DICTIONARY_ELEMENTS: {
8181 // Insert element in the dictionary.
8182 FixedArray* elms = FixedArray::cast(elements());
8183 NumberDictionary* dictionary = NumberDictionary::cast(elms);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008184
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008185 int entry = dictionary->FindEntry(index);
8186 if (entry != NumberDictionary::kNotFound) {
8187 Object* element = dictionary->ValueAt(entry);
8188 PropertyDetails details = dictionary->DetailsAt(entry);
8189 if (details.type() == CALLBACKS) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008190 return SetElementWithCallback(element,
8191 index,
8192 value,
8193 this,
8194 strict_mode);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008195 } else {
8196 dictionary->UpdateMaxNumberKey(index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008197 // If put fails instrict mode, throw exception.
8198 if (!dictionary->ValueAtPut(entry, value) &&
8199 strict_mode == kStrictMode) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008200 Handle<Object> holder(this);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008201 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008202 Handle<Object> args[2] = { number, holder };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008203 return isolate->Throw(
8204 *isolate->factory()->NewTypeError("strict_read_only_property",
8205 HandleVector(args, 2)));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008206 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008207 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008208 } else {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008209 // Index not already used. Look for an accessor in the prototype chain.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008210 if (check_prototype) {
8211 bool found;
8212 MaybeObject* result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008213 // Strict mode not needed. No-setter case already handled.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008214 SetElementWithCallbackSetterInPrototypes(index,
8215 value,
8216 &found,
8217 strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008218 if (found) return result;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008219 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00008220 // When we set the is_extensible flag to false we always force
8221 // the element into dictionary mode (and force them to stay there).
8222 if (!map()->is_extensible()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008223 if (strict_mode == kNonStrictMode) {
8224 return isolate->heap()->undefined_value();
8225 } else {
8226 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
8227 Handle<String> index_string(
8228 isolate->factory()->NumberToString(number));
8229 Handle<Object> args[1] = { index_string };
8230 return isolate->Throw(
8231 *isolate->factory()->NewTypeError("object_not_extensible",
8232 HandleVector(args, 1)));
8233 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00008234 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008235 Object* result;
8236 { MaybeObject* maybe_result = dictionary->AtNumberPut(index, value);
8237 if (!maybe_result->ToObject(&result)) return maybe_result;
8238 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008239 if (elms != FixedArray::cast(result)) {
8240 set_elements(FixedArray::cast(result));
8241 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008242 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008243
8244 // Update the array length if this JSObject is an array.
8245 if (IsJSArray()) {
8246 JSArray* array = JSArray::cast(this);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008247 Object* return_value;
8248 { MaybeObject* maybe_return_value =
8249 array->JSArrayUpdateLengthFromIndex(index, value);
8250 if (!maybe_return_value->ToObject(&return_value)) {
8251 return maybe_return_value;
8252 }
8253 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008254 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008255
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008256 // Attempt to put this object back in fast case.
8257 if (ShouldConvertToFastElements()) {
8258 uint32_t new_length = 0;
8259 if (IsJSArray()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008260 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008261 } else {
8262 new_length = NumberDictionary::cast(elements())->max_number_key() + 1;
8263 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008264 if (ShouldConvertToFastDoubleElements()) {
8265 Object* obj;
8266 { MaybeObject* maybe_obj =
8267 SetFastDoubleElementsCapacityAndLength(new_length, new_length);
8268 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8269 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008270#ifdef DEBUG
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008271 if (FLAG_trace_normalization) {
8272 PrintF("Object elements are fast double case again:\n");
8273 Print();
8274 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008275#endif
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008276 } else {
8277 Object* obj;
8278 { MaybeObject* maybe_obj =
8279 SetFastElementsCapacityAndLength(new_length, new_length);
8280 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8281 }
8282#ifdef DEBUG
8283 if (FLAG_trace_normalization) {
8284 PrintF("Object elements are fast case again:\n");
8285 Print();
8286 }
8287#endif
8288 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008289 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008290
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008291 return value;
8292 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008293 }
8294 // All possible cases have been handled above. Add a return to avoid the
8295 // complaints from the compiler.
8296 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008297 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008298}
8299
8300
lrn@chromium.org303ada72010-10-27 09:33:13 +00008301MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
8302 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303 uint32_t old_len = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008304 CHECK(length()->ToArrayIndex(&old_len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305 // Check to see if we need to update the length. For now, we make
8306 // sure that the length stays within 32-bits (unsigned).
8307 if (index >= old_len && index != 0xffffffff) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008308 Object* len;
8309 { MaybeObject* maybe_len =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008310 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008311 if (!maybe_len->ToObject(&len)) return maybe_len;
8312 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008313 set_length(len);
8314 }
8315 return value;
8316}
8317
8318
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008319MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008320 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321 // Get element works for both JSObject and JSArray since
8322 // JSArray::length cannot change.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008323 switch (GetElementsKind()) {
8324 case FAST_ELEMENTS: {
8325 FixedArray* elms = FixedArray::cast(elements());
8326 if (index < static_cast<uint32_t>(elms->length())) {
8327 Object* value = elms->get(index);
8328 if (!value->IsTheHole()) return value;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008329 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008330 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008331 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008332 case FAST_DOUBLE_ELEMENTS: {
8333 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8334 if (index < static_cast<uint32_t>(elms->length())) {
8335 if (!elms->is_the_hole(index)) {
8336 return GetHeap()->NumberFromDouble(elms->get(index));
8337 }
8338 }
8339 break;
8340 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008341 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00008342 case EXTERNAL_BYTE_ELEMENTS:
8343 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8344 case EXTERNAL_SHORT_ELEMENTS:
8345 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8346 case EXTERNAL_INT_ELEMENTS:
8347 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008348 case EXTERNAL_FLOAT_ELEMENTS:
8349 case EXTERNAL_DOUBLE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008350 MaybeObject* maybe_value = GetExternalElement(index);
8351 Object* value;
8352 if (!maybe_value->ToObject(&value)) return maybe_value;
8353 if (!value->IsUndefined()) return value;
ager@chromium.org3811b432009-10-28 14:53:37 +00008354 break;
8355 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008356 case DICTIONARY_ELEMENTS: {
8357 NumberDictionary* dictionary = element_dictionary();
8358 int entry = dictionary->FindEntry(index);
8359 if (entry != NumberDictionary::kNotFound) {
8360 Object* element = dictionary->ValueAt(entry);
8361 PropertyDetails details = dictionary->DetailsAt(entry);
8362 if (details.type() == CALLBACKS) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008363 return GetElementWithCallback(receiver,
8364 element,
8365 index,
8366 this);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008367 }
8368 return element;
8369 }
8370 break;
8371 }
8372 default:
8373 UNREACHABLE();
8374 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008375 }
8376
8377 // Continue searching via the prototype chain.
8378 Object* pt = GetPrototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008379 if (pt->IsNull()) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008380 return pt->GetElementWithReceiver(receiver, index);
8381}
8382
8383
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008384MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008385 uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008386 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008387 // Make sure that the top context does not change when doing
8388 // callbacks or interceptor calls.
8389 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008390 HandleScope scope(isolate);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008391 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
8392 Handle<Object> this_handle(receiver, isolate);
8393 Handle<JSObject> holder_handle(this, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008394 if (!interceptor->getter()->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008395 v8::IndexedPropertyGetter getter =
8396 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008397 LOG(isolate,
8398 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
8399 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008400 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 v8::Handle<v8::Value> result;
8402 {
8403 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008404 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008405 result = getter(index, info);
8406 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008407 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008408 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
8409 }
8410
lrn@chromium.org303ada72010-10-27 09:33:13 +00008411 MaybeObject* raw_result =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008412 holder_handle->GetElementPostInterceptor(*this_handle, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008413 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008414 return raw_result;
8415}
8416
8417
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008418MaybeObject* JSObject::GetElementWithReceiver(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008419 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008420 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008421 if (IsAccessCheckNeeded()) {
8422 Heap* heap = GetHeap();
8423 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) {
8424 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
8425 return heap->undefined_value();
8426 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008427 }
8428
8429 if (HasIndexedInterceptor()) {
8430 return GetElementWithInterceptor(receiver, index);
8431 }
8432
8433 // Get element works for both JSObject and JSArray since
8434 // JSArray::length cannot change.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008435 switch (GetElementsKind()) {
8436 case FAST_ELEMENTS: {
8437 FixedArray* elms = FixedArray::cast(elements());
8438 if (index < static_cast<uint32_t>(elms->length())) {
8439 Object* value = elms->get(index);
8440 if (!value->IsTheHole()) return value;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008441 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008442 break;
8443 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008444 case FAST_DOUBLE_ELEMENTS: {
8445 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8446 if (index < static_cast<uint32_t>(elms->length())) {
8447 if (!elms->is_the_hole(index)) {
8448 double double_value = elms->get(index);
8449 return GetHeap()->NumberFromDouble(double_value);
8450 }
8451 }
8452 break;
8453 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008454 case EXTERNAL_PIXEL_ELEMENTS:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00008455 case EXTERNAL_BYTE_ELEMENTS:
8456 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8457 case EXTERNAL_SHORT_ELEMENTS:
8458 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8459 case EXTERNAL_INT_ELEMENTS:
8460 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008461 case EXTERNAL_FLOAT_ELEMENTS:
8462 case EXTERNAL_DOUBLE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008463 MaybeObject* maybe_value = GetExternalElement(index);
8464 Object* value;
8465 if (!maybe_value->ToObject(&value)) return maybe_value;
8466 if (!value->IsUndefined()) return value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00008467 break;
8468 }
8469 case DICTIONARY_ELEMENTS: {
8470 NumberDictionary* dictionary = element_dictionary();
8471 int entry = dictionary->FindEntry(index);
8472 if (entry != NumberDictionary::kNotFound) {
8473 Object* element = dictionary->ValueAt(entry);
8474 PropertyDetails details = dictionary->DetailsAt(entry);
8475 if (details.type() == CALLBACKS) {
8476 return GetElementWithCallback(receiver,
8477 element,
8478 index,
8479 this);
8480 }
8481 return element;
8482 }
8483 break;
8484 }
8485 }
8486
8487 Object* pt = GetPrototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008488 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008489 if (pt == heap->null_value()) return heap->undefined_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00008490 return pt->GetElementWithReceiver(receiver, index);
8491}
8492
8493
8494MaybeObject* JSObject::GetExternalElement(uint32_t index) {
8495 // Get element works for both JSObject and JSArray since
8496 // JSArray::length cannot change.
8497 switch (GetElementsKind()) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008498 case EXTERNAL_PIXEL_ELEMENTS: {
8499 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008500 if (index < static_cast<uint32_t>(pixels->length())) {
8501 uint8_t value = pixels->get(index);
8502 return Smi::FromInt(value);
8503 }
8504 break;
8505 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008506 case EXTERNAL_BYTE_ELEMENTS: {
8507 ExternalByteArray* array = ExternalByteArray::cast(elements());
8508 if (index < static_cast<uint32_t>(array->length())) {
8509 int8_t value = array->get(index);
8510 return Smi::FromInt(value);
8511 }
8512 break;
8513 }
8514 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8515 ExternalUnsignedByteArray* array =
8516 ExternalUnsignedByteArray::cast(elements());
8517 if (index < static_cast<uint32_t>(array->length())) {
8518 uint8_t value = array->get(index);
8519 return Smi::FromInt(value);
8520 }
8521 break;
8522 }
8523 case EXTERNAL_SHORT_ELEMENTS: {
8524 ExternalShortArray* array = ExternalShortArray::cast(elements());
8525 if (index < static_cast<uint32_t>(array->length())) {
8526 int16_t value = array->get(index);
8527 return Smi::FromInt(value);
8528 }
8529 break;
8530 }
8531 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8532 ExternalUnsignedShortArray* array =
8533 ExternalUnsignedShortArray::cast(elements());
8534 if (index < static_cast<uint32_t>(array->length())) {
8535 uint16_t value = array->get(index);
8536 return Smi::FromInt(value);
8537 }
8538 break;
8539 }
8540 case EXTERNAL_INT_ELEMENTS: {
8541 ExternalIntArray* array = ExternalIntArray::cast(elements());
8542 if (index < static_cast<uint32_t>(array->length())) {
8543 int32_t value = array->get(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008544 return GetHeap()->NumberFromInt32(value);
ager@chromium.org3811b432009-10-28 14:53:37 +00008545 }
8546 break;
8547 }
8548 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8549 ExternalUnsignedIntArray* array =
8550 ExternalUnsignedIntArray::cast(elements());
8551 if (index < static_cast<uint32_t>(array->length())) {
8552 uint32_t value = array->get(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008553 return GetHeap()->NumberFromUint32(value);
ager@chromium.org3811b432009-10-28 14:53:37 +00008554 }
8555 break;
8556 }
8557 case EXTERNAL_FLOAT_ELEMENTS: {
8558 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
8559 if (index < static_cast<uint32_t>(array->length())) {
8560 float value = array->get(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008561 return GetHeap()->AllocateHeapNumber(value);
ager@chromium.org3811b432009-10-28 14:53:37 +00008562 }
8563 break;
8564 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008565 case EXTERNAL_DOUBLE_ELEMENTS: {
8566 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
8567 if (index < static_cast<uint32_t>(array->length())) {
8568 double value = array->get(index);
8569 return GetHeap()->AllocateHeapNumber(value);
8570 }
8571 break;
8572 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008573 case FAST_DOUBLE_ELEMENTS:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00008574 case FAST_ELEMENTS:
8575 case DICTIONARY_ELEMENTS:
8576 UNREACHABLE();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008577 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008578 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008579 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008580}
8581
8582
8583bool JSObject::HasDenseElements() {
8584 int capacity = 0;
8585 int number_of_elements = 0;
8586
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008587 switch (GetElementsKind()) {
8588 case FAST_ELEMENTS: {
8589 FixedArray* elms = FixedArray::cast(elements());
8590 capacity = elms->length();
8591 for (int i = 0; i < capacity; i++) {
8592 if (!elms->get(i)->IsTheHole()) number_of_elements++;
8593 }
8594 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008595 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008596 case FAST_DOUBLE_ELEMENTS: {
8597 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8598 capacity = elms->length();
8599 for (int i = 0; i < capacity; i++) {
8600 if (!elms->is_the_hole(i)) number_of_elements++;
8601 }
8602 break;
8603 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008604 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00008605 case EXTERNAL_BYTE_ELEMENTS:
8606 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8607 case EXTERNAL_SHORT_ELEMENTS:
8608 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8609 case EXTERNAL_INT_ELEMENTS:
8610 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008611 case EXTERNAL_FLOAT_ELEMENTS:
8612 case EXTERNAL_DOUBLE_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008613 return true;
8614 }
8615 case DICTIONARY_ELEMENTS: {
8616 NumberDictionary* dictionary = NumberDictionary::cast(elements());
8617 capacity = dictionary->Capacity();
8618 number_of_elements = dictionary->NumberOfElements();
8619 break;
8620 }
8621 default:
8622 UNREACHABLE();
8623 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008624 }
8625
8626 if (capacity == 0) return true;
8627 return (number_of_elements > (capacity / 2));
8628}
8629
8630
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008631bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008632 // Keep the array in fast case if the current backing storage is
8633 // almost filled and if the new capacity is no more than twice the
8634 // old capacity.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008635 int elements_length = 0;
8636 if (HasFastElements()) {
8637 elements_length = FixedArray::cast(elements())->length();
8638 } else if (HasFastDoubleElements()) {
8639 elements_length = FixedDoubleArray::cast(elements())->length();
8640 } else {
8641 UNREACHABLE();
8642 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008643 return !HasDenseElements() || ((new_capacity / 2) > elements_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008644}
8645
8646
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008647bool JSObject::ShouldConvertToFastElements() {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008648 ASSERT(HasDictionaryElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008649 NumberDictionary* dictionary = NumberDictionary::cast(elements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008650 // If the elements are sparse, we should not go back to fast case.
8651 if (!HasDenseElements()) return false;
8652 // If an element has been added at a very high index in the elements
8653 // dictionary, we cannot go back to fast case.
8654 if (dictionary->requires_slow_elements()) return false;
8655 // An object requiring access checks is never allowed to have fast
8656 // elements. If it had fast elements we would skip security checks.
8657 if (IsAccessCheckNeeded()) return false;
8658 // If the dictionary backing storage takes up roughly half as much
8659 // space as a fast-case backing storage would the array should have
8660 // fast elements.
8661 uint32_t length = 0;
8662 if (IsJSArray()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008663 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008664 } else {
8665 length = dictionary->max_number_key();
8666 }
8667 return static_cast<uint32_t>(dictionary->Capacity()) >=
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008668 (length / (2 * NumberDictionary::kEntrySize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008669}
8670
8671
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008672bool JSObject::ShouldConvertToFastDoubleElements() {
8673 if (FLAG_unbox_double_arrays) {
8674 ASSERT(HasDictionaryElements());
8675 NumberDictionary* dictionary = NumberDictionary::cast(elements());
8676 for (int i = 0; i < dictionary->Capacity(); i++) {
8677 Object* key = dictionary->KeyAt(i);
8678 if (key->IsNumber()) {
8679 if (!dictionary->ValueAt(i)->IsNumber()) return false;
8680 }
8681 }
8682 return true;
8683 } else {
8684 return false;
8685 }
8686}
8687
8688
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008689// Certain compilers request function template instantiation when they
8690// see the definition of the other template functions in the
8691// class. This requires us to have the template functions put
8692// together, so even though this function belongs in objects-debug.cc,
8693// we keep it here instead to satisfy certain compilers.
whesse@chromium.org023421e2010-12-21 12:19:12 +00008694#ifdef OBJECT_PRINT
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008695template<typename Shape, typename Key>
whesse@chromium.org023421e2010-12-21 12:19:12 +00008696void Dictionary<Shape, Key>::Print(FILE* out) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008697 int capacity = HashTable<Shape, Key>::Capacity();
8698 for (int i = 0; i < capacity; i++) {
8699 Object* k = HashTable<Shape, Key>::KeyAt(i);
8700 if (HashTable<Shape, Key>::IsKey(k)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008701 PrintF(out, " ");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008702 if (k->IsString()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008703 String::cast(k)->StringPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008704 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008705 k->ShortPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008706 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008707 PrintF(out, ": ");
8708 ValueAt(i)->ShortPrint(out);
8709 PrintF(out, "\n");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008710 }
8711 }
8712}
8713#endif
8714
8715
8716template<typename Shape, typename Key>
8717void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008718 int pos = 0;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008719 int capacity = HashTable<Shape, Key>::Capacity();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008720 AssertNoAllocation no_gc;
8721 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008722 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008723 Object* k = Dictionary<Shape, Key>::KeyAt(i);
8724 if (Dictionary<Shape, Key>::IsKey(k)) {
8725 elements->set(pos++, ValueAt(i), mode);
8726 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008727 }
8728 ASSERT(pos == elements->length());
8729}
8730
8731
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008732InterceptorInfo* JSObject::GetNamedInterceptor() {
8733 ASSERT(map()->has_named_interceptor());
8734 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008735 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008736 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008737 constructor->shared()->get_api_func_data()->named_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008738 return InterceptorInfo::cast(result);
8739}
8740
8741
8742InterceptorInfo* JSObject::GetIndexedInterceptor() {
8743 ASSERT(map()->has_indexed_interceptor());
8744 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008745 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008746 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008747 constructor->shared()->get_api_func_data()->indexed_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008748 return InterceptorInfo::cast(result);
8749}
8750
8751
lrn@chromium.org303ada72010-10-27 09:33:13 +00008752MaybeObject* JSObject::GetPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008753 JSReceiver* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008754 String* name,
8755 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008756 // Check local property in holder, ignore interceptor.
8757 LookupResult result;
8758 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008759 if (result.IsProperty()) {
8760 return GetProperty(receiver, &result, name, attributes);
8761 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008762 // Continue searching via the prototype chain.
8763 Object* pt = GetPrototype();
8764 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008765 if (pt->IsNull()) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008766 return pt->GetPropertyWithReceiver(receiver, name, attributes);
8767}
8768
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008769
lrn@chromium.org303ada72010-10-27 09:33:13 +00008770MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008771 JSReceiver* receiver,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008772 String* name,
8773 PropertyAttributes* attributes) {
8774 // Check local property in holder, ignore interceptor.
8775 LookupResult result;
8776 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008777 if (result.IsProperty()) {
8778 return GetProperty(receiver, &result, name, attributes);
8779 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008780 return GetHeap()->undefined_value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008781}
8782
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008783
lrn@chromium.org303ada72010-10-27 09:33:13 +00008784MaybeObject* JSObject::GetPropertyWithInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008785 JSReceiver* receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00008786 String* name,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00008787 PropertyAttributes* attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008788 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008789 InterceptorInfo* interceptor = GetNamedInterceptor();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008790 HandleScope scope(isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008791 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008792 Handle<JSObject> holder_handle(this);
8793 Handle<String> name_handle(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008794
8795 if (!interceptor->getter()->IsUndefined()) {
8796 v8::NamedPropertyGetter getter =
8797 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008798 LOG(isolate,
8799 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
8800 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008801 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008802 v8::Handle<v8::Value> result;
8803 {
8804 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008805 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008806 result = getter(v8::Utils::ToLocal(name_handle), info);
8807 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008808 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008809 if (!result.IsEmpty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008810 *attributes = NONE;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00008811 return *v8::Utils::OpenHandle(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008812 }
8813 }
8814
lrn@chromium.org303ada72010-10-27 09:33:13 +00008815 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008816 *receiver_handle,
8817 *name_handle,
8818 attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008819 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00008820 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008821}
8822
8823
8824bool JSObject::HasRealNamedProperty(String* key) {
8825 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008826 if (IsAccessCheckNeeded()) {
8827 Heap* heap = GetHeap();
8828 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8829 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8830 return false;
8831 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008832 }
8833
8834 LookupResult result;
8835 LocalLookupRealNamedProperty(key, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008836 return result.IsProperty() && (result.type() != INTERCEPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008837}
8838
8839
8840bool JSObject::HasRealElementProperty(uint32_t index) {
8841 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008842 if (IsAccessCheckNeeded()) {
8843 Heap* heap = GetHeap();
8844 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8845 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8846 return false;
8847 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848 }
8849
8850 // Handle [] on String objects.
8851 if (this->IsStringObjectWithCharacterAt(index)) return true;
8852
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008853 switch (GetElementsKind()) {
8854 case FAST_ELEMENTS: {
8855 uint32_t length = IsJSArray() ?
8856 static_cast<uint32_t>(
8857 Smi::cast(JSArray::cast(this)->length())->value()) :
8858 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8859 return (index < length) &&
8860 !FixedArray::cast(elements())->get(index)->IsTheHole();
8861 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008862 case EXTERNAL_PIXEL_ELEMENTS: {
8863 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008864 return index < static_cast<uint32_t>(pixels->length());
8865 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008866 case EXTERNAL_BYTE_ELEMENTS:
8867 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8868 case EXTERNAL_SHORT_ELEMENTS:
8869 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8870 case EXTERNAL_INT_ELEMENTS:
8871 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008872 case EXTERNAL_FLOAT_ELEMENTS:
8873 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00008874 ExternalArray* array = ExternalArray::cast(elements());
8875 return index < static_cast<uint32_t>(array->length());
8876 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008877 case DICTIONARY_ELEMENTS: {
8878 return element_dictionary()->FindEntry(index)
8879 != NumberDictionary::kNotFound;
8880 }
8881 default:
8882 UNREACHABLE();
8883 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008884 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008885 // All possibilities have been handled above already.
8886 UNREACHABLE();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008887 return GetHeap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008888}
8889
8890
8891bool JSObject::HasRealNamedCallbackProperty(String* key) {
8892 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008893 if (IsAccessCheckNeeded()) {
8894 Heap* heap = GetHeap();
8895 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8896 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8897 return false;
8898 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008899 }
8900
8901 LookupResult result;
8902 LocalLookupRealNamedProperty(key, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008903 return result.IsProperty() && (result.type() == CALLBACKS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008904}
8905
8906
8907int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
8908 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00008909 DescriptorArray* descs = map()->instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008910 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00008911 for (int i = 0; i < descs->number_of_descriptors(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008912 PropertyDetails details(descs->GetDetails(i));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00008913 if (details.IsProperty() && (details.attributes() & filter) == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008914 result++;
8915 }
8916 }
8917 return result;
8918 } else {
8919 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
8920 }
8921}
8922
8923
8924int JSObject::NumberOfEnumProperties() {
8925 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
8926}
8927
8928
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008929void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008930 Object* temp = get(i);
8931 set(i, get(j));
8932 set(j, temp);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008933 if (this != numbers) {
8934 temp = numbers->get(i);
8935 numbers->set(i, numbers->get(j));
8936 numbers->set(j, temp);
8937 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008938}
8939
8940
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008941static void InsertionSortPairs(FixedArray* content,
8942 FixedArray* numbers,
8943 int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008944 for (int i = 1; i < len; i++) {
8945 int j = i;
8946 while (j > 0 &&
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008947 (NumberToUint32(numbers->get(j - 1)) >
8948 NumberToUint32(numbers->get(j)))) {
8949 content->SwapPairs(numbers, j - 1, j);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008950 j--;
8951 }
8952 }
8953}
8954
8955
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008956void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008957 // In-place heap sort.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008958 ASSERT(content->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008959
8960 // Bottom-up max-heap construction.
8961 for (int i = 1; i < len; ++i) {
8962 int child_index = i;
8963 while (child_index > 0) {
8964 int parent_index = ((child_index + 1) >> 1) - 1;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008965 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
8966 uint32_t child_value = NumberToUint32(numbers->get(child_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008967 if (parent_value < child_value) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008968 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008969 } else {
8970 break;
8971 }
8972 child_index = parent_index;
8973 }
8974 }
8975
8976 // Extract elements and create sorted array.
8977 for (int i = len - 1; i > 0; --i) {
8978 // Put max element at the back of the array.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008979 content->SwapPairs(numbers, 0, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008980 // Sift down the new top element.
8981 int parent_index = 0;
8982 while (true) {
8983 int child_index = ((parent_index + 1) << 1) - 1;
8984 if (child_index >= i) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008985 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
8986 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
8987 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008988 if (child_index + 1 >= i || child1_value > child2_value) {
8989 if (parent_value > child1_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008990 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008991 parent_index = child_index;
8992 } else {
8993 if (parent_value > child2_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008994 content->SwapPairs(numbers, parent_index, child_index + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008995 parent_index = child_index + 1;
8996 }
8997 }
8998 }
8999}
9000
9001
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009002// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
9003void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
9004 ASSERT(this->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009005 // For small arrays, simply use insertion sort.
9006 if (len <= 10) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009007 InsertionSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009008 return;
9009 }
9010 // Check the range of indices.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009011 uint32_t min_index = NumberToUint32(numbers->get(0));
9012 uint32_t max_index = min_index;
9013 uint32_t i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014 for (i = 1; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009015 if (NumberToUint32(numbers->get(i)) < min_index) {
9016 min_index = NumberToUint32(numbers->get(i));
9017 } else if (NumberToUint32(numbers->get(i)) > max_index) {
9018 max_index = NumberToUint32(numbers->get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019 }
9020 }
9021 if (max_index - min_index + 1 == len) {
9022 // Indices form a contiguous range, unless there are duplicates.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009023 // Do an in-place linear time sort assuming distinct numbers, but
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009024 // avoid hanging in case they are not.
9025 for (i = 0; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009026 uint32_t p;
9027 uint32_t j = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009028 // While the current element at i is not at its correct position p,
9029 // swap the elements at these two positions.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009030 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031 j++ < len) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009032 SwapPairs(numbers, i, p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009033 }
9034 }
9035 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009036 HeapSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009037 return;
9038 }
9039}
9040
9041
9042// Fill in the names of local properties into the supplied storage. The main
9043// purpose of this function is to provide reflection information for the object
9044// mirrors.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009045void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009046 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009047 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009048 DescriptorArray* descs = map()->instance_descriptors();
9049 for (int i = 0; i < descs->number_of_descriptors(); i++) {
9050 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009051 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009052 ASSERT(storage->length() >= index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053 } else {
9054 property_dictionary()->CopyKeysTo(storage);
9055 }
9056}
9057
9058
9059int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
9060 return GetLocalElementKeys(NULL, filter);
9061}
9062
9063
9064int JSObject::NumberOfEnumElements() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009065 // Fast case for objects with no elements.
9066 if (!IsJSValue() && HasFastElements()) {
9067 uint32_t length = IsJSArray() ?
9068 static_cast<uint32_t>(
9069 Smi::cast(JSArray::cast(this)->length())->value()) :
9070 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9071 if (length == 0) return 0;
9072 }
9073 // Compute the number of enumerable elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
9075}
9076
9077
9078int JSObject::GetLocalElementKeys(FixedArray* storage,
9079 PropertyAttributes filter) {
9080 int counter = 0;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009081 switch (GetElementsKind()) {
9082 case FAST_ELEMENTS: {
9083 int length = IsJSArray() ?
9084 Smi::cast(JSArray::cast(this)->length())->value() :
9085 FixedArray::cast(elements())->length();
9086 for (int i = 0; i < length; i++) {
9087 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
9088 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009089 storage->set(counter, Smi::FromInt(i));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009090 }
9091 counter++;
9092 }
9093 }
9094 ASSERT(!storage || storage->length() >= counter);
9095 break;
9096 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009097 case EXTERNAL_PIXEL_ELEMENTS: {
9098 int length = ExternalPixelArray::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009099 while (counter < length) {
9100 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009101 storage->set(counter, Smi::FromInt(counter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009102 }
9103 counter++;
9104 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009105 ASSERT(!storage || storage->length() >= counter);
9106 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009107 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009108 case EXTERNAL_BYTE_ELEMENTS:
9109 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9110 case EXTERNAL_SHORT_ELEMENTS:
9111 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9112 case EXTERNAL_INT_ELEMENTS:
9113 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009114 case EXTERNAL_FLOAT_ELEMENTS:
9115 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00009116 int length = ExternalArray::cast(elements())->length();
9117 while (counter < length) {
9118 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009119 storage->set(counter, Smi::FromInt(counter));
ager@chromium.org3811b432009-10-28 14:53:37 +00009120 }
9121 counter++;
9122 }
9123 ASSERT(!storage || storage->length() >= counter);
9124 break;
9125 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009126 case DICTIONARY_ELEMENTS: {
9127 if (storage != NULL) {
9128 element_dictionary()->CopyKeysTo(storage, filter);
9129 }
9130 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
9131 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009132 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009133 default:
9134 UNREACHABLE();
9135 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009136 }
9137
9138 if (this->IsJSValue()) {
9139 Object* val = JSValue::cast(this)->value();
9140 if (val->IsString()) {
9141 String* str = String::cast(val);
9142 if (storage) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009143 for (int i = 0; i < str->length(); i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009144 storage->set(counter + i, Smi::FromInt(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145 }
9146 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009147 counter += str->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009148 }
9149 }
9150 ASSERT(!storage || storage->length() == counter);
9151 return counter;
9152}
9153
9154
9155int JSObject::GetEnumElementKeys(FixedArray* storage) {
9156 return GetLocalElementKeys(storage,
9157 static_cast<PropertyAttributes>(DONT_ENUM));
9158}
9159
9160
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009161// StringKey simply carries a string object as key.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009162class StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163 public:
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009164 explicit StringKey(String* string) :
9165 string_(string),
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009166 hash_(HashForObject(string)) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009167
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009168 bool IsMatch(Object* string) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009169 // We know that all entries in a hash table had their hash keys created.
9170 // Use that knowledge to have fast failure.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009171 if (hash_ != HashForObject(string)) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009172 return false;
9173 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009174 return string_->Equals(String::cast(string));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175 }
9176
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009177 uint32_t Hash() { return hash_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009178
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009179 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009181 Object* AsObject() { return string_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009182
9183 String* string_;
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009184 uint32_t hash_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185};
9186
ager@chromium.org381abbb2009-02-25 13:23:22 +00009187
9188// StringSharedKeys are used as keys in the eval cache.
9189class StringSharedKey : public HashTableKey {
9190 public:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009191 StringSharedKey(String* source,
9192 SharedFunctionInfo* shared,
9193 StrictModeFlag strict_mode)
9194 : source_(source),
9195 shared_(shared),
9196 strict_mode_(strict_mode) { }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009197
9198 bool IsMatch(Object* other) {
9199 if (!other->IsFixedArray()) return false;
9200 FixedArray* pair = FixedArray::cast(other);
9201 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9202 if (shared != shared_) return false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009203 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9204 Smi::cast(pair->get(2))->value());
9205 if (strict_mode != strict_mode_) return false;
ager@chromium.org381abbb2009-02-25 13:23:22 +00009206 String* source = String::cast(pair->get(1));
9207 return source->Equals(source_);
9208 }
9209
ager@chromium.org381abbb2009-02-25 13:23:22 +00009210 static uint32_t StringSharedHashHelper(String* source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009211 SharedFunctionInfo* shared,
9212 StrictModeFlag strict_mode) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00009213 uint32_t hash = source->Hash();
9214 if (shared->HasSourceCode()) {
9215 // Instead of using the SharedFunctionInfo pointer in the hash
9216 // code computation, we use a combination of the hash of the
9217 // script source code and the start and end positions. We do
9218 // this to ensure that the cache entries can survive garbage
9219 // collection.
9220 Script* script = Script::cast(shared->script());
9221 hash ^= String::cast(script->source())->Hash();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009222 if (strict_mode == kStrictMode) hash ^= 0x8000;
ager@chromium.org381abbb2009-02-25 13:23:22 +00009223 hash += shared->start_position();
9224 }
9225 return hash;
9226 }
9227
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009228 uint32_t Hash() {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009229 return StringSharedHashHelper(source_, shared_, strict_mode_);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009230 }
9231
9232 uint32_t HashForObject(Object* obj) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00009233 FixedArray* pair = FixedArray::cast(obj);
9234 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9235 String* source = String::cast(pair->get(1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009236 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9237 Smi::cast(pair->get(2))->value());
9238 return StringSharedHashHelper(source, shared, strict_mode);
ager@chromium.org381abbb2009-02-25 13:23:22 +00009239 }
9240
lrn@chromium.org303ada72010-10-27 09:33:13 +00009241 MUST_USE_RESULT MaybeObject* AsObject() {
9242 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009243 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009244 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9245 }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009246 FixedArray* pair = FixedArray::cast(obj);
9247 pair->set(0, shared_);
9248 pair->set(1, source_);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009249 pair->set(2, Smi::FromInt(strict_mode_));
ager@chromium.org381abbb2009-02-25 13:23:22 +00009250 return pair;
9251 }
9252
ager@chromium.org381abbb2009-02-25 13:23:22 +00009253 private:
9254 String* source_;
9255 SharedFunctionInfo* shared_;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009256 StrictModeFlag strict_mode_;
ager@chromium.org381abbb2009-02-25 13:23:22 +00009257};
9258
9259
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009260// RegExpKey carries the source and flags of a regular expression as key.
9261class RegExpKey : public HashTableKey {
9262 public:
9263 RegExpKey(String* string, JSRegExp::Flags flags)
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009264 : string_(string),
9265 flags_(Smi::FromInt(flags.value())) { }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009266
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00009267 // Rather than storing the key in the hash table, a pointer to the
9268 // stored value is stored where the key should be. IsMatch then
9269 // compares the search key to the found object, rather than comparing
9270 // a key to a key.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009271 bool IsMatch(Object* obj) {
9272 FixedArray* val = FixedArray::cast(obj);
9273 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
9274 && (flags_ == val->get(JSRegExp::kFlagsIndex));
9275 }
9276
9277 uint32_t Hash() { return RegExpHash(string_, flags_); }
9278
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009279 Object* AsObject() {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009280 // Plain hash maps, which is where regexp keys are used, don't
9281 // use this function.
9282 UNREACHABLE();
9283 return NULL;
9284 }
9285
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009286 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009287 FixedArray* val = FixedArray::cast(obj);
9288 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
9289 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
9290 }
9291
9292 static uint32_t RegExpHash(String* string, Smi* flags) {
9293 return string->Hash() + flags->value();
9294 }
9295
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009296 String* string_;
9297 Smi* flags_;
9298};
9299
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009300// Utf8SymbolKey carries a vector of chars as key.
9301class Utf8SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009302 public:
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009303 explicit Utf8SymbolKey(Vector<const char> string)
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009304 : string_(string), hash_field_(0) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009305
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009306 bool IsMatch(Object* string) {
9307 return String::cast(string)->IsEqualTo(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009308 }
9309
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009310 uint32_t Hash() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009311 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312 unibrow::Utf8InputBuffer<> buffer(string_.start(),
9313 static_cast<unsigned>(string_.length()));
9314 chars_ = buffer.Length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009315 hash_field_ = String::ComputeHashField(&buffer, chars_);
9316 uint32_t result = hash_field_ >> String::kHashShift;
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009317 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9318 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009319 }
9320
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009321 uint32_t HashForObject(Object* other) {
9322 return String::cast(other)->Hash();
9323 }
9324
lrn@chromium.org303ada72010-10-27 09:33:13 +00009325 MaybeObject* AsObject() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009326 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009327 return Isolate::Current()->heap()->AllocateSymbol(
9328 string_, chars_, hash_field_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009329 }
9330
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009331 Vector<const char> string_;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009332 uint32_t hash_field_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009333 int chars_; // Caches the number of characters when computing the hash code.
9334};
9335
9336
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009337template <typename Char>
9338class SequentialSymbolKey : public HashTableKey {
9339 public:
9340 explicit SequentialSymbolKey(Vector<const Char> string)
9341 : string_(string), hash_field_(0) { }
9342
9343 uint32_t Hash() {
9344 StringHasher hasher(string_.length());
9345
9346 // Very long strings have a trivial hash that doesn't inspect the
9347 // string contents.
9348 if (hasher.has_trivial_hash()) {
9349 hash_field_ = hasher.GetHashField();
9350 } else {
9351 int i = 0;
9352 // Do the iterative array index computation as long as there is a
9353 // chance this is an array index.
9354 while (i < string_.length() && hasher.is_array_index()) {
9355 hasher.AddCharacter(static_cast<uc32>(string_[i]));
9356 i++;
9357 }
9358
9359 // Process the remaining characters without updating the array
9360 // index.
9361 while (i < string_.length()) {
9362 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
9363 i++;
9364 }
9365 hash_field_ = hasher.GetHashField();
9366 }
9367
9368 uint32_t result = hash_field_ >> String::kHashShift;
9369 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9370 return result;
9371 }
9372
9373
9374 uint32_t HashForObject(Object* other) {
9375 return String::cast(other)->Hash();
9376 }
9377
9378 Vector<const Char> string_;
9379 uint32_t hash_field_;
9380};
9381
9382
9383
9384class AsciiSymbolKey : public SequentialSymbolKey<char> {
9385 public:
9386 explicit AsciiSymbolKey(Vector<const char> str)
9387 : SequentialSymbolKey<char>(str) { }
9388
9389 bool IsMatch(Object* string) {
9390 return String::cast(string)->IsAsciiEqualTo(string_);
9391 }
9392
9393 MaybeObject* AsObject() {
9394 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009395 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009396 }
9397};
9398
9399
danno@chromium.org40cb8782011-05-25 07:58:50 +00009400class SubStringAsciiSymbolKey : public HashTableKey {
9401 public:
9402 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
9403 int from,
9404 int length)
9405 : string_(string), from_(from), length_(length) { }
9406
9407 uint32_t Hash() {
9408 ASSERT(length_ >= 0);
9409 ASSERT(from_ + length_ <= string_->length());
9410 StringHasher hasher(length_);
9411
9412 // Very long strings have a trivial hash that doesn't inspect the
9413 // string contents.
9414 if (hasher.has_trivial_hash()) {
9415 hash_field_ = hasher.GetHashField();
9416 } else {
9417 int i = 0;
9418 // Do the iterative array index computation as long as there is a
9419 // chance this is an array index.
9420 while (i < length_ && hasher.is_array_index()) {
9421 hasher.AddCharacter(static_cast<uc32>(
9422 string_->SeqAsciiStringGet(i + from_)));
9423 i++;
9424 }
9425
9426 // Process the remaining characters without updating the array
9427 // index.
9428 while (i < length_) {
9429 hasher.AddCharacterNoIndex(static_cast<uc32>(
9430 string_->SeqAsciiStringGet(i + from_)));
9431 i++;
9432 }
9433 hash_field_ = hasher.GetHashField();
9434 }
9435
9436 uint32_t result = hash_field_ >> String::kHashShift;
9437 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9438 return result;
9439 }
9440
9441
9442 uint32_t HashForObject(Object* other) {
9443 return String::cast(other)->Hash();
9444 }
9445
9446 bool IsMatch(Object* string) {
9447 Vector<const char> chars(string_->GetChars() + from_, length_);
9448 return String::cast(string)->IsAsciiEqualTo(chars);
9449 }
9450
9451 MaybeObject* AsObject() {
9452 if (hash_field_ == 0) Hash();
9453 Vector<const char> chars(string_->GetChars() + from_, length_);
9454 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
9455 }
9456
9457 private:
9458 Handle<SeqAsciiString> string_;
9459 int from_;
9460 int length_;
9461 uint32_t hash_field_;
9462};
9463
9464
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009465class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
9466 public:
9467 explicit TwoByteSymbolKey(Vector<const uc16> str)
9468 : SequentialSymbolKey<uc16>(str) { }
9469
9470 bool IsMatch(Object* string) {
9471 return String::cast(string)->IsTwoByteEqualTo(string_);
9472 }
9473
9474 MaybeObject* AsObject() {
9475 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009476 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009477 }
9478};
9479
9480
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009481// SymbolKey carries a string/symbol object as key.
9482class SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009483 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009484 explicit SymbolKey(String* string)
9485 : string_(string) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009486
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009487 bool IsMatch(Object* string) {
9488 return String::cast(string)->Equals(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009489 }
9490
9491 uint32_t Hash() { return string_->Hash(); }
9492
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009493 uint32_t HashForObject(Object* other) {
9494 return String::cast(other)->Hash();
9495 }
9496
lrn@chromium.org303ada72010-10-27 09:33:13 +00009497 MaybeObject* AsObject() {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00009498 // Attempt to flatten the string, so that symbols will most often
9499 // be flat strings.
9500 string_ = string_->TryFlattenGetString();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009501 Heap* heap = string_->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009502 // Transform string to symbol if possible.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009503 Map* map = heap->SymbolMapForString(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009504 if (map != NULL) {
9505 string_->set_map(map);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009506 ASSERT(string_->IsSymbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009507 return string_;
9508 }
9509 // Otherwise allocate a new symbol.
9510 StringInputBuffer buffer(string_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009511 return heap->AllocateInternalSymbol(&buffer,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009512 string_->length(),
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009513 string_->hash_field());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009514 }
9515
9516 static uint32_t StringHash(Object* obj) {
9517 return String::cast(obj)->Hash();
9518 }
9519
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009520 String* string_;
9521};
9522
9523
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009524template<typename Shape, typename Key>
9525void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009526 IteratePointers(v, 0, kElementsStartOffset);
9527}
9528
9529
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009530template<typename Shape, typename Key>
9531void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009532 IteratePointers(v,
9533 kElementsStartOffset,
9534 kHeaderSize + length() * kPointerSize);
9535}
9536
9537
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009538template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +00009539MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
9540 PretenureFlag pretenure) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009541 const int kMinCapacity = 32;
9542 int capacity = RoundUpToPowerOf2(at_least_space_for * 2);
9543 if (capacity < kMinCapacity) {
9544 capacity = kMinCapacity; // Guarantee min capacity.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009545 } else if (capacity > HashTable::kMaxCapacity) {
9546 return Failure::OutOfMemoryException();
9547 }
9548
lrn@chromium.org303ada72010-10-27 09:33:13 +00009549 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009550 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
9551 AllocateHashTable(EntryToIndex(capacity), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009552 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009553 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009554 HashTable::cast(obj)->SetNumberOfElements(0);
9555 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
9556 HashTable::cast(obj)->SetCapacity(capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009557 return obj;
9558}
9559
9560
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009561// Find entry for key otherwise return kNotFound.
ricow@chromium.org4980dff2010-07-19 08:33:45 +00009562int StringDictionary::FindEntry(String* key) {
9563 if (!key->IsSymbol()) {
9564 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
9565 }
9566
9567 // Optimized for symbol key. Knowledge of the key type allows:
9568 // 1. Move the check if the key is a symbol out of the loop.
9569 // 2. Avoid comparing hash codes in symbol to symbol comparision.
9570 // 3. Detect a case when a dictionary key is not a symbol but the key is.
9571 // In case of positive result the dictionary key may be replaced by
9572 // the symbol with minimal performance penalty. It gives a chance to
9573 // perform further lookups in code stubs (and significant performance boost
9574 // a certain style of code).
9575
9576 // EnsureCapacity will guarantee the hash table is never full.
9577 uint32_t capacity = Capacity();
9578 uint32_t entry = FirstProbe(key->Hash(), capacity);
9579 uint32_t count = 1;
9580
9581 while (true) {
9582 int index = EntryToIndex(entry);
9583 Object* element = get(index);
9584 if (element->IsUndefined()) break; // Empty entry.
9585 if (key == element) return entry;
9586 if (!element->IsSymbol() &&
9587 !element->IsNull() &&
9588 String::cast(element)->Equals(key)) {
9589 // Replace a non-symbol key by the equivalent symbol for faster further
9590 // lookups.
9591 set(index, key);
9592 return entry;
9593 }
9594 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
9595 entry = NextProbe(entry, count++, capacity);
9596 }
9597 return kNotFound;
9598}
9599
9600
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009601template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +00009602MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009603 int capacity = Capacity();
9604 int nof = NumberOfElements() + n;
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009605 int nod = NumberOfDeletedElements();
9606 // Return if:
9607 // 50% is still free after adding n elements and
9608 // at most 50% of the free elements are deleted elements.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009609 if (nod <= (capacity - nof) >> 1) {
9610 int needed_free = nof >> 1;
9611 if (nof + needed_free <= capacity) return this;
9612 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009613
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009614 const int kMinCapacityForPretenure = 256;
9615 bool pretenure =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009616 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009617 Object* obj;
9618 { MaybeObject* maybe_obj =
9619 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
9620 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9621 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009622
9623 AssertNoAllocation no_gc;
ager@chromium.org236ad962008-09-25 09:45:57 +00009624 HashTable* table = HashTable::cast(obj);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009625 WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009626
9627 // Copy prefix to new array.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009628 for (int i = kPrefixStartIndex;
9629 i < kPrefixStartIndex + Shape::kPrefixSize;
9630 i++) {
ager@chromium.org236ad962008-09-25 09:45:57 +00009631 table->set(i, get(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009632 }
9633 // Rehash the elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009634 for (int i = 0; i < capacity; i++) {
9635 uint32_t from_index = EntryToIndex(i);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009636 Object* k = get(from_index);
9637 if (IsKey(k)) {
9638 uint32_t hash = Shape::HashForObject(key, k);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009639 uint32_t insertion_index =
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009640 EntryToIndex(table->FindInsertionEntry(hash));
9641 for (int j = 0; j < Shape::kEntrySize; j++) {
ager@chromium.org236ad962008-09-25 09:45:57 +00009642 table->set(insertion_index + j, get(from_index + j), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009643 }
9644 }
9645 }
ager@chromium.org236ad962008-09-25 09:45:57 +00009646 table->SetNumberOfElements(NumberOfElements());
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009647 table->SetNumberOfDeletedElements(0);
ager@chromium.org236ad962008-09-25 09:45:57 +00009648 return table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009649}
9650
9651
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009652template<typename Shape, typename Key>
9653uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009654 uint32_t capacity = Capacity();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009655 uint32_t entry = FirstProbe(hash, capacity);
9656 uint32_t count = 1;
9657 // EnsureCapacity will guarantee the hash table is never full.
9658 while (true) {
9659 Object* element = KeyAt(entry);
9660 if (element->IsUndefined() || element->IsNull()) break;
9661 entry = NextProbe(entry, count++, capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009662 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009663 return entry;
9664}
9665
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009666// Force instantiation of template instances class.
9667// Please note this list is compiler dependent.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009668
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009669template class HashTable<SymbolTableShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009670
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009671template class HashTable<CompilationCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009672
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009673template class HashTable<MapCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009674
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009675template class Dictionary<StringDictionaryShape, String*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009676
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009677template class Dictionary<NumberDictionaryShape, uint32_t>;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009678
lrn@chromium.org303ada72010-10-27 09:33:13 +00009679template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009680 int);
9681
lrn@chromium.org303ada72010-10-27 09:33:13 +00009682template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009683 int);
9684
lrn@chromium.org303ada72010-10-27 09:33:13 +00009685template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009686 uint32_t, Object*);
9687
9688template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
9689 Object*);
9690
9691template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
9692 Object*);
9693
9694template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
9695 FixedArray*, PropertyAttributes);
9696
9697template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
9698 int, JSObject::DeleteMode);
9699
9700template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
9701 int, JSObject::DeleteMode);
9702
9703template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
9704 FixedArray*);
9705
9706template int
9707Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
9708 PropertyAttributes);
9709
lrn@chromium.org303ada72010-10-27 09:33:13 +00009710template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009711 String*, Object*, PropertyDetails);
9712
lrn@chromium.org303ada72010-10-27 09:33:13 +00009713template MaybeObject*
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009714Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
9715
9716template int
9717Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
9718 PropertyAttributes);
9719
lrn@chromium.org303ada72010-10-27 09:33:13 +00009720template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009721 uint32_t, Object*, PropertyDetails);
9722
lrn@chromium.org303ada72010-10-27 09:33:13 +00009723template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
9724 EnsureCapacity(int, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009725
lrn@chromium.org303ada72010-10-27 09:33:13 +00009726template MaybeObject* Dictionary<StringDictionaryShape, String*>::
9727 EnsureCapacity(int, String*);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009728
lrn@chromium.org303ada72010-10-27 09:33:13 +00009729template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009730 uint32_t, Object*, PropertyDetails, uint32_t);
9731
lrn@chromium.org303ada72010-10-27 09:33:13 +00009732template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009733 String*, Object*, PropertyDetails, uint32_t);
9734
9735template
9736int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
9737
9738template
9739int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009740
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009741template
9742int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
9743
9744
ager@chromium.org5ec48922009-05-05 07:25:34 +00009745// Collates undefined and unexisting elements below limit from position
9746// zero of the elements. The object stays in Dictionary mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009747MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009748 ASSERT(HasDictionaryElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009749 // Must stay in dictionary mode, either because of requires_slow_elements,
9750 // or because we are not going to sort (and therefore compact) all of the
9751 // elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009752 NumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009753 HeapNumber* result_double = NULL;
9754 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
9755 // Allocate space for result before we start mutating the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009756 Object* new_double;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009757 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009758 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
9759 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00009760 result_double = HeapNumber::cast(new_double);
9761 }
9762
lrn@chromium.org303ada72010-10-27 09:33:13 +00009763 Object* obj;
9764 { MaybeObject* maybe_obj =
9765 NumberDictionary::Allocate(dict->NumberOfElements());
9766 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9767 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009768 NumberDictionary* new_dict = NumberDictionary::cast(obj);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009769
9770 AssertNoAllocation no_alloc;
9771
ager@chromium.org5ec48922009-05-05 07:25:34 +00009772 uint32_t pos = 0;
9773 uint32_t undefs = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009774 int capacity = dict->Capacity();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009775 for (int i = 0; i < capacity; i++) {
9776 Object* k = dict->KeyAt(i);
9777 if (dict->IsKey(k)) {
9778 ASSERT(k->IsNumber());
9779 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
9780 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
9781 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
9782 Object* value = dict->ValueAt(i);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009783 PropertyDetails details = dict->DetailsAt(i);
9784 if (details.type() == CALLBACKS) {
9785 // Bail out and do the sorting of undefineds and array holes in JS.
9786 return Smi::FromInt(-1);
9787 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00009788 uint32_t key = NumberToUint32(k);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009789 // In the following we assert that adding the entry to the new dictionary
9790 // does not cause GC. This is the case because we made sure to allocate
9791 // the dictionary big enough above, so it need not grow.
ager@chromium.org5ec48922009-05-05 07:25:34 +00009792 if (key < limit) {
9793 if (value->IsUndefined()) {
9794 undefs++;
9795 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009796 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
9797 // Adding an entry with the key beyond smi-range requires
9798 // allocation. Bailout.
9799 return Smi::FromInt(-1);
9800 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009801 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009802 pos++;
9803 }
9804 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009805 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
9806 // Adding an entry with the key beyond smi-range requires
9807 // allocation. Bailout.
9808 return Smi::FromInt(-1);
9809 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009810 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009811 }
9812 }
9813 }
9814
9815 uint32_t result = pos;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009816 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009817 Heap* heap = GetHeap();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009818 while (undefs > 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009819 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
9820 // Adding an entry with the key beyond smi-range requires
9821 // allocation. Bailout.
9822 return Smi::FromInt(-1);
9823 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009824 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
lrn@chromium.org303ada72010-10-27 09:33:13 +00009825 ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009826 pos++;
9827 undefs--;
9828 }
9829
9830 set_elements(new_dict);
9831
9832 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
9833 return Smi::FromInt(static_cast<int>(result));
9834 }
9835
9836 ASSERT_NE(NULL, result_double);
9837 result_double->set_value(static_cast<double>(result));
9838 return result_double;
9839}
9840
9841
9842// Collects all defined (non-hole) and non-undefined (array) elements at
9843// the start of the elements array.
9844// If the object is in dictionary mode, it is converted to fast elements
9845// mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009846MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009847 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009849 Heap* heap = GetHeap();
9850
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009851 if (HasDictionaryElements()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009852 // Convert to fast elements containing only the existing properties.
9853 // Ordering is irrelevant, since we are going to sort anyway.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009854 NumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009855 if (IsJSArray() || dict->requires_slow_elements() ||
9856 dict->max_number_key() >= limit) {
9857 return PrepareSlowElementsForSort(limit);
9858 }
9859 // Convert to fast elements.
9860
lrn@chromium.org303ada72010-10-27 09:33:13 +00009861 Object* obj;
9862 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
9863 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9864 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009865 Map* new_map = Map::cast(obj);
9866
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009867 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009868 Object* new_array;
9869 { MaybeObject* maybe_new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009870 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009871 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
9872 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00009873 FixedArray* fast_elements = FixedArray::cast(new_array);
9874 dict->CopyValuesTo(fast_elements);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009875
9876 set_map(new_map);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009877 set_elements(fast_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00009878 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009879 Object* obj;
9880 { MaybeObject* maybe_obj = EnsureWritableFastElements();
9881 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9882 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00009883 }
9884 ASSERT(HasFastElements());
9885
9886 // Collect holes at the end, undefined before that and the rest at the
9887 // start, and return the number of non-hole, non-undefined values.
9888
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009889 FixedArray* elements = FixedArray::cast(this->elements());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009890 uint32_t elements_length = static_cast<uint32_t>(elements->length());
9891 if (limit > elements_length) {
9892 limit = elements_length ;
9893 }
9894 if (limit == 0) {
9895 return Smi::FromInt(0);
9896 }
9897
9898 HeapNumber* result_double = NULL;
9899 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
9900 // Pessimistically allocate space for return value before
9901 // we start mutating the array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009902 Object* new_double;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009903 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009904 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
9905 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00009906 result_double = HeapNumber::cast(new_double);
9907 }
9908
9909 AssertNoAllocation no_alloc;
9910
9911 // Split elements into defined, undefined and the_hole, in that order.
9912 // Only count locations for undefined and the hole, and fill them afterwards.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009913 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009914 unsigned int undefs = limit;
9915 unsigned int holes = limit;
9916 // Assume most arrays contain no holes and undefined values, so minimize the
9917 // number of stores of non-undefined, non-the-hole values.
9918 for (unsigned int i = 0; i < undefs; i++) {
9919 Object* current = elements->get(i);
9920 if (current->IsTheHole()) {
9921 holes--;
9922 undefs--;
9923 } else if (current->IsUndefined()) {
9924 undefs--;
9925 } else {
9926 continue;
9927 }
9928 // Position i needs to be filled.
9929 while (undefs > i) {
9930 current = elements->get(undefs);
9931 if (current->IsTheHole()) {
9932 holes--;
9933 undefs--;
9934 } else if (current->IsUndefined()) {
9935 undefs--;
9936 } else {
9937 elements->set(i, current, write_barrier);
9938 break;
9939 }
9940 }
9941 }
9942 uint32_t result = undefs;
9943 while (undefs < holes) {
9944 elements->set_undefined(undefs);
9945 undefs++;
9946 }
9947 while (holes < limit) {
9948 elements->set_the_hole(holes);
9949 holes++;
9950 }
9951
9952 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
9953 return Smi::FromInt(static_cast<int>(result));
9954 }
9955 ASSERT_NE(NULL, result_double);
9956 result_double->set_value(static_cast<double>(result));
9957 return result_double;
9958}
9959
9960
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009961Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009962 uint8_t clamped_value = 0;
9963 if (index < static_cast<uint32_t>(length())) {
9964 if (value->IsSmi()) {
9965 int int_value = Smi::cast(value)->value();
9966 if (int_value < 0) {
9967 clamped_value = 0;
9968 } else if (int_value > 255) {
9969 clamped_value = 255;
9970 } else {
9971 clamped_value = static_cast<uint8_t>(int_value);
9972 }
9973 } else if (value->IsHeapNumber()) {
9974 double double_value = HeapNumber::cast(value)->value();
9975 if (!(double_value > 0)) {
9976 // NaN and less than zero clamp to zero.
9977 clamped_value = 0;
9978 } else if (double_value > 255) {
9979 // Greater than 255 clamp to 255.
9980 clamped_value = 255;
9981 } else {
9982 // Other doubles are rounded to the nearest integer.
9983 clamped_value = static_cast<uint8_t>(double_value + 0.5);
9984 }
9985 } else {
9986 // Clamp undefined to zero (default). All other types have been
9987 // converted to a number type further up in the call chain.
9988 ASSERT(value->IsUndefined());
9989 }
9990 set(index, clamped_value);
9991 }
9992 return Smi::FromInt(clamped_value);
9993}
9994
9995
ager@chromium.org3811b432009-10-28 14:53:37 +00009996template<typename ExternalArrayClass, typename ValueType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009997static MaybeObject* ExternalArrayIntSetter(Heap* heap,
9998 ExternalArrayClass* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009999 uint32_t index,
10000 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010001 ValueType cast_value = 0;
10002 if (index < static_cast<uint32_t>(receiver->length())) {
10003 if (value->IsSmi()) {
10004 int int_value = Smi::cast(value)->value();
10005 cast_value = static_cast<ValueType>(int_value);
10006 } else if (value->IsHeapNumber()) {
10007 double double_value = HeapNumber::cast(value)->value();
10008 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
10009 } else {
10010 // Clamp undefined to zero (default). All other types have been
10011 // converted to a number type further up in the call chain.
10012 ASSERT(value->IsUndefined());
10013 }
10014 receiver->set(index, cast_value);
10015 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010016 return heap->NumberFromInt32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010017}
10018
10019
lrn@chromium.org303ada72010-10-27 09:33:13 +000010020MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010021 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010022 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010023}
10024
10025
lrn@chromium.org303ada72010-10-27 09:33:13 +000010026MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
10027 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010028 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010029 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010030}
10031
10032
lrn@chromium.org303ada72010-10-27 09:33:13 +000010033MaybeObject* ExternalShortArray::SetValue(uint32_t index,
10034 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010035 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010036 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010037}
10038
10039
lrn@chromium.org303ada72010-10-27 09:33:13 +000010040MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
10041 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010042 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010043 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010044}
10045
10046
lrn@chromium.org303ada72010-10-27 09:33:13 +000010047MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010048 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010049 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010050}
10051
10052
lrn@chromium.org303ada72010-10-27 09:33:13 +000010053MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010054 uint32_t cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010055 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000010056 if (index < static_cast<uint32_t>(length())) {
10057 if (value->IsSmi()) {
10058 int int_value = Smi::cast(value)->value();
10059 cast_value = static_cast<uint32_t>(int_value);
10060 } else if (value->IsHeapNumber()) {
10061 double double_value = HeapNumber::cast(value)->value();
10062 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
10063 } else {
10064 // Clamp undefined to zero (default). All other types have been
10065 // converted to a number type further up in the call chain.
10066 ASSERT(value->IsUndefined());
10067 }
10068 set(index, cast_value);
10069 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010070 return heap->NumberFromUint32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010071}
10072
10073
lrn@chromium.org303ada72010-10-27 09:33:13 +000010074MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010075 float cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010076 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000010077 if (index < static_cast<uint32_t>(length())) {
10078 if (value->IsSmi()) {
10079 int int_value = Smi::cast(value)->value();
10080 cast_value = static_cast<float>(int_value);
10081 } else if (value->IsHeapNumber()) {
10082 double double_value = HeapNumber::cast(value)->value();
10083 cast_value = static_cast<float>(double_value);
10084 } else {
10085 // Clamp undefined to zero (default). All other types have been
10086 // converted to a number type further up in the call chain.
10087 ASSERT(value->IsUndefined());
10088 }
10089 set(index, cast_value);
10090 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010091 return heap->AllocateHeapNumber(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010092}
10093
10094
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010095MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
10096 double double_value = 0;
10097 Heap* heap = GetHeap();
10098 if (index < static_cast<uint32_t>(length())) {
10099 if (value->IsSmi()) {
10100 int int_value = Smi::cast(value)->value();
10101 double_value = static_cast<double>(int_value);
10102 } else if (value->IsHeapNumber()) {
10103 double_value = HeapNumber::cast(value)->value();
10104 } else {
10105 // Clamp undefined to zero (default). All other types have been
10106 // converted to a number type further up in the call chain.
10107 ASSERT(value->IsUndefined());
10108 }
10109 set(index, double_value);
10110 }
10111 return heap->AllocateHeapNumber(double_value);
10112}
10113
10114
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010115JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010116 ASSERT(!HasFastProperties());
10117 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010118 return JSGlobalPropertyCell::cast(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010119}
10120
10121
lrn@chromium.org303ada72010-10-27 09:33:13 +000010122MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010123 ASSERT(!HasFastProperties());
10124 int entry = property_dictionary()->FindEntry(name);
10125 if (entry == StringDictionary::kNotFound) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010126 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010127 Object* cell;
10128 { MaybeObject* maybe_cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010129 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010130 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
10131 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010132 PropertyDetails details(NONE, NORMAL);
10133 details = details.AsDeleted();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010134 Object* dictionary;
10135 { MaybeObject* maybe_dictionary =
10136 property_dictionary()->Add(name, cell, details);
10137 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
10138 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010139 set_properties(StringDictionary::cast(dictionary));
10140 return cell;
10141 } else {
10142 Object* value = property_dictionary()->ValueAt(entry);
10143 ASSERT(value->IsJSGlobalPropertyCell());
10144 return value;
10145 }
10146}
10147
10148
lrn@chromium.org303ada72010-10-27 09:33:13 +000010149MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010150 SymbolKey key(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010151 return LookupKey(&key, s);
10152}
10153
10154
ager@chromium.org6141cbe2009-11-20 12:14:52 +000010155// This class is used for looking up two character strings in the symbol table.
10156// If we don't have a hit we don't want to waste much time so we unroll the
10157// string hash calculation loop here for speed. Doesn't work if the two
10158// characters form a decimal integer, since such strings have a different hash
10159// algorithm.
10160class TwoCharHashTableKey : public HashTableKey {
10161 public:
10162 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
10163 : c1_(c1), c2_(c2) {
10164 // Char 1.
10165 uint32_t hash = c1 + (c1 << 10);
10166 hash ^= hash >> 6;
10167 // Char 2.
10168 hash += c2;
10169 hash += hash << 10;
10170 hash ^= hash >> 6;
10171 // GetHash.
10172 hash += hash << 3;
10173 hash ^= hash >> 11;
10174 hash += hash << 15;
10175 if (hash == 0) hash = 27;
10176#ifdef DEBUG
10177 StringHasher hasher(2);
10178 hasher.AddCharacter(c1);
10179 hasher.AddCharacter(c2);
10180 // If this assert fails then we failed to reproduce the two-character
10181 // version of the string hashing algorithm above. One reason could be
10182 // that we were passed two digits as characters, since the hash
10183 // algorithm is different in that case.
10184 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
10185#endif
10186 hash_ = hash;
10187 }
10188
10189 bool IsMatch(Object* o) {
10190 if (!o->IsString()) return false;
10191 String* other = String::cast(o);
10192 if (other->length() != 2) return false;
10193 if (other->Get(0) != c1_) return false;
10194 return other->Get(1) == c2_;
10195 }
10196
10197 uint32_t Hash() { return hash_; }
10198 uint32_t HashForObject(Object* key) {
10199 if (!key->IsString()) return 0;
10200 return String::cast(key)->Hash();
10201 }
10202
10203 Object* AsObject() {
10204 // The TwoCharHashTableKey is only used for looking in the symbol
10205 // table, not for adding to it.
10206 UNREACHABLE();
10207 return NULL;
10208 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010209
ager@chromium.org6141cbe2009-11-20 12:14:52 +000010210 private:
10211 uint32_t c1_;
10212 uint32_t c2_;
10213 uint32_t hash_;
10214};
10215
10216
ager@chromium.org7c537e22008-10-16 08:43:32 +000010217bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
10218 SymbolKey key(string);
10219 int entry = FindEntry(&key);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010220 if (entry == kNotFound) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010221 return false;
10222 } else {
10223 String* result = String::cast(KeyAt(entry));
ager@chromium.org870a0b62008-11-04 11:43:05 +000010224 ASSERT(StringShape(result).IsSymbol());
ager@chromium.org7c537e22008-10-16 08:43:32 +000010225 *symbol = result;
10226 return true;
10227 }
10228}
10229
10230
ager@chromium.org6141cbe2009-11-20 12:14:52 +000010231bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
10232 uint32_t c2,
10233 String** symbol) {
10234 TwoCharHashTableKey key(c1, c2);
10235 int entry = FindEntry(&key);
10236 if (entry == kNotFound) {
10237 return false;
10238 } else {
10239 String* result = String::cast(KeyAt(entry));
10240 ASSERT(StringShape(result).IsSymbol());
10241 *symbol = result;
10242 return true;
10243 }
10244}
10245
10246
lrn@chromium.org303ada72010-10-27 09:33:13 +000010247MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010248 Utf8SymbolKey key(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249 return LookupKey(&key, s);
10250}
10251
10252
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010253MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
10254 Object** s) {
10255 AsciiSymbolKey key(str);
10256 return LookupKey(&key, s);
10257}
10258
10259
danno@chromium.org40cb8782011-05-25 07:58:50 +000010260MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
10261 int from,
10262 int length,
10263 Object** s) {
10264 SubStringAsciiSymbolKey key(str, from, length);
10265 return LookupKey(&key, s);
10266}
10267
10268
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010269MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
10270 Object** s) {
10271 TwoByteSymbolKey key(str);
10272 return LookupKey(&key, s);
10273}
10274
lrn@chromium.org303ada72010-10-27 09:33:13 +000010275MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010276 int entry = FindEntry(key);
10277
10278 // Symbol already in table.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010279 if (entry != kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010280 *s = KeyAt(entry);
10281 return this;
10282 }
10283
10284 // Adding new symbol. Grow table if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010285 Object* obj;
10286 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10287 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10288 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010289
10290 // Create symbol object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010291 Object* symbol;
10292 { MaybeObject* maybe_symbol = key->AsObject();
10293 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
10294 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010295
10296 // If the symbol table grew as part of EnsureCapacity, obj is not
10297 // the current symbol table and therefore we cannot use
10298 // SymbolTable::cast here.
10299 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
10300
10301 // Add the new symbol and return it along with the symbol table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010302 entry = table->FindInsertionEntry(key->Hash());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010303 table->set(EntryToIndex(entry), symbol);
10304 table->ElementAdded();
10305 *s = symbol;
10306 return table;
10307}
10308
10309
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010310Object* CompilationCacheTable::Lookup(String* src) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010311 StringKey key(src);
10312 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010313 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010314 return get(EntryToIndex(entry) + 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010315}
10316
10317
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010318Object* CompilationCacheTable::LookupEval(String* src,
10319 Context* context,
10320 StrictModeFlag strict_mode) {
10321 StringSharedKey key(src, context->closure()->shared(), strict_mode);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010322 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010323 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.org381abbb2009-02-25 13:23:22 +000010324 return get(EntryToIndex(entry) + 1);
10325}
10326
10327
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010328Object* CompilationCacheTable::LookupRegExp(String* src,
10329 JSRegExp::Flags flags) {
10330 RegExpKey key(src, flags);
10331 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010332 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010333 return get(EntryToIndex(entry) + 1);
10334}
10335
10336
lrn@chromium.org303ada72010-10-27 09:33:13 +000010337MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010338 StringKey key(src);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010339 Object* obj;
10340 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10341 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10342 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010343
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010344 CompilationCacheTable* cache =
10345 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010346 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010347 cache->set(EntryToIndex(entry), src);
10348 cache->set(EntryToIndex(entry) + 1, value);
10349 cache->ElementAdded();
10350 return cache;
10351}
10352
10353
lrn@chromium.org303ada72010-10-27 09:33:13 +000010354MaybeObject* CompilationCacheTable::PutEval(String* src,
10355 Context* context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010356 SharedFunctionInfo* value) {
10357 StringSharedKey key(src,
10358 context->closure()->shared(),
10359 value->strict_mode() ? kStrictMode : kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010360 Object* obj;
10361 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10362 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10363 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010364
10365 CompilationCacheTable* cache =
10366 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010367 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org381abbb2009-02-25 13:23:22 +000010368
lrn@chromium.org303ada72010-10-27 09:33:13 +000010369 Object* k;
10370 { MaybeObject* maybe_k = key.AsObject();
10371 if (!maybe_k->ToObject(&k)) return maybe_k;
10372 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010373
10374 cache->set(EntryToIndex(entry), k);
10375 cache->set(EntryToIndex(entry) + 1, value);
10376 cache->ElementAdded();
10377 return cache;
10378}
10379
10380
lrn@chromium.org303ada72010-10-27 09:33:13 +000010381MaybeObject* CompilationCacheTable::PutRegExp(String* src,
10382 JSRegExp::Flags flags,
10383 FixedArray* value) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010384 RegExpKey key(src, flags);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010385 Object* obj;
10386 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10387 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10388 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010389
10390 CompilationCacheTable* cache =
10391 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010392 int entry = cache->FindInsertionEntry(key.Hash());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000010393 // We store the value in the key slot, and compare the search key
10394 // to the stored value with a custon IsMatch function during lookups.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010395 cache->set(EntryToIndex(entry), value);
10396 cache->set(EntryToIndex(entry) + 1, value);
10397 cache->ElementAdded();
10398 return cache;
10399}
10400
10401
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010402void CompilationCacheTable::Remove(Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010403 Object* null_value = GetHeap()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010404 for (int entry = 0, size = Capacity(); entry < size; entry++) {
10405 int entry_index = EntryToIndex(entry);
10406 int value_index = entry_index + 1;
10407 if (get(value_index) == value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010408 fast_set(this, entry_index, null_value);
10409 fast_set(this, value_index, null_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010410 ElementRemoved();
10411 }
10412 }
10413 return;
10414}
10415
10416
ager@chromium.org236ad962008-09-25 09:45:57 +000010417// SymbolsKey used for HashTable where key is array of symbols.
10418class SymbolsKey : public HashTableKey {
10419 public:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010420 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
ager@chromium.org236ad962008-09-25 09:45:57 +000010421
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010422 bool IsMatch(Object* symbols) {
10423 FixedArray* o = FixedArray::cast(symbols);
ager@chromium.org236ad962008-09-25 09:45:57 +000010424 int len = symbols_->length();
10425 if (o->length() != len) return false;
10426 for (int i = 0; i < len; i++) {
10427 if (o->get(i) != symbols_->get(i)) return false;
10428 }
10429 return true;
10430 }
10431
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010432 uint32_t Hash() { return HashForObject(symbols_); }
ager@chromium.org236ad962008-09-25 09:45:57 +000010433
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010434 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010435 FixedArray* symbols = FixedArray::cast(obj);
10436 int len = symbols->length();
10437 uint32_t hash = 0;
ager@chromium.org236ad962008-09-25 09:45:57 +000010438 for (int i = 0; i < len; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010439 hash ^= String::cast(symbols->get(i))->Hash();
ager@chromium.org236ad962008-09-25 09:45:57 +000010440 }
10441 return hash;
10442 }
10443
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010444 Object* AsObject() { return symbols_; }
ager@chromium.org236ad962008-09-25 09:45:57 +000010445
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010446 private:
ager@chromium.org236ad962008-09-25 09:45:57 +000010447 FixedArray* symbols_;
10448};
10449
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010450
ager@chromium.org236ad962008-09-25 09:45:57 +000010451Object* MapCache::Lookup(FixedArray* array) {
10452 SymbolsKey key(array);
10453 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010454 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010455 return get(EntryToIndex(entry) + 1);
ager@chromium.org236ad962008-09-25 09:45:57 +000010456}
10457
10458
lrn@chromium.org303ada72010-10-27 09:33:13 +000010459MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
ager@chromium.org236ad962008-09-25 09:45:57 +000010460 SymbolsKey key(array);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010461 Object* obj;
10462 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10463 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10464 }
ager@chromium.org236ad962008-09-25 09:45:57 +000010465
10466 MapCache* cache = reinterpret_cast<MapCache*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010467 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org236ad962008-09-25 09:45:57 +000010468 cache->set(EntryToIndex(entry), array);
10469 cache->set(EntryToIndex(entry) + 1, value);
10470 cache->ElementAdded();
10471 return cache;
10472}
10473
10474
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010475template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010476MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
10477 Object* obj;
10478 { MaybeObject* maybe_obj =
10479 HashTable<Shape, Key>::Allocate(at_least_space_for);
10480 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010481 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010482 // Initialize the next enumeration index.
10483 Dictionary<Shape, Key>::cast(obj)->
10484 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010485 return obj;
10486}
10487
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010488
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010489template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010490MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010491 Heap* heap = Dictionary<Shape, Key>::GetHeap();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010492 int length = HashTable<Shape, Key>::NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010493
10494 // Allocate and initialize iteration order array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010495 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010496 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010497 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10498 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010499 FixedArray* iteration_order = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010500 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010501 iteration_order->set(i, Smi::FromInt(i));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010502 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010503
10504 // Allocate array with enumeration order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010505 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010506 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10507 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010508 FixedArray* enumeration_order = FixedArray::cast(obj);
10509
10510 // Fill the enumeration order array with property details.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010511 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010512 int pos = 0;
10513 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010514 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010515 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010516 }
10517 }
10518
10519 // Sort the arrays wrt. enumeration order.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010520 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010521
10522 // Overwrite the enumeration_order with the enumeration indices.
10523 for (int i = 0; i < length; i++) {
10524 int index = Smi::cast(iteration_order->get(i))->value();
10525 int enum_index = PropertyDetails::kInitialIndex + i;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010526 enumeration_order->set(index, Smi::FromInt(enum_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527 }
10528
10529 // Update the dictionary with new indices.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010530 capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010531 pos = 0;
10532 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010533 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
10535 PropertyDetails details = DetailsAt(i);
10536 PropertyDetails new_details =
10537 PropertyDetails(details.attributes(), details.type(), enum_index);
10538 DetailsAtPut(i, new_details);
10539 }
10540 }
10541
10542 // Set the next enumeration index.
10543 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
10544 return this;
10545}
10546
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010547template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010548MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010549 // Check whether there are enough enumeration indices to add n elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010550 if (Shape::kIsEnumerable &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010551 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
10552 // If not, we generate new indices for the properties.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010553 Object* result;
10554 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
10555 if (!maybe_result->ToObject(&result)) return maybe_result;
10556 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010557 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010558 return HashTable<Shape, Key>::EnsureCapacity(n, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010559}
10560
10561
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010562void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010563 // Do nothing if the interval [from, to) is empty.
10564 if (from >= to) return;
10565
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010566 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010567 int removed_entries = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010568 Object* sentinel = heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010569 int capacity = Capacity();
10570 for (int i = 0; i < capacity; i++) {
10571 Object* key = KeyAt(i);
10572 if (key->IsNumber()) {
10573 uint32_t number = static_cast<uint32_t>(key->Number());
10574 if (from <= number && number < to) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010575 SetEntry(i, sentinel, sentinel);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010576 removed_entries++;
10577 }
10578 }
10579 }
10580
10581 // Update the number of elements.
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +000010582 ElementsRemoved(removed_entries);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010583}
10584
10585
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010586template<typename Shape, typename Key>
10587Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
10588 JSObject::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010589 Heap* heap = Dictionary<Shape, Key>::GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010590 PropertyDetails details = DetailsAt(entry);
ager@chromium.orge2902be2009-06-08 12:21:35 +000010591 // Ignore attributes if forcing a deletion.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000010592 if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010593 return heap->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +000010594 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010595 SetEntry(entry, heap->null_value(), heap->null_value());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010596 HashTable<Shape, Key>::ElementRemoved();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010597 return heap->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010598}
10599
10600
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010601template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010602MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010603 int entry = this->FindEntry(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604
10605 // If the entry is present set the value;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010606 if (entry != Dictionary<Shape, Key>::kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607 ValueAtPut(entry, value);
10608 return this;
10609 }
10610
10611 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010612 Object* obj;
10613 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10614 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10615 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010616
lrn@chromium.org303ada72010-10-27 09:33:13 +000010617 Object* k;
10618 { MaybeObject* maybe_k = Shape::AsObject(key);
10619 if (!maybe_k->ToObject(&k)) return maybe_k;
10620 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 PropertyDetails details = PropertyDetails(NONE, NORMAL);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010622 return Dictionary<Shape, Key>::cast(obj)->
10623 AddEntry(key, value, details, Shape::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010624}
10625
10626
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010627template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010628MaybeObject* Dictionary<Shape, Key>::Add(Key key,
10629 Object* value,
10630 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010631 // Valdate key is absent.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010632 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010633 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010634 Object* obj;
10635 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10636 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10637 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010638 return Dictionary<Shape, Key>::cast(obj)->
10639 AddEntry(key, value, details, Shape::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010640}
10641
10642
10643// Add a key, value pair to the dictionary.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010644template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010645MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
10646 Object* value,
10647 PropertyDetails details,
10648 uint32_t hash) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010649 // Compute the key object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010650 Object* k;
10651 { MaybeObject* maybe_k = Shape::AsObject(key);
10652 if (!maybe_k->ToObject(&k)) return maybe_k;
10653 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010654
10655 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010656 // Insert element at empty or deleted entry
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010657 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010658 // Assign an enumeration index to the property and update
10659 // SetNextEnumerationIndex.
10660 int index = NextEnumerationIndex();
10661 details = PropertyDetails(details.attributes(), details.type(), index);
10662 SetNextEnumerationIndex(index + 1);
10663 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010664 SetEntry(entry, k, value, details);
10665 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
10666 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
10667 HashTable<Shape, Key>::ElementAdded();
10668 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010669}
10670
10671
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010672void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010673 // If the dictionary requires slow elements an element has already
10674 // been added at a high index.
10675 if (requires_slow_elements()) return;
10676 // Check if this index is high enough that we should require slow
10677 // elements.
10678 if (key > kRequiresSlowElementsLimit) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010679 set_requires_slow_elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010680 return;
10681 }
10682 // Update max key value.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010683 Object* max_index_object = get(kMaxNumberKeyIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010684 if (!max_index_object->IsSmi() || max_number_key() < key) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010685 FixedArray::set(kMaxNumberKeyIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010686 Smi::FromInt(key << kRequiresSlowElementsTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010687 }
10688}
10689
10690
lrn@chromium.org303ada72010-10-27 09:33:13 +000010691MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
10692 Object* value,
10693 PropertyDetails details) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010694 UpdateMaxNumberKey(key);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010695 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010696 return Add(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010697}
10698
10699
lrn@chromium.org303ada72010-10-27 09:33:13 +000010700MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010701 UpdateMaxNumberKey(key);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010702 return AtPut(key, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010703}
10704
10705
lrn@chromium.org303ada72010-10-27 09:33:13 +000010706MaybeObject* NumberDictionary::Set(uint32_t key,
10707 Object* value,
10708 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010709 int entry = FindEntry(key);
10710 if (entry == kNotFound) return AddNumberEntry(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010711 // Preserve enumeration index.
10712 details = PropertyDetails(details.attributes(),
10713 details.type(),
10714 DetailsAt(entry).index());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010715 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
10716 Object* object_key;
10717 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010718 SetEntry(entry, object_key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010719 return this;
10720}
10721
10722
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010723
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010724template<typename Shape, typename Key>
10725int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
10726 PropertyAttributes filter) {
10727 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010728 int result = 0;
10729 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010730 Object* k = HashTable<Shape, Key>::KeyAt(i);
10731 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010732 PropertyDetails details = DetailsAt(i);
10733 if (details.IsDeleted()) continue;
10734 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010735 if ((attr & filter) == 0) result++;
10736 }
10737 }
10738 return result;
10739}
10740
10741
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010742template<typename Shape, typename Key>
10743int Dictionary<Shape, Key>::NumberOfEnumElements() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010744 return NumberOfElementsFilterAttributes(
10745 static_cast<PropertyAttributes>(DONT_ENUM));
10746}
10747
10748
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010749template<typename Shape, typename Key>
10750void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage,
10751 PropertyAttributes filter) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010752 ASSERT(storage->length() >= NumberOfEnumElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010753 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010754 int index = 0;
10755 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010756 Object* k = HashTable<Shape, Key>::KeyAt(i);
10757 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010758 PropertyDetails details = DetailsAt(i);
10759 if (details.IsDeleted()) continue;
10760 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010761 if ((attr & filter) == 0) storage->set(index++, k);
10762 }
10763 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010764 storage->SortPairs(storage, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010765 ASSERT(storage->length() >= index);
10766}
10767
10768
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010769void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
10770 FixedArray* sort_array) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771 ASSERT(storage->length() >= NumberOfEnumElements());
10772 int capacity = Capacity();
10773 int index = 0;
10774 for (int i = 0; i < capacity; i++) {
10775 Object* k = KeyAt(i);
10776 if (IsKey(k)) {
10777 PropertyDetails details = DetailsAt(i);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010778 if (details.IsDeleted() || details.IsDontEnum()) continue;
10779 storage->set(index, k);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010780 sort_array->set(index, Smi::FromInt(details.index()));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010781 index++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010782 }
10783 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010784 storage->SortPairs(sort_array, sort_array->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010785 ASSERT(storage->length() >= index);
10786}
10787
10788
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010789template<typename Shape, typename Key>
10790void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010791 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
10792 static_cast<PropertyAttributes>(NONE)));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010793 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010794 int index = 0;
10795 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010796 Object* k = HashTable<Shape, Key>::KeyAt(i);
10797 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010798 PropertyDetails details = DetailsAt(i);
10799 if (details.IsDeleted()) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010800 storage->set(index++, k);
10801 }
10802 }
10803 ASSERT(storage->length() >= index);
10804}
10805
10806
10807// Backwards lookup (slow).
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010808template<typename Shape, typename Key>
10809Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
10810 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010811 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010812 Object* k = HashTable<Shape, Key>::KeyAt(i);
10813 if (Dictionary<Shape, Key>::IsKey(k)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010814 Object* e = ValueAt(i);
10815 if (e->IsJSGlobalPropertyCell()) {
10816 e = JSGlobalPropertyCell::cast(e)->value();
10817 }
10818 if (e == value) return k;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010819 }
10820 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010821 Heap* heap = Dictionary<Shape, Key>::GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010822 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010823}
10824
10825
lrn@chromium.org303ada72010-10-27 09:33:13 +000010826MaybeObject* StringDictionary::TransformPropertiesToFastFor(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010827 JSObject* obj, int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010828 // Make sure we preserve dictionary representation if there are too many
10829 // descriptors.
10830 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
10831
10832 // Figure out if it is necessary to generate new enumeration indices.
10833 int max_enumeration_index =
10834 NextEnumerationIndex() +
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010835 (DescriptorArray::kMaxNumberOfDescriptors -
10836 NumberOfElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010837 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010838 Object* result;
10839 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
10840 if (!maybe_result->ToObject(&result)) return maybe_result;
10841 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 }
10843
10844 int instance_descriptor_length = 0;
10845 int number_of_fields = 0;
10846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010847 Heap* heap = GetHeap();
10848
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849 // Compute the length of the instance descriptor.
10850 int capacity = Capacity();
10851 for (int i = 0; i < capacity; i++) {
10852 Object* k = KeyAt(i);
10853 if (IsKey(k)) {
10854 Object* value = ValueAt(i);
10855 PropertyType type = DetailsAt(i).type();
10856 ASSERT(type != FIELD);
10857 instance_descriptor_length++;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000010858 if (type == NORMAL &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010859 (!value->IsJSFunction() || heap->InNewSpace(value))) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000010860 number_of_fields += 1;
10861 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010862 }
10863 }
10864
10865 // Allocate the instance descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010866 Object* descriptors_unchecked;
10867 { MaybeObject* maybe_descriptors_unchecked =
10868 DescriptorArray::Allocate(instance_descriptor_length);
10869 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
10870 return maybe_descriptors_unchecked;
10871 }
10872 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010873 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010874
ager@chromium.org32912102009-01-16 10:38:43 +000010875 int inobject_props = obj->map()->inobject_properties();
10876 int number_of_allocated_fields =
10877 number_of_fields + unused_property_fields - inobject_props;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010878 if (number_of_allocated_fields < 0) {
10879 // There is enough inobject space for all fields (including unused).
10880 number_of_allocated_fields = 0;
10881 unused_property_fields = inobject_props - number_of_fields;
10882 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010883
10884 // Allocate the fixed array for the fields.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010885 Object* fields;
10886 { MaybeObject* maybe_fields =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010887 heap->AllocateFixedArray(number_of_allocated_fields);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010888 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
10889 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890
10891 // Fill in the instance descriptor and the fields.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010892 int next_descriptor = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010893 int current_offset = 0;
10894 for (int i = 0; i < capacity; i++) {
10895 Object* k = KeyAt(i);
10896 if (IsKey(k)) {
10897 Object* value = ValueAt(i);
10898 // Ensure the key is a symbol before writing into the instance descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010899 Object* key;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010900 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010901 if (!maybe_key->ToObject(&key)) return maybe_key;
10902 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010903 PropertyDetails details = DetailsAt(i);
10904 PropertyType type = details.type();
ager@chromium.org32912102009-01-16 10:38:43 +000010905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010906 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010907 ConstantFunctionDescriptor d(String::cast(key),
10908 JSFunction::cast(value),
10909 details.attributes(),
10910 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010911 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010912 } else if (type == NORMAL) {
ager@chromium.org32912102009-01-16 10:38:43 +000010913 if (current_offset < inobject_props) {
10914 obj->InObjectPropertyAtPut(current_offset,
10915 value,
10916 UPDATE_WRITE_BARRIER);
10917 } else {
10918 int offset = current_offset - inobject_props;
10919 FixedArray::cast(fields)->set(offset, value);
10920 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010921 FieldDescriptor d(String::cast(key),
10922 current_offset++,
10923 details.attributes(),
10924 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010925 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010926 } else if (type == CALLBACKS) {
10927 CallbacksDescriptor d(String::cast(key),
10928 value,
10929 details.attributes(),
10930 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010931 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932 } else {
10933 UNREACHABLE();
10934 }
10935 }
10936 }
10937 ASSERT(current_offset == number_of_fields);
10938
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010939 descriptors->Sort();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010940 // Allocate new map.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010941 Object* new_map;
10942 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
10943 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
10944 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010945
10946 // Transform the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947 obj->set_map(Map::cast(new_map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010948 obj->map()->set_instance_descriptors(descriptors);
10949 obj->map()->set_unused_property_fields(unused_property_fields);
10950
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010951 obj->set_properties(FixedArray::cast(fields));
10952 ASSERT(obj->IsJSObject());
10953
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010954 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
ager@chromium.org32912102009-01-16 10:38:43 +000010955 // Check that it really works.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010956 ASSERT(obj->HasFastProperties());
ager@chromium.org32912102009-01-16 10:38:43 +000010957
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010958 return obj;
10959}
10960
10961
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010962#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010963// Check if there is a break point at this code position.
10964bool DebugInfo::HasBreakPoint(int code_position) {
10965 // Get the break point info object for this code position.
10966 Object* break_point_info = GetBreakPointInfo(code_position);
10967
10968 // If there is no break point info object or no break points in the break
10969 // point info object there is no break point at this code position.
10970 if (break_point_info->IsUndefined()) return false;
10971 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
10972}
10973
10974
10975// Get the break point info object for this code position.
10976Object* DebugInfo::GetBreakPointInfo(int code_position) {
10977 // Find the index of the break point info object for this code position.
10978 int index = GetBreakPointInfoIndex(code_position);
10979
10980 // Return the break point info object if any.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010981 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010982 return BreakPointInfo::cast(break_points()->get(index));
10983}
10984
10985
10986// Clear a break point at the specified code position.
10987void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
10988 int code_position,
10989 Handle<Object> break_point_object) {
10990 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
10991 if (break_point_info->IsUndefined()) return;
10992 BreakPointInfo::ClearBreakPoint(
10993 Handle<BreakPointInfo>::cast(break_point_info),
10994 break_point_object);
10995}
10996
10997
10998void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
10999 int code_position,
11000 int source_position,
11001 int statement_position,
11002 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011003 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011004 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11005 if (!break_point_info->IsUndefined()) {
11006 BreakPointInfo::SetBreakPoint(
11007 Handle<BreakPointInfo>::cast(break_point_info),
11008 break_point_object);
11009 return;
11010 }
11011
11012 // Adding a new break point for a code position which did not have any
11013 // break points before. Try to find a free slot.
11014 int index = kNoBreakPointInfo;
11015 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11016 if (debug_info->break_points()->get(i)->IsUndefined()) {
11017 index = i;
11018 break;
11019 }
11020 }
11021 if (index == kNoBreakPointInfo) {
11022 // No free slot - extend break point info array.
11023 Handle<FixedArray> old_break_points =
11024 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011025 Handle<FixedArray> new_break_points =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011026 isolate->factory()->NewFixedArray(
11027 old_break_points->length() +
11028 Debug::kEstimatedNofBreakPointsInFunction);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011029
11030 debug_info->set_break_points(*new_break_points);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011031 for (int i = 0; i < old_break_points->length(); i++) {
11032 new_break_points->set(i, old_break_points->get(i));
11033 }
11034 index = old_break_points->length();
11035 }
11036 ASSERT(index != kNoBreakPointInfo);
11037
11038 // Allocate new BreakPointInfo object and set the break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011039 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
11040 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011041 new_break_point_info->set_code_position(Smi::FromInt(code_position));
11042 new_break_point_info->set_source_position(Smi::FromInt(source_position));
11043 new_break_point_info->
11044 set_statement_position(Smi::FromInt(statement_position));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011045 new_break_point_info->set_break_point_objects(
11046 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011047 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
11048 debug_info->break_points()->set(index, *new_break_point_info);
11049}
11050
11051
11052// Get the break point objects for a code position.
11053Object* DebugInfo::GetBreakPointObjects(int code_position) {
11054 Object* break_point_info = GetBreakPointInfo(code_position);
11055 if (break_point_info->IsUndefined()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011056 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011057 }
11058 return BreakPointInfo::cast(break_point_info)->break_point_objects();
11059}
11060
11061
11062// Get the total number of break points.
11063int DebugInfo::GetBreakPointCount() {
11064 if (break_points()->IsUndefined()) return 0;
11065 int count = 0;
11066 for (int i = 0; i < break_points()->length(); i++) {
11067 if (!break_points()->get(i)->IsUndefined()) {
11068 BreakPointInfo* break_point_info =
11069 BreakPointInfo::cast(break_points()->get(i));
11070 count += break_point_info->GetBreakPointCount();
11071 }
11072 }
11073 return count;
11074}
11075
11076
11077Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
11078 Handle<Object> break_point_object) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011079 Heap* heap = debug_info->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011080 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011081 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11082 if (!debug_info->break_points()->get(i)->IsUndefined()) {
11083 Handle<BreakPointInfo> break_point_info =
11084 Handle<BreakPointInfo>(BreakPointInfo::cast(
11085 debug_info->break_points()->get(i)));
11086 if (BreakPointInfo::HasBreakPointObject(break_point_info,
11087 break_point_object)) {
11088 return *break_point_info;
11089 }
11090 }
11091 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011092 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011093}
11094
11095
11096// Find the index of the break point info object for the specified code
11097// position.
11098int DebugInfo::GetBreakPointInfoIndex(int code_position) {
11099 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
11100 for (int i = 0; i < break_points()->length(); i++) {
11101 if (!break_points()->get(i)->IsUndefined()) {
11102 BreakPointInfo* break_point_info =
11103 BreakPointInfo::cast(break_points()->get(i));
11104 if (break_point_info->code_position()->value() == code_position) {
11105 return i;
11106 }
11107 }
11108 }
11109 return kNoBreakPointInfo;
11110}
11111
11112
11113// Remove the specified break point object.
11114void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
11115 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011116 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011117 // If there are no break points just ignore.
11118 if (break_point_info->break_point_objects()->IsUndefined()) return;
11119 // If there is a single break point clear it if it is the same.
11120 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11121 if (break_point_info->break_point_objects() == *break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011122 break_point_info->set_break_point_objects(
11123 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011124 }
11125 return;
11126 }
11127 // If there are multiple break points shrink the array
11128 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
11129 Handle<FixedArray> old_array =
11130 Handle<FixedArray>(
11131 FixedArray::cast(break_point_info->break_point_objects()));
11132 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011133 isolate->factory()->NewFixedArray(old_array->length() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011134 int found_count = 0;
11135 for (int i = 0; i < old_array->length(); i++) {
11136 if (old_array->get(i) == *break_point_object) {
11137 ASSERT(found_count == 0);
11138 found_count++;
11139 } else {
11140 new_array->set(i - found_count, old_array->get(i));
11141 }
11142 }
11143 // If the break point was found in the list change it.
11144 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
11145}
11146
11147
11148// Add the specified break point object.
11149void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
11150 Handle<Object> break_point_object) {
11151 // If there was no break point objects before just set it.
11152 if (break_point_info->break_point_objects()->IsUndefined()) {
11153 break_point_info->set_break_point_objects(*break_point_object);
11154 return;
11155 }
11156 // If the break point object is the same as before just ignore.
11157 if (break_point_info->break_point_objects() == *break_point_object) return;
11158 // If there was one break point object before replace with array.
11159 if (!break_point_info->break_point_objects()->IsFixedArray()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011160 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011161 array->set(0, break_point_info->break_point_objects());
11162 array->set(1, *break_point_object);
11163 break_point_info->set_break_point_objects(*array);
11164 return;
11165 }
11166 // If there was more than one break point before extend array.
11167 Handle<FixedArray> old_array =
11168 Handle<FixedArray>(
11169 FixedArray::cast(break_point_info->break_point_objects()));
11170 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011171 FACTORY->NewFixedArray(old_array->length() + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011172 for (int i = 0; i < old_array->length(); i++) {
11173 // If the break point was there before just ignore.
11174 if (old_array->get(i) == *break_point_object) return;
11175 new_array->set(i, old_array->get(i));
11176 }
11177 // Add the new break point.
11178 new_array->set(old_array->length(), *break_point_object);
11179 break_point_info->set_break_point_objects(*new_array);
11180}
11181
11182
11183bool BreakPointInfo::HasBreakPointObject(
11184 Handle<BreakPointInfo> break_point_info,
11185 Handle<Object> break_point_object) {
11186 // No break point.
11187 if (break_point_info->break_point_objects()->IsUndefined()) return false;
11188 // Single beak point.
11189 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11190 return break_point_info->break_point_objects() == *break_point_object;
11191 }
11192 // Multiple break points.
11193 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
11194 for (int i = 0; i < array->length(); i++) {
11195 if (array->get(i) == *break_point_object) {
11196 return true;
11197 }
11198 }
11199 return false;
11200}
11201
11202
11203// Get the number of break points.
11204int BreakPointInfo::GetBreakPointCount() {
11205 // No break point.
11206 if (break_point_objects()->IsUndefined()) return 0;
11207 // Single beak point.
11208 if (!break_point_objects()->IsFixedArray()) return 1;
11209 // Multiple break points.
11210 return FixedArray::cast(break_point_objects())->length();
11211}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011212#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011213
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011214
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011215} } // namespace v8::internal