blob: 64d85a0685a98470ad66df6207a6f18f8448eeae [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010033#include "codegen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include "debug.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "deoptimizer.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010036#include "date.h"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000037#include "elements.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000038#include "execution.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010039#include "full-codegen.h"
40#include "hydrogen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000041#include "objects-inl.h"
Iain Merrick75681382010-08-19 15:07:18 +010042#include "objects-visiting.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010043#include "objects-visiting-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000044#include "macro-assembler.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010045#include "mark-compact.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010046#include "safepoint-table.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000047#include "string-stream.h"
Steve Blockd0582a62009-12-15 09:54:21 +000048#include "utils.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010049#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000050
51#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +010052#include "disasm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000053#include "disassembler.h"
54#endif
55
Steve Blocka7e24c12009-10-30 11:49:00 +000056namespace v8 {
57namespace internal {
58
Ben Murdoch3ef787d2012-04-12 10:51:47 +010059void PrintElementsKind(FILE* out, ElementsKind kind) {
60 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
61 PrintF(out, "%s", accessor->name());
62}
63
Steve Blocka7e24c12009-10-30 11:49:00 +000064
John Reck59135872010-11-02 12:39:01 -070065MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
66 Object* value) {
67 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +010068 { MaybeObject* maybe_result =
69 constructor->GetHeap()->AllocateJSObject(constructor);
John Reck59135872010-11-02 12:39:01 -070070 if (!maybe_result->ToObject(&result)) return maybe_result;
71 }
Steve Blocka7e24c12009-10-30 11:49:00 +000072 JSValue::cast(result)->set_value(value);
73 return result;
74}
75
76
John Reck59135872010-11-02 12:39:01 -070077MaybeObject* Object::ToObject(Context* global_context) {
Steve Blocka7e24c12009-10-30 11:49:00 +000078 if (IsNumber()) {
79 return CreateJSValue(global_context->number_function(), this);
80 } else if (IsBoolean()) {
81 return CreateJSValue(global_context->boolean_function(), this);
82 } else if (IsString()) {
83 return CreateJSValue(global_context->string_function(), this);
84 }
85 ASSERT(IsJSObject());
86 return this;
87}
88
89
John Reck59135872010-11-02 12:39:01 -070090MaybeObject* Object::ToObject() {
Ben Murdoch589d6972011-11-30 16:04:58 +000091 if (IsJSReceiver()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000092 return this;
93 } else if (IsNumber()) {
Steve Block44f0eee2011-05-26 01:26:41 +010094 Isolate* isolate = Isolate::Current();
95 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +000096 return CreateJSValue(global_context->number_function(), this);
97 } else if (IsBoolean()) {
Steve Block44f0eee2011-05-26 01:26:41 +010098 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
99 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000100 return CreateJSValue(global_context->boolean_function(), this);
101 } else if (IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100102 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
103 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000104 return CreateJSValue(global_context->string_function(), this);
105 }
106
107 // Throw a type error.
108 return Failure::InternalError();
109}
110
111
112Object* Object::ToBoolean() {
Steve Block44f0eee2011-05-26 01:26:41 +0100113 if (IsTrue()) return this;
114 if (IsFalse()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000115 if (IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100116 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000117 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100118 HeapObject* heap_object = HeapObject::cast(this);
119 if (heap_object->IsUndefined() || heap_object->IsNull()) {
120 return heap_object->GetHeap()->false_value();
Steve Block44f0eee2011-05-26 01:26:41 +0100121 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000122 // Undetectable object is false
Ben Murdoch8b112d22011-06-08 16:22:53 +0100123 if (heap_object->IsUndetectableObject()) {
124 return heap_object->GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000125 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100126 if (heap_object->IsString()) {
127 return heap_object->GetHeap()->ToBoolean(
Steve Block44f0eee2011-05-26 01:26:41 +0100128 String::cast(this)->length() != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100130 if (heap_object->IsHeapNumber()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000131 return HeapNumber::cast(this)->HeapNumberToBoolean();
132 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100133 return heap_object->GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000134}
135
136
137void Object::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000138 Object* holder = NULL;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100139 if (IsJSReceiver()) {
140 holder = this;
Ben Murdoch85b71792012-04-11 18:30:58 +0100141 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +0100142 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100143 if (IsNumber()) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100144 holder = global_context->number_function()->instance_prototype();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100145 } else if (IsString()) {
146 holder = global_context->string_function()->instance_prototype();
147 } else if (IsBoolean()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100148 holder = global_context->boolean_function()->instance_prototype();
149 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000150 }
151 ASSERT(holder != NULL); // Cannot handle null or undefined.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100152 JSReceiver::cast(holder)->Lookup(name, result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000153}
154
155
John Reck59135872010-11-02 12:39:01 -0700156MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
157 String* name,
158 PropertyAttributes* attributes) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100159 LookupResult result(name->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000160 Lookup(name, &result);
John Reck59135872010-11-02 12:39:01 -0700161 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000162 ASSERT(*attributes <= ABSENT);
163 return value;
164}
165
166
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100167MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
168 Object* structure,
169 String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +0100170 Isolate* isolate = name->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000171 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +0000172 // data structure used to store the callbacks. Eventually foreign
Steve Blocka7e24c12009-10-30 11:49:00 +0000173 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +0000174 if (structure->IsForeign()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000175 AccessorDescriptor* callback =
Ben Murdoch257744e2011-11-30 15:57:28 +0000176 reinterpret_cast<AccessorDescriptor*>(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100177 Foreign::cast(structure)->foreign_address());
John Reck59135872010-11-02 12:39:01 -0700178 MaybeObject* value = (callback->getter)(receiver, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +0100179 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000180 return value;
181 }
182
183 // api style callbacks.
184 if (structure->IsAccessorInfo()) {
185 AccessorInfo* data = AccessorInfo::cast(structure);
186 Object* fun_obj = data->getter();
187 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000188 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000189 JSObject* self = JSObject::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000190 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +0100191 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100192 CustomArguments args(isolate, data->data(), self, this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000193 v8::AccessorInfo info(args.end());
194 v8::Handle<v8::Value> result;
195 {
196 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +0100197 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000198 result = call_fun(v8::Utils::ToLocal(key), info);
199 }
Steve Block44f0eee2011-05-26 01:26:41 +0100200 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
201 if (result.IsEmpty()) {
202 return isolate->heap()->undefined_value();
203 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000204 return *v8::Utils::OpenHandle(*result);
205 }
206
207 // __defineGetter__ callback
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100208 if (structure->IsAccessorPair()) {
209 Object* getter = AccessorPair::cast(structure)->getter();
210 if (getter->IsSpecFunction()) {
211 // TODO(rossberg): nicer would be to cast to some JSCallable here...
212 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
Steve Blocka7e24c12009-10-30 11:49:00 +0000213 }
214 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +0100215 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000216 }
217
218 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +0100219 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000220}
221
222
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100223MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
224 String* name_raw) {
225 Isolate* isolate = GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000226 HandleScope scope(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +0000227 Handle<Object> receiver(receiver_raw);
228 Handle<Object> name(name_raw);
Ben Murdoch257744e2011-11-30 15:57:28 +0000229
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100230 Handle<Object> args[] = { receiver, name };
231 Handle<Object> result = CallTrap(
232 "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +0000233 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch257744e2011-11-30 15:57:28 +0000234
235 return *result;
236}
237
238
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100239Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
240 Isolate* isolate = object->IsHeapObject()
241 ? Handle<HeapObject>::cast(object)->GetIsolate()
242 : Isolate::Current();
243 CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
244}
245
246
247MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
248 uint32_t index) {
249 String* name;
250 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
251 if (!maybe->To<String>(&name)) return maybe;
252 return GetPropertyWithHandler(receiver, name);
253}
254
255
256MaybeObject* JSProxy::SetElementWithHandler(uint32_t index,
257 Object* value,
258 StrictModeFlag strict_mode) {
259 String* name;
260 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
261 if (!maybe->To<String>(&name)) return maybe;
262 return SetPropertyWithHandler(name, value, NONE, strict_mode);
263}
264
265
266bool JSProxy::HasElementWithHandler(uint32_t index) {
267 String* name;
268 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
269 if (!maybe->To<String>(&name)) return maybe;
270 return HasPropertyWithHandler(name);
271}
272
273
John Reck59135872010-11-02 12:39:01 -0700274MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100275 JSReceiver* getter) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000276 HandleScope scope;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100277 Handle<JSReceiver> fun(getter);
Steve Blocka7e24c12009-10-30 11:49:00 +0000278 Handle<Object> self(receiver);
279#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +0100280 Debug* debug = fun->GetHeap()->isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000281 // Handle stepping into a getter if step into is active.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100282 // TODO(rossberg): should this apply to getters that are function proxies?
283 if (debug->StepInActive() && fun->IsJSFunction()) {
284 debug->HandleStepIn(
285 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000286 }
287#endif
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100288
Steve Blocka7e24c12009-10-30 11:49:00 +0000289 bool has_pending_exception;
290 Handle<Object> result =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100291 Execution::Call(fun, self, 0, NULL, &has_pending_exception, true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000292 // Check for pending exception and return the result.
293 if (has_pending_exception) return Failure::Exception();
294 return *result;
295}
296
297
298// Only deal with CALLBACKS and INTERCEPTOR
John Reck59135872010-11-02 12:39:01 -0700299MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
Steve Blocka7e24c12009-10-30 11:49:00 +0000300 Object* receiver,
301 LookupResult* result,
302 String* name,
303 PropertyAttributes* attributes) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000304 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000305 switch (result->type()) {
306 case CALLBACKS: {
307 // Only allow API accessors.
308 Object* obj = result->GetCallbackObject();
309 if (obj->IsAccessorInfo()) {
310 AccessorInfo* info = AccessorInfo::cast(obj);
311 if (info->all_can_read()) {
312 *attributes = result->GetAttributes();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100313 return result->holder()->GetPropertyWithCallback(
314 receiver, result->GetCallbackObject(), name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 }
316 }
317 break;
318 }
319 case NORMAL:
320 case FIELD:
321 case CONSTANT_FUNCTION: {
322 // Search ALL_CAN_READ accessors in prototype chain.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100323 LookupResult r(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000324 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000325 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000326 return GetPropertyWithFailedAccessCheck(receiver,
327 &r,
328 name,
329 attributes);
330 }
331 break;
332 }
333 case INTERCEPTOR: {
334 // If the object has an interceptor, try real named properties.
335 // No access check in GetPropertyAttributeWithInterceptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100336 LookupResult r(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000337 result->holder()->LookupRealNamedProperty(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000338 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000339 return GetPropertyWithFailedAccessCheck(receiver,
340 &r,
341 name,
342 attributes);
343 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000344 break;
345 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000346 default:
347 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000348 }
349 }
350
351 // No accessible property found.
352 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100353 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100354 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
355 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000356}
357
358
359PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
360 Object* receiver,
361 LookupResult* result,
362 String* name,
363 bool continue_search) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000364 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 switch (result->type()) {
366 case CALLBACKS: {
367 // Only allow API accessors.
368 Object* obj = result->GetCallbackObject();
369 if (obj->IsAccessorInfo()) {
370 AccessorInfo* info = AccessorInfo::cast(obj);
371 if (info->all_can_read()) {
372 return result->GetAttributes();
373 }
374 }
375 break;
376 }
377
378 case NORMAL:
379 case FIELD:
380 case CONSTANT_FUNCTION: {
381 if (!continue_search) break;
382 // Search ALL_CAN_READ accessors in prototype chain.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100383 LookupResult r(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000384 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000385 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000386 return GetPropertyAttributeWithFailedAccessCheck(receiver,
387 &r,
388 name,
389 continue_search);
390 }
391 break;
392 }
393
394 case INTERCEPTOR: {
395 // If the object has an interceptor, try real named properties.
396 // No access check in GetPropertyAttributeWithInterceptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100397 LookupResult r(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000398 if (continue_search) {
399 result->holder()->LookupRealNamedProperty(name, &r);
400 } else {
401 result->holder()->LocalLookupRealNamedProperty(name, &r);
402 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000403 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000404 return GetPropertyAttributeWithFailedAccessCheck(receiver,
405 &r,
406 name,
407 continue_search);
408 }
409 break;
410 }
411
Andrei Popescu402d9372010-02-26 13:31:12 +0000412 default:
413 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000414 }
415 }
416
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100417 GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000418 return ABSENT;
419}
420
421
Steve Blocka7e24c12009-10-30 11:49:00 +0000422Object* JSObject::GetNormalizedProperty(LookupResult* result) {
423 ASSERT(!HasFastProperties());
424 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
425 if (IsGlobalObject()) {
426 value = JSGlobalPropertyCell::cast(value)->value();
427 }
428 ASSERT(!value->IsJSGlobalPropertyCell());
429 return value;
430}
431
432
433Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
434 ASSERT(!HasFastProperties());
435 if (IsGlobalObject()) {
436 JSGlobalPropertyCell* cell =
437 JSGlobalPropertyCell::cast(
438 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
439 cell->set_value(value);
440 } else {
441 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
442 }
443 return value;
444}
445
446
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100447Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
448 Handle<String> key,
449 Handle<Object> value,
450 PropertyDetails details) {
451 CALL_HEAP_FUNCTION(object->GetIsolate(),
452 object->SetNormalizedProperty(*key, *value, details),
453 Object);
454}
455
456
John Reck59135872010-11-02 12:39:01 -0700457MaybeObject* JSObject::SetNormalizedProperty(String* name,
458 Object* value,
459 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000460 ASSERT(!HasFastProperties());
461 int entry = property_dictionary()->FindEntry(name);
462 if (entry == StringDictionary::kNotFound) {
463 Object* store_value = value;
464 if (IsGlobalObject()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100465 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100466 MaybeObject* maybe_store_value =
467 heap->AllocateJSGlobalPropertyCell(value);
468 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000469 }
John Reck59135872010-11-02 12:39:01 -0700470 Object* dict;
471 { MaybeObject* maybe_dict =
472 property_dictionary()->Add(name, store_value, details);
473 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
474 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000475 set_properties(StringDictionary::cast(dict));
476 return value;
477 }
478 // Preserve enumeration index.
479 details = PropertyDetails(details.attributes(),
480 details.type(),
481 property_dictionary()->DetailsAt(entry).index());
482 if (IsGlobalObject()) {
483 JSGlobalPropertyCell* cell =
484 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
485 cell->set_value(value);
486 // Please note we have to update the property details.
487 property_dictionary()->DetailsAtPut(entry, details);
488 } else {
489 property_dictionary()->SetEntry(entry, name, value, details);
490 }
491 return value;
492}
493
494
John Reck59135872010-11-02 12:39:01 -0700495MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000496 ASSERT(!HasFastProperties());
497 StringDictionary* dictionary = property_dictionary();
498 int entry = dictionary->FindEntry(name);
499 if (entry != StringDictionary::kNotFound) {
500 // If we have a global object set the cell to the hole.
501 if (IsGlobalObject()) {
502 PropertyDetails details = dictionary->DetailsAt(entry);
503 if (details.IsDontDelete()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100504 if (mode != FORCE_DELETION) return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000505 // When forced to delete global properties, we have to make a
506 // map change to invalidate any ICs that think they can load
507 // from the DontDelete cell without checking if it contains
508 // the hole value.
John Reck59135872010-11-02 12:39:01 -0700509 Object* new_map;
510 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
511 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
512 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000513 set_map(Map::cast(new_map));
514 }
515 JSGlobalPropertyCell* cell =
516 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100517 cell->set_value(cell->GetHeap()->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000518 dictionary->DetailsAtPut(entry, details.AsDeleted());
519 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000520 Object* deleted = dictionary->DeleteProperty(entry, mode);
521 if (deleted == GetHeap()->true_value()) {
522 FixedArray* new_properties = NULL;
523 MaybeObject* maybe_properties = dictionary->Shrink(name);
524 if (!maybe_properties->To(&new_properties)) {
525 return maybe_properties;
526 }
527 set_properties(new_properties);
528 }
529 return deleted;
Steve Blocka7e24c12009-10-30 11:49:00 +0000530 }
531 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100532 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000533}
534
535
536bool JSObject::IsDirty() {
537 Object* cons_obj = map()->constructor();
538 if (!cons_obj->IsJSFunction())
539 return true;
540 JSFunction* fun = JSFunction::cast(cons_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100541 if (!fun->shared()->IsApiFunction())
Steve Blocka7e24c12009-10-30 11:49:00 +0000542 return true;
543 // If the object is fully fast case and has the same map it was
544 // created with then no changes can have been made to it.
545 return map() != fun->initial_map()
546 || !HasFastElements()
547 || !HasFastProperties();
548}
549
550
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100551Handle<Object> Object::GetProperty(Handle<Object> object,
552 Handle<Object> receiver,
553 LookupResult* result,
554 Handle<String> key,
555 PropertyAttributes* attributes) {
556 Isolate* isolate = object->IsHeapObject()
557 ? Handle<HeapObject>::cast(object)->GetIsolate()
558 : Isolate::Current();
559 CALL_HEAP_FUNCTION(
560 isolate,
561 object->GetProperty(*receiver, result, *key, attributes),
562 Object);
563}
564
565
John Reck59135872010-11-02 12:39:01 -0700566MaybeObject* Object::GetProperty(Object* receiver,
567 LookupResult* result,
568 String* name,
569 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000570 // Make sure that the top context does not change when doing
571 // callbacks or interceptor calls.
572 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +0100573 Heap* heap = name->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000574
575 // Traverse the prototype chain from the current object (this) to
Ben Murdoch257744e2011-11-30 15:57:28 +0000576 // the holder and check for access rights. This avoids traversing the
Steve Blocka7e24c12009-10-30 11:49:00 +0000577 // objects more than once in case of interceptors, because the
578 // holder will always be the interceptor holder and the search may
579 // only continue with a current object just after the interceptor
580 // holder in the prototype chain.
Ben Murdoch257744e2011-11-30 15:57:28 +0000581 // Proxy handlers do not use the proxy's prototype, so we can skip this.
582 if (!result->IsHandler()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100583 Object* last = result->IsProperty()
584 ? result->holder()
585 : Object::cast(heap->null_value());
Ben Murdoch257744e2011-11-30 15:57:28 +0000586 ASSERT(this != this->GetPrototype());
587 for (Object* current = this; true; current = current->GetPrototype()) {
588 if (current->IsAccessCheckNeeded()) {
589 // Check if we're allowed to read from the current object. Note
590 // that even though we may not actually end up loading the named
591 // property from the current object, we still check that we have
592 // access to it.
593 JSObject* checked = JSObject::cast(current);
594 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
595 return checked->GetPropertyWithFailedAccessCheck(receiver,
596 result,
597 name,
598 attributes);
599 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000600 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000601 // Stop traversing the chain once we reach the last object in the
602 // chain; either the holder of the result or null in case of an
603 // absent property.
604 if (current == last) break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000605 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000606 }
607
608 if (!result->IsProperty()) {
609 *attributes = ABSENT;
Steve Block44f0eee2011-05-26 01:26:41 +0100610 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000611 }
612 *attributes = result->GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +0000613 Object* value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000614 switch (result->type()) {
615 case NORMAL:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100616 value = result->holder()->GetNormalizedProperty(result);
Steve Blocka7e24c12009-10-30 11:49:00 +0000617 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100618 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000619 case FIELD:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100620 value = result->holder()->FastPropertyAt(result->GetFieldIndex());
Steve Blocka7e24c12009-10-30 11:49:00 +0000621 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100622 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000623 case CONSTANT_FUNCTION:
624 return result->GetConstantFunction();
625 case CALLBACKS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100626 return result->holder()->GetPropertyWithCallback(
627 receiver, result->GetCallbackObject(), name);
628 case HANDLER:
629 return result->proxy()->GetPropertyWithHandler(receiver, name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000630 case INTERCEPTOR: {
631 JSObject* recvr = JSObject::cast(receiver);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100632 return result->holder()->GetPropertyWithInterceptor(
633 recvr, name, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000634 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000635 case MAP_TRANSITION:
Ben Murdoch589d6972011-11-30 16:04:58 +0000636 case ELEMENTS_TRANSITION:
Ben Murdoch257744e2011-11-30 15:57:28 +0000637 case CONSTANT_TRANSITION:
638 case NULL_DESCRIPTOR:
639 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000640 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000641 UNREACHABLE();
642 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000643}
644
645
John Reck59135872010-11-02 12:39:01 -0700646MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000647 Heap* heap = IsSmi()
648 ? Isolate::Current()->heap()
649 : HeapObject::cast(this)->GetHeap();
650 Object* holder = this;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100651
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000652 // Iterate up the prototype chain until an element is found or the null
653 // prototype is encountered.
654 for (holder = this;
655 holder != heap->null_value();
656 holder = holder->GetPrototype()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100657 if (!holder->IsJSObject()) {
658 Isolate* isolate = heap->isolate();
659 Context* global_context = isolate->context()->global_context();
660 if (holder->IsNumber()) {
661 holder = global_context->number_function()->instance_prototype();
662 } else if (holder->IsString()) {
663 holder = global_context->string_function()->instance_prototype();
664 } else if (holder->IsBoolean()) {
665 holder = global_context->boolean_function()->instance_prototype();
666 } else if (holder->IsJSProxy()) {
667 return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
668 } else {
669 // Undefined and null have no indexed properties.
670 ASSERT(holder->IsUndefined() || holder->IsNull());
671 return heap->undefined_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000672 }
673 }
674
675 // Inline the case for JSObjects. Doing so significantly improves the
676 // performance of fetching elements where checking the prototype chain is
677 // necessary.
678 JSObject* js_object = JSObject::cast(holder);
679
680 // Check access rights if needed.
681 if (js_object->IsAccessCheckNeeded()) {
682 Isolate* isolate = heap->isolate();
683 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
684 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
685 return heap->undefined_value();
686 }
687 }
688
689 if (js_object->HasIndexedInterceptor()) {
690 return js_object->GetElementWithInterceptor(receiver, index);
691 }
692
693 if (js_object->elements() != heap->empty_fixed_array()) {
694 MaybeObject* result = js_object->GetElementsAccessor()->Get(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100695 receiver, js_object, index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000696 if (result != heap->the_hole_value()) return result;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100697 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100698 }
699
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000700 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000701}
702
703
704Object* Object::GetPrototype() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100705 if (IsSmi()) {
706 Heap* heap = Isolate::Current()->heap();
707 Context* context = heap->isolate()->context()->global_context();
708 return context->number_function()->instance_prototype();
709 }
710
711 HeapObject* heap_object = HeapObject::cast(this);
712
Ben Murdoch257744e2011-11-30 15:57:28 +0000713 // The object is either a number, a string, a boolean,
714 // a real JS object, or a Harmony proxy.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000715 if (heap_object->IsJSReceiver()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000716 return heap_object->map()->prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100717 }
718 Heap* heap = heap_object->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100719 Context* context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000720
Ben Murdoch8b112d22011-06-08 16:22:53 +0100721 if (heap_object->IsHeapNumber()) {
722 return context->number_function()->instance_prototype();
723 }
724 if (heap_object->IsString()) {
725 return context->string_function()->instance_prototype();
726 }
727 if (heap_object->IsBoolean()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000728 return context->boolean_function()->instance_prototype();
729 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100730 return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000731 }
732}
733
734
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100735MaybeObject* Object::GetHash(CreationFlag flag) {
736 // The object is either a number, a string, an odd-ball,
737 // a real JS object, or a Harmony proxy.
738 if (IsNumber()) {
739 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
740 return Smi::FromInt(hash & Smi::kMaxValue);
741 }
742 if (IsString()) {
743 uint32_t hash = String::cast(this)->Hash();
744 return Smi::FromInt(hash);
745 }
746 if (IsOddball()) {
747 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
748 return Smi::FromInt(hash);
749 }
750 if (IsJSReceiver()) {
751 return JSReceiver::cast(this)->GetIdentityHash(flag);
752 }
753
754 UNREACHABLE();
755 return Smi::FromInt(0);
756}
757
758
759bool Object::SameValue(Object* other) {
760 if (other == this) return true;
761 if (!IsHeapObject() || !other->IsHeapObject()) return false;
762
763 // The object is either a number, a string, an odd-ball,
764 // a real JS object, or a Harmony proxy.
765 if (IsNumber() && other->IsNumber()) {
766 double this_value = Number();
767 double other_value = other->Number();
768 return (this_value == other_value) ||
769 (isnan(this_value) && isnan(other_value));
770 }
771 if (IsString() && other->IsString()) {
772 return String::cast(this)->Equals(String::cast(other));
773 }
774 return false;
775}
776
777
Ben Murdochb0fe1622011-05-05 13:52:32 +0100778void Object::ShortPrint(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 HeapStringAllocator allocator;
780 StringStream accumulator(&allocator);
781 ShortPrint(&accumulator);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100782 accumulator.OutputToFile(out);
Steve Blocka7e24c12009-10-30 11:49:00 +0000783}
784
785
786void Object::ShortPrint(StringStream* accumulator) {
787 if (IsSmi()) {
788 Smi::cast(this)->SmiPrint(accumulator);
789 } else if (IsFailure()) {
790 Failure::cast(this)->FailurePrint(accumulator);
791 } else {
792 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
793 }
794}
795
796
Ben Murdochb0fe1622011-05-05 13:52:32 +0100797void Smi::SmiPrint(FILE* out) {
798 PrintF(out, "%d", value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000799}
800
801
802void Smi::SmiPrint(StringStream* accumulator) {
803 accumulator->Add("%d", value());
804}
805
806
807void Failure::FailurePrint(StringStream* accumulator) {
Steve Block3ce2e202009-11-05 08:53:23 +0000808 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000809}
810
811
Ben Murdochb0fe1622011-05-05 13:52:32 +0100812void Failure::FailurePrint(FILE* out) {
813 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000814}
815
816
Steve Blocka7e24c12009-10-30 11:49:00 +0000817// Should a word be prefixed by 'a' or 'an' in order to read naturally in
818// English? Returns false for non-ASCII or words that don't start with
819// a capital letter. The a/an rule follows pronunciation in English.
820// We don't use the BBC's overcorrect "an historic occasion" though if
821// you speak a dialect you may well say "an 'istoric occasion".
822static bool AnWord(String* str) {
823 if (str->length() == 0) return false; // A nothing.
824 int c0 = str->Get(0);
825 int c1 = str->length() > 1 ? str->Get(1) : 0;
826 if (c0 == 'U') {
827 if (c1 > 'Z') {
828 return true; // An Umpire, but a UTF8String, a U.
829 }
830 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
831 return true; // An Ape, an ABCBook.
832 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
833 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
834 c0 == 'S' || c0 == 'X')) {
835 return true; // An MP3File, an M.
836 }
837 return false;
838}
839
840
John Reck59135872010-11-02 12:39:01 -0700841MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000842#ifdef DEBUG
843 // Do not attempt to flatten in debug mode when allocation is not
844 // allowed. This is to avoid an assertion failure when allocating.
845 // Flattening strings is the only case where we always allow
846 // allocation because no GC is performed if the allocation fails.
Steve Block44f0eee2011-05-26 01:26:41 +0100847 if (!HEAP->IsAllocationAllowed()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000848#endif
849
Steve Block44f0eee2011-05-26 01:26:41 +0100850 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000851 switch (StringShape(this).representation_tag()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000852 case kConsStringTag: {
853 ConsString* cs = ConsString::cast(this);
854 if (cs->second()->length() == 0) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100855 return cs->first();
Steve Blocka7e24c12009-10-30 11:49:00 +0000856 }
857 // There's little point in putting the flat string in new space if the
858 // cons string is in old space. It can never get GCed until there is
859 // an old space GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100860 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +0000861 int len = length();
862 Object* object;
863 String* result;
864 if (IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100865 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700866 if (!maybe_object->ToObject(&object)) return maybe_object;
867 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000868 result = String::cast(object);
869 String* first = cs->first();
870 int first_length = first->length();
871 char* dest = SeqAsciiString::cast(result)->GetChars();
872 WriteToFlat(first, dest, 0, first_length);
873 String* second = cs->second();
874 WriteToFlat(second,
875 dest + first_length,
876 0,
877 len - first_length);
878 } else {
John Reck59135872010-11-02 12:39:01 -0700879 { MaybeObject* maybe_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100880 heap->AllocateRawTwoByteString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700881 if (!maybe_object->ToObject(&object)) return maybe_object;
882 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000883 result = String::cast(object);
884 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
885 String* first = cs->first();
886 int first_length = first->length();
887 WriteToFlat(first, dest, 0, first_length);
888 String* second = cs->second();
889 WriteToFlat(second,
890 dest + first_length,
891 0,
892 len - first_length);
893 }
894 cs->set_first(result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100895 cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
Leon Clarkef7060e22010-06-03 12:02:55 +0100896 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000897 }
898 default:
899 return this;
900 }
901}
902
903
904bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +0100905 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100906 // prohibited by the API.
907 ASSERT(!this->IsExternalString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000908#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000909 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000910 // Assert that the resource and the string are equivalent.
911 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100912 ScopedVector<uc16> smart_chars(this->length());
913 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
914 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000915 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100916 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000917 }
918#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100919 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000920 int size = this->Size(); // Byte size of the original string.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100921 if (size < ExternalString::kShortSize) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000922 return false;
923 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100924 bool is_ascii = this->IsAsciiRepresentation();
Steve Blocka7e24c12009-10-30 11:49:00 +0000925 bool is_symbol = this->IsSymbol();
Steve Blocka7e24c12009-10-30 11:49:00 +0000926
927 // Morph the object to an external string by adjusting the map and
928 // reinitializing the fields.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100929 if (size >= ExternalString::kSize) {
930 this->set_map_no_write_barrier(
931 is_symbol
932 ? (is_ascii ? heap->external_symbol_with_ascii_data_map()
933 : heap->external_symbol_map())
934 : (is_ascii ? heap->external_string_with_ascii_data_map()
935 : heap->external_string_map()));
936 } else {
937 this->set_map_no_write_barrier(
938 is_symbol
939 ? (is_ascii ? heap->short_external_symbol_with_ascii_data_map()
940 : heap->short_external_symbol_map())
941 : (is_ascii ? heap->short_external_string_with_ascii_data_map()
942 : heap->short_external_string_map()));
Ben Murdoch85b71792012-04-11 18:30:58 +0100943 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100944 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
945 self->set_resource(resource);
946 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
Steve Blocka7e24c12009-10-30 11:49:00 +0000947
948 // Fill the remainder of the string with dead wood.
949 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100950 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100951 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
952 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
953 new_size - size);
954 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000955 return true;
956}
957
958
959bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
960#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000961 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000962 // Assert that the resource and the string are equivalent.
963 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100964 ScopedVector<char> smart_chars(this->length());
965 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
966 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000967 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100968 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000969 }
970#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100971 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000972 int size = this->Size(); // Byte size of the original string.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100973 if (size < ExternalString::kShortSize) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000974 return false;
975 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000976 bool is_symbol = this->IsSymbol();
Steve Blocka7e24c12009-10-30 11:49:00 +0000977
978 // Morph the object to an external string by adjusting the map and
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100979 // reinitializing the fields. Use short version if space is limited.
980 if (size >= ExternalString::kSize) {
981 this->set_map_no_write_barrier(
982 is_symbol ? heap->external_ascii_symbol_map()
983 : heap->external_ascii_string_map());
984 } else {
985 this->set_map_no_write_barrier(
986 is_symbol ? heap->short_external_ascii_symbol_map()
987 : heap->short_external_ascii_string_map());
Ben Murdoch85b71792012-04-11 18:30:58 +0100988 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100989 ExternalAsciiString* self = ExternalAsciiString::cast(this);
990 self->set_resource(resource);
991 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
Steve Blocka7e24c12009-10-30 11:49:00 +0000992
993 // Fill the remainder of the string with dead wood.
994 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100995 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100996 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
997 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
998 new_size - size);
999 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001000 return true;
1001}
1002
1003
1004void String::StringShortPrint(StringStream* accumulator) {
1005 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +00001006 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001007 accumulator->Add("<Very long string[%u]>", len);
1008 return;
1009 }
1010
1011 if (!LooksValid()) {
1012 accumulator->Add("<Invalid String>");
1013 return;
1014 }
1015
1016 StringInputBuffer buf(this);
1017
1018 bool truncated = false;
1019 if (len > kMaxShortPrintLength) {
1020 len = kMaxShortPrintLength;
1021 truncated = true;
1022 }
1023 bool ascii = true;
1024 for (int i = 0; i < len; i++) {
1025 int c = buf.GetNext();
1026
1027 if (c < 32 || c >= 127) {
1028 ascii = false;
1029 }
1030 }
1031 buf.Reset(this);
1032 if (ascii) {
1033 accumulator->Add("<String[%u]: ", length());
1034 for (int i = 0; i < len; i++) {
1035 accumulator->Put(buf.GetNext());
1036 }
1037 accumulator->Put('>');
1038 } else {
1039 // Backslash indicates that the string contains control
1040 // characters and that backslashes are therefore escaped.
1041 accumulator->Add("<String[%u]\\: ", length());
1042 for (int i = 0; i < len; i++) {
1043 int c = buf.GetNext();
1044 if (c == '\n') {
1045 accumulator->Add("\\n");
1046 } else if (c == '\r') {
1047 accumulator->Add("\\r");
1048 } else if (c == '\\') {
1049 accumulator->Add("\\\\");
1050 } else if (c < 32 || c > 126) {
1051 accumulator->Add("\\x%02x", c);
1052 } else {
1053 accumulator->Put(c);
1054 }
1055 }
1056 if (truncated) {
1057 accumulator->Put('.');
1058 accumulator->Put('.');
1059 accumulator->Put('.');
1060 }
1061 accumulator->Put('>');
1062 }
1063 return;
1064}
1065
1066
1067void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1068 switch (map()->instance_type()) {
1069 case JS_ARRAY_TYPE: {
1070 double length = JSArray::cast(this)->length()->Number();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001071 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
Steve Blocka7e24c12009-10-30 11:49:00 +00001072 break;
1073 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001074 case JS_WEAK_MAP_TYPE: {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001075 accumulator->Add("<JS WeakMap>");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001076 break;
1077 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001078 case JS_REGEXP_TYPE: {
1079 accumulator->Add("<JS RegExp>");
1080 break;
1081 }
1082 case JS_FUNCTION_TYPE: {
1083 Object* fun_name = JSFunction::cast(this)->shared()->name();
1084 bool printed = false;
1085 if (fun_name->IsString()) {
1086 String* str = String::cast(fun_name);
1087 if (str->length() > 0) {
1088 accumulator->Add("<JS Function ");
1089 accumulator->Put(str);
1090 accumulator->Put('>');
1091 printed = true;
1092 }
1093 }
1094 if (!printed) {
1095 accumulator->Add("<JS Function>");
1096 }
1097 break;
1098 }
1099 // All other JSObjects are rather similar to each other (JSObject,
1100 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1101 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001102 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001103 Heap* heap = GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001104 Object* constructor = map_of_this->constructor();
Steve Blocka7e24c12009-10-30 11:49:00 +00001105 bool printed = false;
1106 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001107 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001108 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1109 } else {
1110 bool global_object = IsJSGlobalProxy();
1111 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001112 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001113 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1114 } else {
1115 Object* constructor_name =
1116 JSFunction::cast(constructor)->shared()->name();
1117 if (constructor_name->IsString()) {
1118 String* str = String::cast(constructor_name);
1119 if (str->length() > 0) {
1120 bool vowel = AnWord(str);
1121 accumulator->Add("<%sa%s ",
1122 global_object ? "Global Object: " : "",
1123 vowel ? "n" : "");
1124 accumulator->Put(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00001125 printed = true;
1126 }
1127 }
1128 }
1129 }
1130 if (!printed) {
1131 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1132 }
1133 }
1134 if (IsJSValue()) {
1135 accumulator->Add(" value = ");
1136 JSValue::cast(this)->value()->ShortPrint(accumulator);
1137 }
1138 accumulator->Put('>');
1139 break;
1140 }
1141 }
1142}
1143
1144
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001145void JSObject::PrintElementsTransition(
1146 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1147 ElementsKind to_kind, FixedArrayBase* to_elements) {
1148 if (from_kind != to_kind) {
1149 PrintF(file, "elements transition [");
1150 PrintElementsKind(file, from_kind);
1151 PrintF(file, " -> ");
1152 PrintElementsKind(file, to_kind);
1153 PrintF(file, "] in ");
1154 JavaScriptFrame::PrintTop(file, false, true);
1155 PrintF(file, " for ");
1156 ShortPrint(file);
1157 PrintF(file, " from ");
1158 from_elements->ShortPrint(file);
1159 PrintF(file, " to ");
1160 to_elements->ShortPrint(file);
1161 PrintF(file, "\n");
1162 }
1163}
1164
1165
Steve Blocka7e24c12009-10-30 11:49:00 +00001166void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
Steve Block44f0eee2011-05-26 01:26:41 +01001167 Heap* heap = GetHeap();
1168 if (!heap->Contains(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001169 accumulator->Add("!!!INVALID POINTER!!!");
1170 return;
1171 }
Steve Block44f0eee2011-05-26 01:26:41 +01001172 if (!heap->Contains(map())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001173 accumulator->Add("!!!INVALID MAP!!!");
1174 return;
1175 }
1176
1177 accumulator->Add("%p ", this);
1178
1179 if (IsString()) {
1180 String::cast(this)->StringShortPrint(accumulator);
1181 return;
1182 }
1183 if (IsJSObject()) {
1184 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1185 return;
1186 }
1187 switch (map()->instance_type()) {
1188 case MAP_TYPE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001189 accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
Steve Blocka7e24c12009-10-30 11:49:00 +00001190 break;
1191 case FIXED_ARRAY_TYPE:
1192 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1193 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001194 case FIXED_DOUBLE_ARRAY_TYPE:
1195 accumulator->Add("<FixedDoubleArray[%u]>",
1196 FixedDoubleArray::cast(this)->length());
1197 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001198 case BYTE_ARRAY_TYPE:
1199 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1200 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001201 case FREE_SPACE_TYPE:
1202 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1203 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001204 case EXTERNAL_PIXEL_ARRAY_TYPE:
1205 accumulator->Add("<ExternalPixelArray[%u]>",
1206 ExternalPixelArray::cast(this)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00001207 break;
Steve Block3ce2e202009-11-05 08:53:23 +00001208 case EXTERNAL_BYTE_ARRAY_TYPE:
1209 accumulator->Add("<ExternalByteArray[%u]>",
1210 ExternalByteArray::cast(this)->length());
1211 break;
1212 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1213 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1214 ExternalUnsignedByteArray::cast(this)->length());
1215 break;
1216 case EXTERNAL_SHORT_ARRAY_TYPE:
1217 accumulator->Add("<ExternalShortArray[%u]>",
1218 ExternalShortArray::cast(this)->length());
1219 break;
1220 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1221 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1222 ExternalUnsignedShortArray::cast(this)->length());
1223 break;
1224 case EXTERNAL_INT_ARRAY_TYPE:
1225 accumulator->Add("<ExternalIntArray[%u]>",
1226 ExternalIntArray::cast(this)->length());
1227 break;
1228 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1229 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1230 ExternalUnsignedIntArray::cast(this)->length());
1231 break;
1232 case EXTERNAL_FLOAT_ARRAY_TYPE:
1233 accumulator->Add("<ExternalFloatArray[%u]>",
1234 ExternalFloatArray::cast(this)->length());
1235 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001236 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1237 accumulator->Add("<ExternalDoubleArray[%u]>",
1238 ExternalDoubleArray::cast(this)->length());
1239 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 case SHARED_FUNCTION_INFO_TYPE:
1241 accumulator->Add("<SharedFunctionInfo>");
1242 break;
Steve Block1e0659c2011-05-24 12:43:12 +01001243 case JS_MESSAGE_OBJECT_TYPE:
1244 accumulator->Add("<JSMessageObject>");
1245 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001246#define MAKE_STRUCT_CASE(NAME, Name, name) \
1247 case NAME##_TYPE: \
1248 accumulator->Put('<'); \
1249 accumulator->Add(#Name); \
1250 accumulator->Put('>'); \
1251 break;
1252 STRUCT_LIST(MAKE_STRUCT_CASE)
1253#undef MAKE_STRUCT_CASE
1254 case CODE_TYPE:
1255 accumulator->Add("<Code>");
1256 break;
1257 case ODDBALL_TYPE: {
1258 if (IsUndefined())
1259 accumulator->Add("<undefined>");
1260 else if (IsTheHole())
1261 accumulator->Add("<the hole>");
1262 else if (IsNull())
1263 accumulator->Add("<null>");
1264 else if (IsTrue())
1265 accumulator->Add("<true>");
1266 else if (IsFalse())
1267 accumulator->Add("<false>");
1268 else
1269 accumulator->Add("<Odd Oddball>");
1270 break;
1271 }
1272 case HEAP_NUMBER_TYPE:
1273 accumulator->Add("<Number: ");
1274 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1275 accumulator->Put('>');
1276 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00001277 case JS_PROXY_TYPE:
1278 accumulator->Add("<JSProxy>");
1279 break;
1280 case JS_FUNCTION_PROXY_TYPE:
1281 accumulator->Add("<JSFunctionProxy>");
1282 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001283 case FOREIGN_TYPE:
1284 accumulator->Add("<Foreign>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001285 break;
1286 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1287 accumulator->Add("Cell for ");
1288 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1289 break;
1290 default:
1291 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1292 break;
1293 }
1294}
1295
1296
Steve Blocka7e24c12009-10-30 11:49:00 +00001297void HeapObject::Iterate(ObjectVisitor* v) {
1298 // Handle header
1299 IteratePointer(v, kMapOffset);
1300 // Handle object body
1301 Map* m = map();
1302 IterateBody(m->instance_type(), SizeFromMap(m), v);
1303}
1304
1305
1306void HeapObject::IterateBody(InstanceType type, int object_size,
1307 ObjectVisitor* v) {
1308 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1309 // During GC, the map pointer field is encoded.
1310 if (type < FIRST_NONSTRING_TYPE) {
1311 switch (type & kStringRepresentationMask) {
1312 case kSeqStringTag:
1313 break;
1314 case kConsStringTag:
Iain Merrick75681382010-08-19 15:07:18 +01001315 ConsString::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001316 break;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001317 case kSlicedStringTag:
1318 SlicedString::BodyDescriptor::IterateBody(this, v);
1319 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001320 case kExternalStringTag:
1321 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1322 reinterpret_cast<ExternalAsciiString*>(this)->
1323 ExternalAsciiStringIterateBody(v);
1324 } else {
1325 reinterpret_cast<ExternalTwoByteString*>(this)->
1326 ExternalTwoByteStringIterateBody(v);
1327 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001328 break;
1329 }
1330 return;
1331 }
1332
1333 switch (type) {
1334 case FIXED_ARRAY_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001335 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001336 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001337 case FIXED_DOUBLE_ARRAY_TYPE:
1338 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001339 case JS_OBJECT_TYPE:
1340 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1341 case JS_VALUE_TYPE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001342 case JS_DATE_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001343 case JS_ARRAY_TYPE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001344 case JS_SET_TYPE:
1345 case JS_MAP_TYPE:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001346 case JS_WEAK_MAP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001347 case JS_REGEXP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001348 case JS_GLOBAL_PROXY_TYPE:
1349 case JS_GLOBAL_OBJECT_TYPE:
1350 case JS_BUILTINS_OBJECT_TYPE:
Steve Block1e0659c2011-05-24 12:43:12 +01001351 case JS_MESSAGE_OBJECT_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001352 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001353 break;
Steve Block791712a2010-08-27 10:21:07 +01001354 case JS_FUNCTION_TYPE:
1355 reinterpret_cast<JSFunction*>(this)
1356 ->JSFunctionIterateBody(object_size, v);
1357 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001358 case ODDBALL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001359 Oddball::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001360 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001361 case JS_PROXY_TYPE:
1362 JSProxy::BodyDescriptor::IterateBody(this, v);
1363 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00001364 case JS_FUNCTION_PROXY_TYPE:
1365 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1366 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001367 case FOREIGN_TYPE:
1368 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001369 break;
1370 case MAP_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001371 Map::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001372 break;
1373 case CODE_TYPE:
1374 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1375 break;
1376 case JS_GLOBAL_PROPERTY_CELL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001377 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001378 break;
1379 case HEAP_NUMBER_TYPE:
1380 case FILLER_TYPE:
1381 case BYTE_ARRAY_TYPE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001382 case FREE_SPACE_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01001383 case EXTERNAL_PIXEL_ARRAY_TYPE:
Steve Block3ce2e202009-11-05 08:53:23 +00001384 case EXTERNAL_BYTE_ARRAY_TYPE:
1385 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1386 case EXTERNAL_SHORT_ARRAY_TYPE:
1387 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1388 case EXTERNAL_INT_ARRAY_TYPE:
1389 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1390 case EXTERNAL_FLOAT_ARRAY_TYPE:
Ben Murdoch257744e2011-11-30 15:57:28 +00001391 case EXTERNAL_DOUBLE_ARRAY_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001392 break;
Iain Merrick75681382010-08-19 15:07:18 +01001393 case SHARED_FUNCTION_INFO_TYPE:
1394 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001395 break;
Iain Merrick75681382010-08-19 15:07:18 +01001396
Steve Blocka7e24c12009-10-30 11:49:00 +00001397#define MAKE_STRUCT_CASE(NAME, Name, name) \
1398 case NAME##_TYPE:
1399 STRUCT_LIST(MAKE_STRUCT_CASE)
1400#undef MAKE_STRUCT_CASE
Iain Merrick75681382010-08-19 15:07:18 +01001401 StructBodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001402 break;
1403 default:
1404 PrintF("Unknown type: %d\n", type);
1405 UNREACHABLE();
1406 }
1407}
1408
1409
Steve Blocka7e24c12009-10-30 11:49:00 +00001410Object* HeapNumber::HeapNumberToBoolean() {
1411 // NaN, +0, and -0 should return the false object
Iain Merrick75681382010-08-19 15:07:18 +01001412#if __BYTE_ORDER == __LITTLE_ENDIAN
1413 union IeeeDoubleLittleEndianArchType u;
1414#elif __BYTE_ORDER == __BIG_ENDIAN
1415 union IeeeDoubleBigEndianArchType u;
1416#endif
1417 u.d = value();
1418 if (u.bits.exp == 2047) {
1419 // Detect NaN for IEEE double precision floating point.
1420 if ((u.bits.man_low | u.bits.man_high) != 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001421 return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001422 }
Iain Merrick75681382010-08-19 15:07:18 +01001423 if (u.bits.exp == 0) {
1424 // Detect +0, and -0 for IEEE double precision floating point.
1425 if ((u.bits.man_low | u.bits.man_high) == 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001426 return GetHeap()->false_value();
Iain Merrick75681382010-08-19 15:07:18 +01001427 }
Steve Block44f0eee2011-05-26 01:26:41 +01001428 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001429}
1430
1431
Ben Murdochb0fe1622011-05-05 13:52:32 +01001432void HeapNumber::HeapNumberPrint(FILE* out) {
1433 PrintF(out, "%.16g", Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00001434}
1435
1436
1437void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1438 // The Windows version of vsnprintf can allocate when printing a %g string
1439 // into a buffer that may not be big enough. We don't want random memory
1440 // allocation when producing post-crash stack traces, so we print into a
1441 // buffer that is plenty big enough for any floating point number, then
1442 // print that using vsnprintf (which may truncate but never allocate if
1443 // there is no more space in the buffer).
1444 EmbeddedVector<char, 100> buffer;
1445 OS::SNPrintF(buffer, "%.16g", Number());
1446 accumulator->Add("%s", buffer.start());
1447}
1448
1449
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001450String* JSReceiver::class_name() {
1451 if (IsJSFunction() && IsJSFunctionProxy()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001452 return GetHeap()->function_class_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001453 }
1454 if (map()->constructor()->IsJSFunction()) {
1455 JSFunction* constructor = JSFunction::cast(map()->constructor());
1456 return String::cast(constructor->shared()->instance_class_name());
1457 }
1458 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001459 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001460}
1461
1462
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001463String* JSReceiver::constructor_name() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001464 if (map()->constructor()->IsJSFunction()) {
1465 JSFunction* constructor = JSFunction::cast(map()->constructor());
1466 String* name = String::cast(constructor->shared()->name());
Ben Murdochf87a2032010-10-22 12:50:53 +01001467 if (name->length() > 0) return name;
1468 String* inferred_name = constructor->shared()->inferred_name();
1469 if (inferred_name->length() > 0) return inferred_name;
1470 Object* proto = GetPrototype();
1471 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001472 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001473 // TODO(rossberg): what about proxies?
Steve Blocka7e24c12009-10-30 11:49:00 +00001474 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001475 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001476}
1477
1478
John Reck59135872010-11-02 12:39:01 -07001479MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1480 String* name,
1481 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001482 int index = new_map->PropertyIndexFor(name);
1483 if (map()->unused_property_fields() == 0) {
1484 ASSERT(map()->unused_property_fields() == 0);
1485 int new_unused = new_map->unused_property_fields();
John Reck59135872010-11-02 12:39:01 -07001486 Object* values;
1487 { MaybeObject* maybe_values =
1488 properties()->CopySize(properties()->length() + new_unused + 1);
1489 if (!maybe_values->ToObject(&values)) return maybe_values;
1490 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001491 set_properties(FixedArray::cast(values));
1492 }
1493 set_map(new_map);
1494 return FastPropertyAtPut(index, value);
1495}
1496
1497
Ben Murdoch8b112d22011-06-08 16:22:53 +01001498static bool IsIdentifier(UnicodeCache* cache,
1499 unibrow::CharacterStream* buffer) {
1500 // Checks whether the buffer contains an identifier (no escape).
1501 if (!buffer->has_more()) return false;
1502 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1503 return false;
1504 }
1505 while (buffer->has_more()) {
1506 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1507 return false;
1508 }
1509 }
1510 return true;
1511}
1512
1513
John Reck59135872010-11-02 12:39:01 -07001514MaybeObject* JSObject::AddFastProperty(String* name,
1515 Object* value,
1516 PropertyAttributes attributes) {
Steve Block1e0659c2011-05-24 12:43:12 +01001517 ASSERT(!IsJSGlobalProxy());
1518
Steve Blocka7e24c12009-10-30 11:49:00 +00001519 // Normalize the object if the name is an actual string (not the
1520 // hidden symbols) and is not a real identifier.
Steve Block44f0eee2011-05-26 01:26:41 +01001521 Isolate* isolate = GetHeap()->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00001522 StringInputBuffer buffer(name);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001523 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
Steve Block44f0eee2011-05-26 01:26:41 +01001524 && name != isolate->heap()->hidden_symbol()) {
John Reck59135872010-11-02 12:39:01 -07001525 Object* obj;
1526 { MaybeObject* maybe_obj =
1527 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1528 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1529 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001530 return AddSlowProperty(name, value, attributes);
1531 }
1532
1533 DescriptorArray* old_descriptors = map()->instance_descriptors();
1534 // Compute the new index for new field.
1535 int index = map()->NextFreePropertyIndex();
1536
1537 // Allocate new instance descriptors with (name, index) added
1538 FieldDescriptor new_field(name, index, attributes);
John Reck59135872010-11-02 12:39:01 -07001539 Object* new_descriptors;
1540 { MaybeObject* maybe_new_descriptors =
1541 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1542 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1543 return maybe_new_descriptors;
1544 }
1545 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001546
Steve Block44f0eee2011-05-26 01:26:41 +01001547 // Only allow map transition if the object isn't the global object and there
1548 // is not a transition for the name, or there's a transition for the name but
1549 // it's unrelated to properties.
1550 int descriptor_index = old_descriptors->Search(name);
1551
Ben Murdoch589d6972011-11-30 16:04:58 +00001552 // Element transitions are stored in the descriptor for property "", which is
1553 // not a identifier and should have forced a switch to slow properties above.
Steve Block44f0eee2011-05-26 01:26:41 +01001554 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
Ben Murdoch589d6972011-11-30 16:04:58 +00001555 old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
Steve Block44f0eee2011-05-26 01:26:41 +01001556 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
Ben Murdoch589d6972011-11-30 16:04:58 +00001557 old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
Steve Blocka7e24c12009-10-30 11:49:00 +00001558 bool allow_map_transition =
Steve Block44f0eee2011-05-26 01:26:41 +01001559 can_insert_transition &&
1560 (isolate->context()->global_context()->object_function()->map() != map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001561
1562 ASSERT(index < map()->inobject_properties() ||
1563 (index - map()->inobject_properties()) < properties()->length() ||
1564 map()->unused_property_fields() == 0);
1565 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001566 Object* r;
1567 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1568 if (!maybe_r->ToObject(&r)) return maybe_r;
1569 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001570 Map* new_map = Map::cast(r);
1571 if (allow_map_transition) {
1572 // Allocate new instance descriptors for the old map with map transition.
1573 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
John Reck59135872010-11-02 12:39:01 -07001574 Object* r;
1575 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1576 if (!maybe_r->ToObject(&r)) return maybe_r;
1577 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001578 old_descriptors = DescriptorArray::cast(r);
1579 }
1580
1581 if (map()->unused_property_fields() == 0) {
Steve Block8defd9f2010-07-08 12:39:36 +01001582 if (properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001583 Object* obj;
1584 { MaybeObject* maybe_obj =
1585 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1586 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1587 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001588 return AddSlowProperty(name, value, attributes);
1589 }
1590 // Make room for the new value
John Reck59135872010-11-02 12:39:01 -07001591 Object* values;
1592 { MaybeObject* maybe_values =
1593 properties()->CopySize(properties()->length() + kFieldsAdded);
1594 if (!maybe_values->ToObject(&values)) return maybe_values;
1595 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001596 set_properties(FixedArray::cast(values));
1597 new_map->set_unused_property_fields(kFieldsAdded - 1);
1598 } else {
1599 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1600 }
1601 // We have now allocated all the necessary objects.
1602 // All the changes can be applied at once, so they are atomic.
1603 map()->set_instance_descriptors(old_descriptors);
1604 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1605 set_map(new_map);
1606 return FastPropertyAtPut(index, value);
1607}
1608
1609
John Reck59135872010-11-02 12:39:01 -07001610MaybeObject* JSObject::AddConstantFunctionProperty(
1611 String* name,
1612 JSFunction* function,
1613 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001614 // Allocate new instance descriptors with (name, function) added
1615 ConstantFunctionDescriptor d(name, function, attributes);
John Reck59135872010-11-02 12:39:01 -07001616 Object* new_descriptors;
1617 { MaybeObject* maybe_new_descriptors =
1618 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1619 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1620 return maybe_new_descriptors;
1621 }
1622 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001623
1624 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001625 Object* new_map;
1626 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1627 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1628 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001629
1630 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1631 Map::cast(new_map)->set_instance_descriptors(descriptors);
1632 Map* old_map = map();
1633 set_map(Map::cast(new_map));
1634
1635 // If the old map is the global object map (from new Object()),
1636 // then transitions are not added to it, so we are done.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001637 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01001638 if (old_map == heap->isolate()->context()->global_context()->
1639 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001640 return function;
1641 }
1642
1643 // Do not add CONSTANT_TRANSITIONS to global objects
1644 if (IsGlobalObject()) {
1645 return function;
1646 }
1647
1648 // Add a CONSTANT_TRANSITION descriptor to the old map,
1649 // so future assignments to this property on other objects
1650 // of the same type will create a normal field, not a constant function.
1651 // Don't do this for special properties, with non-trival attributes.
1652 if (attributes != NONE) {
1653 return function;
1654 }
Iain Merrick75681382010-08-19 15:07:18 +01001655 ConstTransitionDescriptor mark(name, Map::cast(new_map));
John Reck59135872010-11-02 12:39:01 -07001656 { MaybeObject* maybe_new_descriptors =
1657 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1658 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1659 // We have accomplished the main goal, so return success.
1660 return function;
1661 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001662 }
1663 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1664
1665 return function;
1666}
1667
1668
1669// Add property in slow mode
John Reck59135872010-11-02 12:39:01 -07001670MaybeObject* JSObject::AddSlowProperty(String* name,
1671 Object* value,
1672 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001673 ASSERT(!HasFastProperties());
1674 StringDictionary* dict = property_dictionary();
1675 Object* store_value = value;
1676 if (IsGlobalObject()) {
1677 // In case name is an orphaned property reuse the cell.
1678 int entry = dict->FindEntry(name);
1679 if (entry != StringDictionary::kNotFound) {
1680 store_value = dict->ValueAt(entry);
1681 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1682 // Assign an enumeration index to the property and update
1683 // SetNextEnumerationIndex.
1684 int index = dict->NextEnumerationIndex();
1685 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1686 dict->SetNextEnumerationIndex(index + 1);
1687 dict->SetEntry(entry, name, store_value, details);
1688 return value;
1689 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001690 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07001691 { MaybeObject* maybe_store_value =
Steve Block44f0eee2011-05-26 01:26:41 +01001692 heap->AllocateJSGlobalPropertyCell(value);
John Reck59135872010-11-02 12:39:01 -07001693 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1694 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001695 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1696 }
1697 PropertyDetails details = PropertyDetails(attributes, NORMAL);
John Reck59135872010-11-02 12:39:01 -07001698 Object* result;
1699 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1700 if (!maybe_result->ToObject(&result)) return maybe_result;
1701 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001702 if (dict != result) set_properties(StringDictionary::cast(result));
1703 return value;
1704}
1705
1706
John Reck59135872010-11-02 12:39:01 -07001707MaybeObject* JSObject::AddProperty(String* name,
1708 Object* value,
Steve Block44f0eee2011-05-26 01:26:41 +01001709 PropertyAttributes attributes,
1710 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001711 ASSERT(!IsJSGlobalProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001712 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001713 Heap* heap = GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001714 if (!map_of_this->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001715 if (strict_mode == kNonStrictMode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001716 return value;
Steve Block44f0eee2011-05-26 01:26:41 +01001717 } else {
1718 Handle<Object> args[1] = {Handle<String>(name)};
1719 return heap->isolate()->Throw(
1720 *FACTORY->NewTypeError("object_not_extensible",
1721 HandleVector(args, 1)));
1722 }
Steve Block8defd9f2010-07-08 12:39:36 +01001723 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001724 if (HasFastProperties()) {
1725 // Ensure the descriptor array does not get too big.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001726 if (map_of_this->instance_descriptors()->number_of_descriptors() <
Steve Blocka7e24c12009-10-30 11:49:00 +00001727 DescriptorArray::kMaxNumberOfDescriptors) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001728 if (value->IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001729 return AddConstantFunctionProperty(name,
1730 JSFunction::cast(value),
1731 attributes);
1732 } else {
1733 return AddFastProperty(name, value, attributes);
1734 }
1735 } else {
1736 // Normalize the object to prevent very large instance descriptors.
1737 // This eliminates unwanted N^2 allocation and lookup behavior.
John Reck59135872010-11-02 12:39:01 -07001738 Object* obj;
1739 { MaybeObject* maybe_obj =
1740 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1741 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1742 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001743 }
1744 }
1745 return AddSlowProperty(name, value, attributes);
1746}
1747
1748
John Reck59135872010-11-02 12:39:01 -07001749MaybeObject* JSObject::SetPropertyPostInterceptor(
1750 String* name,
1751 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001752 PropertyAttributes attributes,
1753 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001754 // Check local property, ignore interceptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001755 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001756 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001757 if (result.IsFound()) {
1758 // An existing property, a map transition or a null descriptor was
1759 // found. Use set property to handle all these cases.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001760 return SetProperty(&result, name, value, attributes, strict_mode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001761 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001762 bool found = false;
1763 MaybeObject* result_object;
1764 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
1765 value,
1766 attributes,
1767 &found,
1768 strict_mode);
1769 if (found) return result_object;
Andrei Popescu402d9372010-02-26 13:31:12 +00001770 // Add a new real property.
Steve Block44f0eee2011-05-26 01:26:41 +01001771 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001772}
1773
1774
John Reck59135872010-11-02 12:39:01 -07001775MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1776 Object* value,
1777 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001778 StringDictionary* dictionary = property_dictionary();
1779 int old_index = dictionary->FindEntry(name);
1780 int new_enumeration_index = 0; // 0 means "Use the next available index."
1781 if (old_index != -1) {
1782 // All calls to ReplaceSlowProperty have had all transitions removed.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001783 ASSERT(!dictionary->ContainsTransition(old_index));
Steve Blocka7e24c12009-10-30 11:49:00 +00001784 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1785 }
1786
1787 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1788 return SetNormalizedProperty(name, value, new_details);
1789}
1790
Steve Blockd0582a62009-12-15 09:54:21 +00001791
John Reck59135872010-11-02 12:39:01 -07001792MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
Steve Blocka7e24c12009-10-30 11:49:00 +00001793 String* name,
1794 Object* new_value,
1795 PropertyAttributes attributes) {
1796 Map* old_map = map();
John Reck59135872010-11-02 12:39:01 -07001797 Object* result;
1798 { MaybeObject* maybe_result =
1799 ConvertDescriptorToField(name, new_value, attributes);
1800 if (!maybe_result->ToObject(&result)) return maybe_result;
1801 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001802 // If we get to this point we have succeeded - do not return failure
1803 // after this point. Later stuff is optional.
1804 if (!HasFastProperties()) {
1805 return result;
1806 }
1807 // Do not add transitions to the map of "new Object()".
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001808 if (map() == GetIsolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01001809 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001810 return result;
1811 }
1812
1813 MapTransitionDescriptor transition(name,
1814 map(),
1815 attributes);
John Reck59135872010-11-02 12:39:01 -07001816 Object* new_descriptors;
1817 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1818 CopyInsert(&transition, KEEP_TRANSITIONS);
1819 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1820 return result; // Yes, return _result_.
1821 }
1822 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001823 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1824 return result;
1825}
1826
1827
John Reck59135872010-11-02 12:39:01 -07001828MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1829 Object* new_value,
1830 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001831 if (map()->unused_property_fields() == 0 &&
Steve Block8defd9f2010-07-08 12:39:36 +01001832 properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001833 Object* obj;
1834 { MaybeObject* maybe_obj =
1835 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1836 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1837 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001838 return ReplaceSlowProperty(name, new_value, attributes);
1839 }
1840
1841 int index = map()->NextFreePropertyIndex();
1842 FieldDescriptor new_field(name, index, attributes);
1843 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
John Reck59135872010-11-02 12:39:01 -07001844 Object* descriptors_unchecked;
1845 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1846 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1847 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1848 return maybe_descriptors_unchecked;
1849 }
1850 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001851 DescriptorArray* new_descriptors =
1852 DescriptorArray::cast(descriptors_unchecked);
1853
1854 // Make a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001855 Object* new_map_unchecked;
1856 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1857 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1858 return maybe_new_map_unchecked;
1859 }
1860 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001861 Map* new_map = Map::cast(new_map_unchecked);
1862 new_map->set_instance_descriptors(new_descriptors);
1863
1864 // Make new properties array if necessary.
1865 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1866 int new_unused_property_fields = map()->unused_property_fields() - 1;
1867 if (map()->unused_property_fields() == 0) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001868 new_unused_property_fields = kFieldsAdded - 1;
John Reck59135872010-11-02 12:39:01 -07001869 Object* new_properties_object;
1870 { MaybeObject* maybe_new_properties_object =
1871 properties()->CopySize(properties()->length() + kFieldsAdded);
1872 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1873 return maybe_new_properties_object;
1874 }
1875 }
1876 new_properties = FixedArray::cast(new_properties_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001877 }
1878
1879 // Update pointers to commit changes.
1880 // Object points to the new map.
1881 new_map->set_unused_property_fields(new_unused_property_fields);
1882 set_map(new_map);
1883 if (new_properties) {
1884 set_properties(FixedArray::cast(new_properties));
1885 }
1886 return FastPropertyAtPut(index, new_value);
1887}
1888
1889
1890
John Reck59135872010-11-02 12:39:01 -07001891MaybeObject* JSObject::SetPropertyWithInterceptor(
1892 String* name,
1893 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001894 PropertyAttributes attributes,
1895 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001896 Isolate* isolate = GetIsolate();
1897 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001898 Handle<JSObject> this_handle(this);
1899 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001900 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001901 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1902 if (!interceptor->setter()->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001903 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1904 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001905 v8::AccessorInfo info(args.end());
1906 v8::NamedPropertySetter setter =
1907 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1908 v8::Handle<v8::Value> result;
1909 {
1910 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001911 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001912 Handle<Object> value_unhole(value->IsTheHole() ?
Steve Block44f0eee2011-05-26 01:26:41 +01001913 isolate->heap()->undefined_value() :
1914 value,
1915 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001916 result = setter(v8::Utils::ToLocal(name_handle),
1917 v8::Utils::ToLocal(value_unhole),
1918 info);
1919 }
Steve Block44f0eee2011-05-26 01:26:41 +01001920 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001921 if (!result.IsEmpty()) return *value_handle;
1922 }
John Reck59135872010-11-02 12:39:01 -07001923 MaybeObject* raw_result =
1924 this_handle->SetPropertyPostInterceptor(*name_handle,
1925 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001926 attributes,
1927 strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001928 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001929 return raw_result;
1930}
1931
1932
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001933Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
1934 Handle<String> key,
1935 Handle<Object> value,
1936 PropertyAttributes attributes,
1937 StrictModeFlag strict_mode) {
1938 CALL_HEAP_FUNCTION(object->GetIsolate(),
1939 object->SetProperty(*key, *value, attributes, strict_mode),
1940 Object);
1941}
1942
1943
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001944MaybeObject* JSReceiver::SetProperty(String* name,
1945 Object* value,
1946 PropertyAttributes attributes,
1947 StrictModeFlag strict_mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001948 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00001949 LocalLookup(name, &result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001950 return SetProperty(&result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001951}
1952
1953
John Reck59135872010-11-02 12:39:01 -07001954MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1955 String* name,
1956 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001957 JSObject* holder,
1958 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001959 Isolate* isolate = GetIsolate();
1960 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001961
1962 // We should never get here to initialize a const with the hole
1963 // value since a const declaration would conflict with the setter.
1964 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01001965 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001966
1967 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00001968 // data structure used to store the callbacks. Eventually foreign
Steve Blocka7e24c12009-10-30 11:49:00 +00001969 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00001970 if (structure->IsForeign()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001971 AccessorDescriptor* callback =
Ben Murdoch257744e2011-11-30 15:57:28 +00001972 reinterpret_cast<AccessorDescriptor*>(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001973 Foreign::cast(structure)->foreign_address());
John Reck59135872010-11-02 12:39:01 -07001974 MaybeObject* obj = (callback->setter)(this, value, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +01001975 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001976 if (obj->IsFailure()) return obj;
1977 return *value_handle;
1978 }
1979
1980 if (structure->IsAccessorInfo()) {
1981 // api style callbacks
1982 AccessorInfo* data = AccessorInfo::cast(structure);
1983 Object* call_obj = data->setter();
1984 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1985 if (call_fun == NULL) return value;
1986 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001987 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1988 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Steve Blocka7e24c12009-10-30 11:49:00 +00001989 v8::AccessorInfo info(args.end());
1990 {
1991 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001992 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001993 call_fun(v8::Utils::ToLocal(key),
1994 v8::Utils::ToLocal(value_handle),
1995 info);
1996 }
Steve Block44f0eee2011-05-26 01:26:41 +01001997 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001998 return *value_handle;
1999 }
2000
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002001 if (structure->IsAccessorPair()) {
2002 Object* setter = AccessorPair::cast(structure)->setter();
2003 if (setter->IsSpecFunction()) {
2004 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2005 return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002006 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002007 if (strict_mode == kNonStrictMode) {
2008 return value;
2009 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002010 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002011 Handle<Object> holder_handle(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002012 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01002013 return isolate->Throw(
2014 *isolate->factory()->NewTypeError("no_setter_in_callback",
2015 HandleVector(args, 2)));
Steve Blocka7e24c12009-10-30 11:49:00 +00002016 }
2017 }
2018
2019 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +01002020 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00002021}
2022
2023
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002024MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
2025 Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01002026 Isolate* isolate = GetIsolate();
2027 Handle<Object> value_handle(value, isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002028 Handle<JSReceiver> fun(setter, isolate);
2029 Handle<JSReceiver> self(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002030#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01002031 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00002032 // Handle stepping into a setter if step into is active.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002033 // TODO(rossberg): should this apply to getters that are function proxies?
2034 if (debug->StepInActive() && fun->IsJSFunction()) {
2035 debug->HandleStepIn(
2036 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00002037 }
2038#endif
2039 bool has_pending_exception;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002040 Handle<Object> argv[] = { value_handle };
2041 Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +00002042 // Check for pending exception and return the result.
2043 if (has_pending_exception) return Failure::Exception();
2044 return *value_handle;
2045}
2046
2047
2048void JSObject::LookupCallbackSetterInPrototypes(String* name,
2049 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01002050 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002051 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002052 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002053 pt = pt->GetPrototype()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002054 if (pt->IsJSProxy()) {
2055 return result->HandlerResult(JSProxy::cast(pt));
2056 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002057 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002058 if (result->IsProperty()) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01002059 if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
2060 // Found non-callback or read-only callback, stop looking.
2061 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002062 }
2063 }
2064 result->NotFound();
2065}
2066
2067
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002068MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
2069 uint32_t index,
2070 Object* value,
2071 bool* found,
2072 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002073 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002074 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002075 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002076 pt = pt->GetPrototype()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002077 if (pt->IsJSProxy()) {
2078 String* name;
2079 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
2080 if (!maybe->To<String>(&name)) {
2081 *found = true; // Force abort
2082 return maybe;
2083 }
2084 return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
2085 name, value, NONE, strict_mode, found);
2086 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002087 if (!JSObject::cast(pt)->HasDictionaryElements()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002088 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00002089 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00002090 SeededNumberDictionary* dictionary =
2091 JSObject::cast(pt)->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +00002092 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00002093 if (entry != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002094 PropertyDetails details = dictionary->DetailsAt(entry);
2095 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01002096 *found = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002097 return SetElementWithCallback(dictionary->ValueAt(entry),
2098 index,
2099 value,
2100 JSObject::cast(pt),
2101 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002102 }
2103 }
2104 }
Steve Block1e0659c2011-05-24 12:43:12 +01002105 *found = false;
Steve Block44f0eee2011-05-26 01:26:41 +01002106 return heap->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002107}
2108
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002109MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
2110 String* name,
2111 Object* value,
2112 PropertyAttributes attributes,
2113 bool* found,
2114 StrictModeFlag strict_mode) {
2115 Heap* heap = GetHeap();
2116 // We could not find a local property so let's check whether there is an
2117 // accessor that wants to handle the property.
2118 LookupResult accessor_result(heap->isolate());
2119 LookupCallbackSetterInPrototypes(name, &accessor_result);
2120 if (accessor_result.IsFound()) {
2121 *found = true;
2122 if (accessor_result.type() == CALLBACKS) {
2123 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2124 name,
2125 value,
2126 accessor_result.holder(),
2127 strict_mode);
2128 } else if (accessor_result.type() == HANDLER) {
2129 // There is a proxy in the prototype chain. Invoke its
2130 // getPropertyDescriptor trap.
2131 bool found = false;
2132 // SetPropertyWithHandlerIfDefiningSetter can cause GC,
2133 // make sure to use the handlified references after calling
2134 // the function.
2135 Handle<JSObject> self(this);
2136 Handle<String> hname(name);
2137 Handle<Object> hvalue(value);
2138 MaybeObject* result =
2139 accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
2140 name, value, attributes, strict_mode, &found);
2141 if (found) return result;
2142 // The proxy does not define the property as an accessor.
2143 // Consequently, it has no effect on setting the receiver.
2144 return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
2145 }
2146 }
2147 *found = false;
2148 return heap->the_hole_value();
2149}
2150
Steve Blocka7e24c12009-10-30 11:49:00 +00002151
2152void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
2153 DescriptorArray* descriptors = map()->instance_descriptors();
Iain Merrick75681382010-08-19 15:07:18 +01002154 int number = descriptors->SearchWithCache(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00002155 if (number != DescriptorArray::kNotFound) {
2156 result->DescriptorResult(this, descriptors->GetDetails(number), number);
2157 } else {
2158 result->NotFound();
2159 }
2160}
2161
2162
Ben Murdochb0fe1622011-05-05 13:52:32 +01002163void Map::LookupInDescriptors(JSObject* holder,
2164 String* name,
2165 LookupResult* result) {
2166 DescriptorArray* descriptors = instance_descriptors();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002167 DescriptorLookupCache* cache =
2168 GetHeap()->isolate()->descriptor_lookup_cache();
Steve Block44f0eee2011-05-26 01:26:41 +01002169 int number = cache->Lookup(descriptors, name);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002170 if (number == DescriptorLookupCache::kAbsent) {
2171 number = descriptors->Search(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002172 cache->Update(descriptors, name, number);
Ben Murdochb0fe1622011-05-05 13:52:32 +01002173 }
2174 if (number != DescriptorArray::kNotFound) {
2175 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
2176 } else {
2177 result->NotFound();
2178 }
2179}
2180
2181
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002182static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2183 ASSERT(!map.is_null());
2184 for (int i = 0; i < maps->length(); ++i) {
2185 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2186 }
2187 return false;
2188}
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002189
Ben Murdoch85b71792012-04-11 18:30:58 +01002190
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002191template <class T>
2192static Handle<T> MaybeNull(T* p) {
2193 if (p == NULL) return Handle<T>::null();
2194 return Handle<T>(p);
2195}
2196
2197
2198Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
2199 ElementsKind elms_kind = elements_kind();
2200 if (elms_kind == FAST_DOUBLE_ELEMENTS) {
2201 bool dummy = true;
2202 Handle<Map> fast_map =
2203 MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
2204 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2205 return fast_map;
Ben Murdoch85b71792012-04-11 18:30:58 +01002206 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002207 return Handle<Map>::null();
2208 }
2209 if (elms_kind == FAST_SMI_ONLY_ELEMENTS) {
2210 bool dummy = true;
2211 Handle<Map> double_map =
2212 MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy));
2213 // In the current implementation, if the DOUBLE map doesn't exist, the
2214 // FAST map can't exist either.
2215 if (double_map.is_null()) return Handle<Map>::null();
2216 Handle<Map> fast_map =
2217 MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2218 &dummy));
2219 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2220 return fast_map;
2221 }
2222 if (ContainsMap(candidates, double_map)) return double_map;
2223 }
2224 return Handle<Map>::null();
2225}
Ben Murdoch85b71792012-04-11 18:30:58 +01002226
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002227static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
2228 ElementsKind elements_kind) {
2229 if (descriptor_contents->IsMap()) {
2230 Map* map = Map::cast(descriptor_contents);
2231 if (map->elements_kind() == elements_kind) {
2232 return map;
2233 }
2234 return NULL;
2235 }
2236
2237 FixedArray* map_array = FixedArray::cast(descriptor_contents);
2238 for (int i = 0; i < map_array->length(); ++i) {
2239 Object* current = map_array->get(i);
2240 // Skip undefined slots, they are sentinels for reclaimed maps.
2241 if (!current->IsUndefined()) {
2242 Map* current_map = Map::cast(map_array->get(i));
2243 if (current_map->elements_kind() == elements_kind) {
2244 return current_map;
Ben Murdoch85b71792012-04-11 18:30:58 +01002245 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002246 }
2247 }
2248
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002249 return NULL;
2250}
2251
2252
2253static MaybeObject* AddElementsTransitionMapToDescriptor(
2254 Object* descriptor_contents,
2255 Map* new_map) {
2256 // Nothing was in the descriptor for an ELEMENTS_TRANSITION,
2257 // simply add the map.
2258 if (descriptor_contents == NULL) {
2259 return new_map;
2260 }
2261
2262 // There was already a map in the descriptor, create a 2-element FixedArray
2263 // to contain the existing map plus the new one.
2264 FixedArray* new_array;
2265 Heap* heap = new_map->GetHeap();
2266 if (descriptor_contents->IsMap()) {
2267 // Must tenure, DescriptorArray expects no new-space objects.
2268 MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED);
2269 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2270 return maybe_new_array;
2271 }
2272 new_array->set(0, descriptor_contents);
2273 new_array->set(1, new_map);
2274 return new_array;
2275 }
2276
2277 // The descriptor already contained a list of maps for different ElementKinds
2278 // of ELEMENTS_TRANSITION, first check the existing array for an undefined
2279 // slot, and if that's not available, create a FixedArray to hold the existing
2280 // maps plus the new one and fill it in.
2281 FixedArray* array = FixedArray::cast(descriptor_contents);
2282 for (int i = 0; i < array->length(); ++i) {
2283 if (array->get(i)->IsUndefined()) {
2284 array->set(i, new_map);
2285 return array;
2286 }
2287 }
2288
2289 // Must tenure, DescriptorArray expects no new-space objects.
2290 MaybeObject* maybe_new_array =
2291 heap->AllocateFixedArray(array->length() + 1, TENURED);
2292 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2293 return maybe_new_array;
2294 }
2295 int i = 0;
2296 while (i < array->length()) {
2297 new_array->set(i, array->get(i));
2298 ++i;
2299 }
2300 new_array->set(i, new_map);
2301 return new_array;
2302}
2303
2304
2305String* Map::elements_transition_sentinel_name() {
2306 return GetHeap()->empty_symbol();
2307}
2308
2309
2310Object* Map::GetDescriptorContents(String* sentinel_name,
2311 bool* safe_to_add_transition) {
2312 // Get the cached index for the descriptors lookup, or find and cache it.
2313 DescriptorArray* descriptors = instance_descriptors();
2314 DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache();
2315 int index = cache->Lookup(descriptors, sentinel_name);
2316 if (index == DescriptorLookupCache::kAbsent) {
2317 index = descriptors->Search(sentinel_name);
2318 cache->Update(descriptors, sentinel_name, index);
2319 }
2320 // If the transition already exists, return its descriptor.
2321 if (index != DescriptorArray::kNotFound) {
2322 PropertyDetails details(descriptors->GetDetails(index));
2323 if (details.type() == ELEMENTS_TRANSITION) {
2324 return descriptors->GetValue(index);
2325 } else {
2326 if (safe_to_add_transition != NULL) {
2327 *safe_to_add_transition = false;
2328 }
2329 }
2330 }
2331 return NULL;
2332}
2333
2334
2335Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
2336 bool* safe_to_add_transition) {
2337 // Special case: indirect SMI->FAST transition (cf. comment in
2338 // AddElementsTransition()).
2339 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2340 elements_kind == FAST_ELEMENTS) {
2341 Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
2342 safe_to_add_transition);
2343 if (double_map == NULL) return double_map;
2344 return double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2345 safe_to_add_transition);
2346 }
2347 Object* descriptor_contents = GetDescriptorContents(
2348 elements_transition_sentinel_name(), safe_to_add_transition);
2349 if (descriptor_contents != NULL) {
2350 Map* maybe_transition_map =
2351 GetElementsTransitionMapFromDescriptor(descriptor_contents,
2352 elements_kind);
2353 ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
2354 return maybe_transition_map;
2355 }
2356 return NULL;
2357}
2358
2359
2360MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
2361 Map* transitioned_map) {
2362 // The map transition graph should be a tree, therefore the transition
2363 // from SMI to FAST elements is not done directly, but by going through
2364 // DOUBLE elements first.
2365 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2366 elements_kind == FAST_ELEMENTS) {
2367 bool safe_to_add = true;
2368 Map* double_map = this->LookupElementsTransitionMap(
2369 FAST_DOUBLE_ELEMENTS, &safe_to_add);
2370 // This method is only called when safe_to_add_transition has been found
2371 // to be true earlier.
2372 ASSERT(safe_to_add);
2373
2374 if (double_map == NULL) {
2375 MaybeObject* maybe_map = this->CopyDropTransitions();
2376 if (!maybe_map->To(&double_map)) return maybe_map;
2377 double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
2378 MaybeObject* maybe_double_transition = this->AddElementsTransition(
2379 FAST_DOUBLE_ELEMENTS, double_map);
2380 if (maybe_double_transition->IsFailure()) return maybe_double_transition;
2381 }
2382 return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map);
2383 }
2384
2385 bool safe_to_add_transition = true;
2386 Object* descriptor_contents = GetDescriptorContents(
2387 elements_transition_sentinel_name(), &safe_to_add_transition);
2388 // This method is only called when safe_to_add_transition has been found
2389 // to be true earlier.
2390 ASSERT(safe_to_add_transition);
2391 MaybeObject* maybe_new_contents =
2392 AddElementsTransitionMapToDescriptor(descriptor_contents,
2393 transitioned_map);
2394 Object* new_contents;
2395 if (!maybe_new_contents->ToObject(&new_contents)) {
2396 return maybe_new_contents;
2397 }
2398
2399 ElementsTransitionDescriptor desc(elements_transition_sentinel_name(),
2400 new_contents);
2401 Object* new_descriptors;
2402 MaybeObject* maybe_new_descriptors =
2403 instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS);
2404 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2405 return maybe_new_descriptors;
2406 }
2407 set_instance_descriptors(DescriptorArray::cast(new_descriptors));
2408 return this;
2409}
2410
2411
2412Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
2413 ElementsKind to_kind) {
2414 Isolate* isolate = object->GetIsolate();
2415 CALL_HEAP_FUNCTION(isolate,
2416 object->GetElementsTransitionMap(isolate, to_kind),
2417 Map);
2418}
2419
2420
2421MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
2422 Map* current_map = map();
2423 ElementsKind from_kind = current_map->elements_kind();
2424
2425 if (from_kind == to_kind) return current_map;
2426
2427 // Only objects with FastProperties can have DescriptorArrays and can track
2428 // element-related maps. Also don't add descriptors to maps that are shared.
2429 bool safe_to_add_transition = HasFastProperties() &&
2430 !current_map->IsUndefined() &&
2431 !current_map->is_shared();
2432
2433 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
2434 // with elements that switch back and forth between dictionary and fast
2435 // element mode.
2436 if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
2437 safe_to_add_transition = false;
2438 }
2439
2440 if (safe_to_add_transition) {
2441 // It's only safe to manipulate the descriptor array if it would be
2442 // safe to add a transition.
2443 Map* maybe_transition_map = current_map->LookupElementsTransitionMap(
2444 to_kind, &safe_to_add_transition);
2445 if (maybe_transition_map != NULL) {
2446 return maybe_transition_map;
2447 }
2448 }
2449
2450 Map* new_map = NULL;
2451
Ben Murdoch589d6972011-11-30 16:04:58 +00002452 // No transition to an existing map for the given ElementsKind. Make a new
2453 // one.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002454 { MaybeObject* maybe_map = current_map->CopyDropTransitions();
2455 if (!maybe_map->To(&new_map)) return maybe_map;
Steve Block44f0eee2011-05-26 01:26:41 +01002456 }
Steve Block44f0eee2011-05-26 01:26:41 +01002457
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002458 new_map->set_elements_kind(to_kind);
Steve Block44f0eee2011-05-26 01:26:41 +01002459
2460 // Only remember the map transition if the object's map is NOT equal to the
2461 // global object_function's map and there is not an already existing
Ben Murdoch589d6972011-11-30 16:04:58 +00002462 // non-matching element transition.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002463 Context* global_context = GetIsolate()->context()->global_context();
2464 bool allow_map_transition = safe_to_add_transition &&
2465 (global_context->object_function()->map() != map());
Steve Block44f0eee2011-05-26 01:26:41 +01002466 if (allow_map_transition) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002467 MaybeObject* maybe_transition =
2468 current_map->AddElementsTransition(to_kind, new_map);
2469 if (maybe_transition->IsFailure()) return maybe_transition;
Steve Block44f0eee2011-05-26 01:26:41 +01002470 }
Steve Block44f0eee2011-05-26 01:26:41 +01002471 return new_map;
2472}
2473
2474
Steve Blocka7e24c12009-10-30 11:49:00 +00002475void JSObject::LocalLookupRealNamedProperty(String* name,
2476 LookupResult* result) {
2477 if (IsJSGlobalProxy()) {
2478 Object* proto = GetPrototype();
2479 if (proto->IsNull()) return result->NotFound();
2480 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002481 // A GlobalProxy's prototype should always be a proper JSObject.
Steve Blocka7e24c12009-10-30 11:49:00 +00002482 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2483 }
2484
2485 if (HasFastProperties()) {
2486 LookupInDescriptor(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002487 if (result->IsFound()) {
2488 // A property, a map transition or a null descriptor was found.
2489 // We return all of these result types because
2490 // LocalLookupRealNamedProperty is used when setting properties
2491 // where map transitions and null descriptors are handled.
Steve Blocka7e24c12009-10-30 11:49:00 +00002492 ASSERT(result->holder() == this && result->type() != NORMAL);
2493 // Disallow caching for uninitialized constants. These can only
2494 // occur as fields.
2495 if (result->IsReadOnly() && result->type() == FIELD &&
2496 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2497 result->DisallowCaching();
2498 }
2499 return;
2500 }
2501 } else {
2502 int entry = property_dictionary()->FindEntry(name);
2503 if (entry != StringDictionary::kNotFound) {
2504 Object* value = property_dictionary()->ValueAt(entry);
2505 if (IsGlobalObject()) {
2506 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2507 if (d.IsDeleted()) {
2508 result->NotFound();
2509 return;
2510 }
2511 value = JSGlobalPropertyCell::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002512 }
2513 // Make sure to disallow caching for uninitialized constants
2514 // found in the dictionary-mode objects.
2515 if (value->IsTheHole()) result->DisallowCaching();
2516 result->DictionaryResult(this, entry);
2517 return;
2518 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002519 }
2520 result->NotFound();
2521}
2522
2523
2524void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2525 LocalLookupRealNamedProperty(name, result);
2526 if (result->IsProperty()) return;
2527
2528 LookupRealNamedPropertyInPrototypes(name, result);
2529}
2530
2531
2532void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2533 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01002534 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002535 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002536 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002537 pt = JSObject::cast(pt)->GetPrototype()) {
2538 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002539 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002540 }
2541 result->NotFound();
2542}
2543
2544
2545// We only need to deal with CALLBACKS and INTERCEPTORS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002546MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2547 LookupResult* result,
2548 String* name,
2549 Object* value,
2550 bool check_prototype,
2551 StrictModeFlag strict_mode) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002552 if (check_prototype && !result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002553 LookupCallbackSetterInPrototypes(name, result);
2554 }
2555
2556 if (result->IsProperty()) {
2557 if (!result->IsReadOnly()) {
2558 switch (result->type()) {
2559 case CALLBACKS: {
2560 Object* obj = result->GetCallbackObject();
2561 if (obj->IsAccessorInfo()) {
2562 AccessorInfo* info = AccessorInfo::cast(obj);
2563 if (info->all_can_write()) {
2564 return SetPropertyWithCallback(result->GetCallbackObject(),
2565 name,
2566 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002567 result->holder(),
2568 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002569 }
2570 }
2571 break;
2572 }
2573 case INTERCEPTOR: {
2574 // Try lookup real named properties. Note that only property can be
2575 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002576 LookupResult r(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00002577 LookupRealNamedProperty(name, &r);
2578 if (r.IsProperty()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002579 return SetPropertyWithFailedAccessCheck(&r,
2580 name,
2581 value,
2582 check_prototype,
2583 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002584 }
2585 break;
2586 }
2587 default: {
2588 break;
2589 }
2590 }
2591 }
2592 }
2593
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002594 Isolate* isolate = GetIsolate();
2595 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002596 Handle<Object> value_handle(value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002597 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
Iain Merrick75681382010-08-19 15:07:18 +01002598 return *value_handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00002599}
2600
2601
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002602MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2603 String* key,
2604 Object* value,
2605 PropertyAttributes attributes,
2606 StrictModeFlag strict_mode) {
2607 if (result->IsFound() && result->type() == HANDLER) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002608 return result->proxy()->SetPropertyWithHandler(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002609 key, value, attributes, strict_mode);
2610 } else {
2611 return JSObject::cast(this)->SetPropertyForResult(
2612 result, key, value, attributes, strict_mode);
2613 }
2614}
2615
2616
2617bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2618 Isolate* isolate = GetIsolate();
2619 HandleScope scope(isolate);
2620 Handle<Object> receiver(this);
2621 Handle<Object> name(name_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002622
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002623 Handle<Object> args[] = { name };
2624 Handle<Object> result = CallTrap(
2625 "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002626 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002627
2628 return result->ToBoolean()->IsTrue();
2629}
2630
2631
2632MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2633 String* name_raw,
2634 Object* value_raw,
2635 PropertyAttributes attributes,
2636 StrictModeFlag strict_mode) {
2637 Isolate* isolate = GetIsolate();
2638 HandleScope scope(isolate);
2639 Handle<Object> receiver(this);
2640 Handle<Object> name(name_raw);
2641 Handle<Object> value(value_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002642
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002643 Handle<Object> args[] = { receiver, name, value };
2644 CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002645 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002646
2647 return *value;
2648}
2649
2650
2651MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
2652 String* name_raw,
2653 Object* value_raw,
2654 PropertyAttributes attributes,
2655 StrictModeFlag strict_mode,
2656 bool* found) {
2657 *found = true; // except where defined otherwise...
2658 Isolate* isolate = GetHeap()->isolate();
2659 Handle<JSProxy> proxy(this);
2660 Handle<Object> handler(this->handler()); // Trap might morph proxy.
2661 Handle<String> name(name_raw);
2662 Handle<Object> value(value_raw);
2663 Handle<Object> args[] = { name };
2664 Handle<Object> result = proxy->CallTrap(
2665 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
2666 if (isolate->has_pending_exception()) return Failure::Exception();
2667
2668 if (!result->IsUndefined()) {
2669 // The proxy handler cares about this property.
2670 // Check whether it is virtualized as an accessor.
2671 // Emulate [[GetProperty]] semantics for proxies.
2672 bool has_pending_exception;
2673 Handle<Object> argv[] = { result };
2674 Handle<Object> desc =
2675 Execution::Call(isolate->to_complete_property_descriptor(), result,
2676 ARRAY_SIZE(argv), argv, &has_pending_exception);
2677 if (has_pending_exception) return Failure::Exception();
2678
2679 Handle<String> conf_name =
2680 isolate->factory()->LookupAsciiSymbol("configurable_");
2681 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
2682 ASSERT(!isolate->has_pending_exception());
2683 if (configurable->IsFalse()) {
2684 Handle<String> trap =
2685 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2686 Handle<Object> args[] = { handler, trap, name };
2687 Handle<Object> error = isolate->factory()->NewTypeError(
2688 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2689 return isolate->Throw(*error);
2690 }
2691 ASSERT(configurable->IsTrue());
2692
2693 // Check for AccessorDescriptor.
2694 Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
2695 Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
2696 ASSERT(!isolate->has_pending_exception());
2697 if (!setter->IsUndefined()) {
2698 // We have a setter -- invoke it.
2699 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2700 return proxy->SetPropertyWithDefinedSetter(
2701 JSReceiver::cast(*setter), *value);
2702 } else {
2703 Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
2704 Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
2705 ASSERT(!isolate->has_pending_exception());
2706 if (!getter->IsUndefined()) {
2707 // We have a getter but no setter -- the property may not be
2708 // written. In strict mode, throw an error.
2709 if (strict_mode == kNonStrictMode) return *value;
2710 Handle<Object> args[] = { name, proxy };
2711 Handle<Object> error = isolate->factory()->NewTypeError(
2712 "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
2713 return isolate->Throw(*error);
2714 }
2715 }
2716 // Fall-through.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002717 }
2718
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002719 // The proxy does not define the property as an accessor.
2720 *found = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002721 return *value;
2722}
2723
2724
2725MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2726 String* name_raw, DeleteMode mode) {
2727 Isolate* isolate = GetIsolate();
2728 HandleScope scope(isolate);
2729 Handle<Object> receiver(this);
2730 Handle<Object> name(name_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002731
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002732 Handle<Object> args[] = { name };
2733 Handle<Object> result = CallTrap(
2734 "delete", Handle<Object>(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002735 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002736
2737 Object* bool_result = result->ToBoolean();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002738 if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
2739 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2740 Handle<Object> args[] = { Handle<Object>(handler()), trap_name };
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002741 Handle<Object> error = isolate->factory()->NewTypeError(
2742 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2743 isolate->Throw(*error);
2744 return Failure::Exception();
2745 }
2746 return bool_result;
2747}
2748
2749
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002750MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
2751 uint32_t index,
2752 DeleteMode mode) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00002753 Isolate* isolate = GetIsolate();
2754 HandleScope scope(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002755 Handle<String> name = isolate->factory()->Uint32ToString(index);
2756 return JSProxy::DeletePropertyWithHandler(*name, mode);
2757}
2758
2759
2760MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2761 JSReceiver* receiver_raw,
2762 String* name_raw) {
2763 Isolate* isolate = GetIsolate();
2764 HandleScope scope(isolate);
2765 Handle<JSProxy> proxy(this);
2766 Handle<Object> handler(this->handler()); // Trap might morph proxy.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002767 Handle<JSReceiver> receiver(receiver_raw);
2768 Handle<Object> name(name_raw);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002769
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002770 Handle<Object> args[] = { name };
2771 Handle<Object> result = CallTrap(
2772 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
Ben Murdoch589d6972011-11-30 16:04:58 +00002773 if (isolate->has_pending_exception()) return NONE;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002774
2775 if (result->IsUndefined()) return ABSENT;
2776
2777 bool has_pending_exception;
2778 Handle<Object> argv[] = { result };
2779 Handle<Object> desc =
2780 Execution::Call(isolate->to_complete_property_descriptor(), result,
2781 ARRAY_SIZE(argv), argv, &has_pending_exception);
2782 if (has_pending_exception) return NONE;
2783
2784 // Convert result to PropertyAttributes.
2785 Handle<String> enum_n = isolate->factory()->LookupAsciiSymbol("enumerable");
2786 Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_n));
2787 if (isolate->has_pending_exception()) return NONE;
2788 Handle<String> conf_n = isolate->factory()->LookupAsciiSymbol("configurable");
2789 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_n));
2790 if (isolate->has_pending_exception()) return NONE;
2791 Handle<String> writ_n = isolate->factory()->LookupAsciiSymbol("writable");
2792 Handle<Object> writable(v8::internal::GetProperty(desc, writ_n));
2793 if (isolate->has_pending_exception()) return NONE;
2794
2795 if (configurable->IsFalse()) {
2796 Handle<String> trap =
2797 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2798 Handle<Object> args[] = { handler, trap, name };
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002799 Handle<Object> error = isolate->factory()->NewTypeError(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002800 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002801 isolate->Throw(*error);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002802 return NONE;
2803 }
2804
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002805 int attributes = NONE;
2806 if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM;
2807 if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE;
2808 if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY;
2809 return static_cast<PropertyAttributes>(attributes);
2810}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002811
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002812
2813MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
2814 JSReceiver* receiver,
2815 uint32_t index) {
2816 Isolate* isolate = GetIsolate();
2817 HandleScope scope(isolate);
2818 Handle<String> name = isolate->factory()->Uint32ToString(index);
2819 return GetPropertyAttributeWithHandler(receiver, *name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002820}
2821
2822
2823void JSProxy::Fix() {
2824 Isolate* isolate = GetIsolate();
2825 HandleScope scope(isolate);
2826 Handle<JSProxy> self(this);
2827
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002828 // Save identity hash.
2829 MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
2830
Ben Murdoch589d6972011-11-30 16:04:58 +00002831 if (IsJSFunctionProxy()) {
2832 isolate->factory()->BecomeJSFunction(self);
2833 // Code will be set on the JavaScript side.
2834 } else {
2835 isolate->factory()->BecomeJSObject(self);
2836 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002837 ASSERT(self->IsJSObject());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002838
2839 // Inherit identity, if it was present.
2840 Object* hash;
2841 if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
2842 Handle<JSObject> new_self(JSObject::cast(*self));
2843 isolate->factory()->SetIdentityHash(new_self, hash);
2844 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002845}
2846
2847
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002848MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
2849 Handle<Object> derived,
2850 int argc,
2851 Handle<Object> argv[]) {
2852 Isolate* isolate = GetIsolate();
2853 Handle<Object> handler(this->handler());
2854
2855 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol(name);
2856 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2857 if (isolate->has_pending_exception()) return trap;
2858
2859 if (trap->IsUndefined()) {
2860 if (derived.is_null()) {
2861 Handle<Object> args[] = { handler, trap_name };
2862 Handle<Object> error = isolate->factory()->NewTypeError(
2863 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2864 isolate->Throw(*error);
2865 return Handle<Object>();
2866 }
2867 trap = Handle<Object>(derived);
2868 }
2869
2870 bool threw;
2871 return Execution::Call(trap, handler, argc, argv, &threw);
2872}
2873
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002874
2875MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
2876 String* name,
2877 Object* value,
2878 PropertyAttributes attributes,
2879 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002880 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002881 // Make sure that the top context does not change when doing callbacks or
2882 // interceptor calls.
2883 AssertNoContextChange ncc;
2884
Steve Blockd0582a62009-12-15 09:54:21 +00002885 // Optimization for 2-byte strings often used as keys in a decompression
2886 // dictionary. We make these short keys into symbols to avoid constantly
2887 // reallocating them.
2888 if (!name->IsSymbol() && name->length() <= 2) {
John Reck59135872010-11-02 12:39:01 -07002889 Object* symbol_version;
Steve Block44f0eee2011-05-26 01:26:41 +01002890 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
John Reck59135872010-11-02 12:39:01 -07002891 if (maybe_symbol_version->ToObject(&symbol_version)) {
2892 name = String::cast(symbol_version);
2893 }
2894 }
Steve Blockd0582a62009-12-15 09:54:21 +00002895 }
2896
Steve Blocka7e24c12009-10-30 11:49:00 +00002897 // Check access rights if needed.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002898 if (IsAccessCheckNeeded()) {
2899 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
2900 return SetPropertyWithFailedAccessCheck(
2901 result, name, value, true, strict_mode);
2902 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002903 }
2904
2905 if (IsJSGlobalProxy()) {
2906 Object* proto = GetPrototype();
2907 if (proto->IsNull()) return value;
2908 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002909 return JSObject::cast(proto)->SetPropertyForResult(
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002910 result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002911 }
2912
2913 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002914 bool found = false;
2915 MaybeObject* result_object;
2916 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
2917 value,
2918 attributes,
2919 &found,
2920 strict_mode);
2921 if (found) return result_object;
Steve Blocka7e24c12009-10-30 11:49:00 +00002922 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002923
2924 // At this point, no GC should have happened, as this would invalidate
2925 // 'result', which we cannot handlify!
2926
Andrei Popescu402d9372010-02-26 13:31:12 +00002927 if (!result->IsFound()) {
2928 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002929 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002930 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002931 if (result->IsReadOnly() && result->IsProperty()) {
2932 if (strict_mode == kStrictMode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002933 Handle<JSObject> self(this);
2934 Handle<String> hname(name);
2935 Handle<Object> args[] = { hname, self };
Steve Block44f0eee2011-05-26 01:26:41 +01002936 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002937 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002938 } else {
2939 return value;
2940 }
2941 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002942 // This is a real property that is not read-only, or it is a
2943 // transition or null descriptor and there are no setters in the prototypes.
2944 switch (result->type()) {
2945 case NORMAL:
2946 return SetNormalizedProperty(result, value);
2947 case FIELD:
2948 return FastPropertyAtPut(result->GetFieldIndex(), value);
2949 case MAP_TRANSITION:
2950 if (attributes == result->GetAttributes()) {
2951 // Only use map transition if the attributes match.
2952 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2953 name,
2954 value);
2955 }
2956 return ConvertDescriptorToField(name, value, attributes);
2957 case CONSTANT_FUNCTION:
2958 // Only replace the function if necessary.
2959 if (value == result->GetConstantFunction()) return value;
2960 // Preserve the attributes of this existing property.
2961 attributes = result->GetAttributes();
2962 return ConvertDescriptorToField(name, value, attributes);
2963 case CALLBACKS:
2964 return SetPropertyWithCallback(result->GetCallbackObject(),
2965 name,
2966 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002967 result->holder(),
2968 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002969 case INTERCEPTOR:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002970 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
Iain Merrick75681382010-08-19 15:07:18 +01002971 case CONSTANT_TRANSITION: {
2972 // If the same constant function is being added we can simply
2973 // transition to the target map.
2974 Map* target_map = result->GetTransitionMap();
2975 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2976 int number = target_descriptors->SearchWithCache(name);
2977 ASSERT(number != DescriptorArray::kNotFound);
2978 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2979 JSFunction* function =
2980 JSFunction::cast(target_descriptors->GetValue(number));
Iain Merrick75681382010-08-19 15:07:18 +01002981 if (value == function) {
2982 set_map(target_map);
2983 return value;
2984 }
2985 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2986 // FIELD, even if the value is a constant function.
Steve Blocka7e24c12009-10-30 11:49:00 +00002987 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Iain Merrick75681382010-08-19 15:07:18 +01002988 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002989 case NULL_DESCRIPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00002990 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002991 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002992 case HANDLER:
Steve Blocka7e24c12009-10-30 11:49:00 +00002993 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002994 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00002995 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002996 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +00002997 return value;
2998}
2999
3000
3001// Set a real local property, even if it is READ_ONLY. If the property is not
3002// present, add it with attributes NONE. This code is an exact clone of
3003// SetProperty, with the check for IsReadOnly and the check for a
3004// callback setter removed. The two lines looking up the LookupResult
3005// result are also added. If one of the functions is changed, the other
3006// should be.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003007// Note that this method cannot be used to set the prototype of a function
3008// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
3009// doesn't handle function prototypes correctly.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003010Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
3011 Handle<JSObject> object,
3012 Handle<String> key,
3013 Handle<Object> value,
3014 PropertyAttributes attributes) {
3015 CALL_HEAP_FUNCTION(
3016 object->GetIsolate(),
3017 object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
3018 Object);
3019}
3020
3021
Ben Murdoch086aeea2011-05-13 15:57:08 +01003022MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00003023 String* name,
3024 Object* value,
3025 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01003026
Steve Blocka7e24c12009-10-30 11:49:00 +00003027 // Make sure that the top context does not change when doing callbacks or
3028 // interceptor calls.
3029 AssertNoContextChange ncc;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003030 Isolate* isolate = GetIsolate();
3031 LookupResult result(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00003032 LocalLookup(name, &result);
Steve Blocka7e24c12009-10-30 11:49:00 +00003033 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003034 if (IsAccessCheckNeeded()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003035 if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003036 return SetPropertyWithFailedAccessCheck(&result,
3037 name,
3038 value,
3039 false,
3040 kNonStrictMode);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003041 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003042 }
3043
3044 if (IsJSGlobalProxy()) {
3045 Object* proto = GetPrototype();
3046 if (proto->IsNull()) return value;
3047 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch086aeea2011-05-13 15:57:08 +01003048 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00003049 name,
3050 value,
3051 attributes);
3052 }
3053
3054 // Check for accessor in prototype chain removed here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00003055 if (!result.IsFound()) {
3056 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01003057 return AddProperty(name, value, attributes, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003058 }
Steve Block6ded16b2010-05-10 14:33:55 +01003059
Andrei Popescu402d9372010-02-26 13:31:12 +00003060 PropertyDetails details = PropertyDetails(attributes, NORMAL);
3061
Steve Blocka7e24c12009-10-30 11:49:00 +00003062 // Check of IsReadOnly removed from here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00003063 switch (result.type()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003064 case NORMAL:
Andrei Popescu402d9372010-02-26 13:31:12 +00003065 return SetNormalizedProperty(name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00003066 case FIELD:
Andrei Popescu402d9372010-02-26 13:31:12 +00003067 return FastPropertyAtPut(result.GetFieldIndex(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00003068 case MAP_TRANSITION:
Andrei Popescu402d9372010-02-26 13:31:12 +00003069 if (attributes == result.GetAttributes()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003070 // Only use map transition if the attributes match.
Andrei Popescu402d9372010-02-26 13:31:12 +00003071 return AddFastPropertyUsingMap(result.GetTransitionMap(),
Steve Blocka7e24c12009-10-30 11:49:00 +00003072 name,
3073 value);
3074 }
3075 return ConvertDescriptorToField(name, value, attributes);
3076 case CONSTANT_FUNCTION:
3077 // Only replace the function if necessary.
Andrei Popescu402d9372010-02-26 13:31:12 +00003078 if (value == result.GetConstantFunction()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00003079 // Preserve the attributes of this existing property.
Andrei Popescu402d9372010-02-26 13:31:12 +00003080 attributes = result.GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +00003081 return ConvertDescriptorToField(name, value, attributes);
3082 case CALLBACKS:
3083 case INTERCEPTOR:
3084 // Override callback in clone
3085 return ConvertDescriptorToField(name, value, attributes);
3086 case CONSTANT_TRANSITION:
3087 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
3088 // if the value is a function.
3089 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
3090 case NULL_DESCRIPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00003091 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00003092 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003093 case HANDLER:
Steve Blocka7e24c12009-10-30 11:49:00 +00003094 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003095 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00003096 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003097 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +00003098 return value;
3099}
3100
3101
3102PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
3103 JSObject* receiver,
3104 String* name,
3105 bool continue_search) {
3106 // Check local property, ignore interceptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003107 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003108 LocalLookupRealNamedProperty(name, &result);
3109 if (result.IsProperty()) return result.GetAttributes();
3110
3111 if (continue_search) {
3112 // Continue searching via the prototype chain.
3113 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003114 if (!pt->IsNull()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003115 return JSObject::cast(pt)->
3116 GetPropertyAttributeWithReceiver(receiver, name);
3117 }
3118 }
3119 return ABSENT;
3120}
3121
3122
3123PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
3124 JSObject* receiver,
3125 String* name,
3126 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +01003127 Isolate* isolate = GetIsolate();
3128
Steve Blocka7e24c12009-10-30 11:49:00 +00003129 // Make sure that the top context does not change when doing
3130 // callbacks or interceptor calls.
3131 AssertNoContextChange ncc;
3132
Steve Block44f0eee2011-05-26 01:26:41 +01003133 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003134 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3135 Handle<JSObject> receiver_handle(receiver);
3136 Handle<JSObject> holder_handle(this);
3137 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01003138 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003139 v8::AccessorInfo info(args.end());
3140 if (!interceptor->query()->IsUndefined()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003141 v8::NamedPropertyQuery query =
3142 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01003143 LOG(isolate,
3144 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003145 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00003146 {
3147 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003148 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003149 result = query(v8::Utils::ToLocal(name_handle), info);
3150 }
3151 if (!result.IsEmpty()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01003152 ASSERT(result->IsInt32());
3153 return static_cast<PropertyAttributes>(result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00003154 }
3155 } else if (!interceptor->getter()->IsUndefined()) {
3156 v8::NamedPropertyGetter getter =
3157 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01003158 LOG(isolate,
3159 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
Steve Blocka7e24c12009-10-30 11:49:00 +00003160 v8::Handle<v8::Value> result;
3161 {
3162 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003163 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003164 result = getter(v8::Utils::ToLocal(name_handle), info);
3165 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003166 if (!result.IsEmpty()) return DONT_ENUM;
Steve Blocka7e24c12009-10-30 11:49:00 +00003167 }
3168 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
3169 *name_handle,
3170 continue_search);
3171}
3172
3173
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003174PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
3175 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00003176 String* key) {
3177 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003178 if (IsJSObject() && key->AsArrayIndex(&index)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003179 return JSObject::cast(this)->HasElementWithReceiver(receiver, index)
3180 ? NONE : ABSENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00003181 }
3182 // Named property.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003183 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003184 Lookup(key, &result);
3185 return GetPropertyAttribute(receiver, &result, key, true);
3186}
3187
3188
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003189PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
3190 LookupResult* result,
3191 String* name,
3192 bool continue_search) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003193 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003194 if (IsAccessCheckNeeded()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003195 JSObject* this_obj = JSObject::cast(this);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003196 Heap* heap = GetHeap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003197 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
3198 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
3199 receiver, result, name, continue_search);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003200 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003201 }
Andrei Popescu402d9372010-02-26 13:31:12 +00003202 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003203 switch (result->type()) {
3204 case NORMAL: // fall through
3205 case FIELD:
3206 case CONSTANT_FUNCTION:
3207 case CALLBACKS:
3208 return result->GetAttributes();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003209 case HANDLER: {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003210 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler(
3211 receiver, name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003212 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003213 case INTERCEPTOR:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003214 return result->holder()->GetPropertyAttributeWithInterceptor(
3215 JSObject::cast(receiver), name, continue_search);
Steve Blocka7e24c12009-10-30 11:49:00 +00003216 default:
3217 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00003218 }
3219 }
3220 return ABSENT;
3221}
3222
3223
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003224PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003225 // Check whether the name is an array index.
3226 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003227 if (IsJSObject() && name->AsArrayIndex(&index)) {
3228 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
Steve Blocka7e24c12009-10-30 11:49:00 +00003229 return ABSENT;
3230 }
3231 // Named property.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003232 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003233 LocalLookup(name, &result);
3234 return GetPropertyAttribute(this, &result, name, false);
3235}
3236
3237
John Reck59135872010-11-02 12:39:01 -07003238MaybeObject* NormalizedMapCache::Get(JSObject* obj,
3239 PropertyNormalizationMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003240 Isolate* isolate = obj->GetIsolate();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003241 Map* fast = obj->map();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003242 int index = fast->Hash() % kEntries;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003243 Object* result = get(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003244 if (result->IsMap() &&
3245 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003246#ifdef DEBUG
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003247 if (FLAG_verify_heap) {
3248 Map::cast(result)->SharedMapVerify();
3249 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003250 if (FLAG_enable_slow_asserts) {
3251 // The cached map should match newly created normalized map bit-by-bit.
John Reck59135872010-11-02 12:39:01 -07003252 Object* fresh;
3253 { MaybeObject* maybe_fresh =
3254 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3255 if (maybe_fresh->ToObject(&fresh)) {
3256 ASSERT(memcmp(Map::cast(fresh)->address(),
3257 Map::cast(result)->address(),
3258 Map::kSize) == 0);
3259 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003260 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003261 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003262#endif
3263 return result;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003264 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003265
John Reck59135872010-11-02 12:39:01 -07003266 { MaybeObject* maybe_result =
3267 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3268 if (!maybe_result->ToObject(&result)) return maybe_result;
3269 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003270 set(index, result);
Steve Block44f0eee2011-05-26 01:26:41 +01003271 isolate->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003272
3273 return result;
3274}
3275
3276
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003277void NormalizedMapCache::Clear() {
3278 int entries = length();
3279 for (int i = 0; i != entries; i++) {
3280 set_undefined(i);
3281 }
3282}
3283
3284
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003285void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
3286 Handle<String> name,
3287 Handle<Code> code) {
3288 Isolate* isolate = object->GetIsolate();
3289 CALL_HEAP_FUNCTION_VOID(isolate,
3290 object->UpdateMapCodeCache(*name, *code));
3291}
3292
3293
John Reck59135872010-11-02 12:39:01 -07003294MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003295 if (map()->is_shared()) {
3296 // Fast case maps are never marked as shared.
3297 ASSERT(!HasFastProperties());
3298 // Replace the map with an identical copy that can be safely modified.
John Reck59135872010-11-02 12:39:01 -07003299 Object* obj;
3300 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
3301 UNIQUE_NORMALIZED_MAP);
3302 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3303 }
Steve Block44f0eee2011-05-26 01:26:41 +01003304 GetIsolate()->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003305
3306 set_map(Map::cast(obj));
3307 }
3308 return map()->UpdateCodeCache(name, code);
3309}
3310
3311
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003312void JSObject::NormalizeProperties(Handle<JSObject> object,
3313 PropertyNormalizationMode mode,
3314 int expected_additional_properties) {
3315 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
3316 object->NormalizeProperties(
3317 mode, expected_additional_properties));
3318}
3319
3320
John Reck59135872010-11-02 12:39:01 -07003321MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
3322 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003323 if (!HasFastProperties()) return this;
3324
3325 // The global object is always normalized.
3326 ASSERT(!IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01003327 // JSGlobalProxy must never be normalized
3328 ASSERT(!IsJSGlobalProxy());
3329
Ben Murdoch8b112d22011-06-08 16:22:53 +01003330 Map* map_of_this = map();
Steve Block44f0eee2011-05-26 01:26:41 +01003331
Steve Blocka7e24c12009-10-30 11:49:00 +00003332 // Allocate new content.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003333 int property_count = map_of_this->NumberOfDescribedProperties();
Steve Blocka7e24c12009-10-30 11:49:00 +00003334 if (expected_additional_properties > 0) {
3335 property_count += expected_additional_properties;
3336 } else {
3337 property_count += 2; // Make space for two more properties.
3338 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003339 StringDictionary* dictionary;
3340 { MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count);
3341 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
John Reck59135872010-11-02 12:39:01 -07003342 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003343
Ben Murdoch8b112d22011-06-08 16:22:53 +01003344 DescriptorArray* descs = map_of_this->instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00003345 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01003346 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00003347 switch (details.type()) {
3348 case CONSTANT_FUNCTION: {
3349 PropertyDetails d =
3350 PropertyDetails(details.attributes(), NORMAL, details.index());
3351 Object* value = descs->GetConstantFunction(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003352 MaybeObject* maybe_dictionary =
3353 dictionary->Add(descs->GetKey(i), value, d);
3354 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00003355 break;
3356 }
3357 case FIELD: {
3358 PropertyDetails d =
3359 PropertyDetails(details.attributes(), NORMAL, details.index());
3360 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003361 MaybeObject* maybe_dictionary =
3362 dictionary->Add(descs->GetKey(i), value, d);
3363 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00003364 break;
3365 }
3366 case CALLBACKS: {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003367 if (!descs->IsProperty(i)) break;
Steve Blocka7e24c12009-10-30 11:49:00 +00003368 Object* value = descs->GetCallbacksObject(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003369 if (value->IsAccessorPair()) {
3370 MaybeObject* maybe_copy =
3371 AccessorPair::cast(value)->CopyWithoutTransitions();
3372 if (!maybe_copy->To(&value)) return maybe_copy;
John Reck59135872010-11-02 12:39:01 -07003373 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003374 MaybeObject* maybe_dictionary =
3375 dictionary->Add(descs->GetKey(i), value, details);
3376 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00003377 break;
3378 }
3379 case MAP_TRANSITION:
3380 case CONSTANT_TRANSITION:
3381 case NULL_DESCRIPTOR:
3382 case INTERCEPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00003383 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00003384 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003385 case HANDLER:
3386 case NORMAL:
Steve Blocka7e24c12009-10-30 11:49:00 +00003387 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003388 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00003389 }
3390 }
3391
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003392 Heap* current_heap = GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01003393
Steve Blocka7e24c12009-10-30 11:49:00 +00003394 // Copy the next enumeration index from instance descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01003395 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00003396 dictionary->SetNextEnumerationIndex(index);
3397
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003398 Map* new_map;
3399 { MaybeObject* maybe_map =
Ben Murdoch8b112d22011-06-08 16:22:53 +01003400 current_heap->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01003401 normalized_map_cache()->Get(this, mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003402 if (!maybe_map->To(&new_map)) return maybe_map;
John Reck59135872010-11-02 12:39:01 -07003403 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003404
Steve Blocka7e24c12009-10-30 11:49:00 +00003405 // We have now successfully allocated all the necessary objects.
3406 // Changes can now be made with the guarantee that all of them take effect.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003407
3408 // Resize the object in the heap if necessary.
3409 int new_instance_size = new_map->instance_size();
Ben Murdoch8b112d22011-06-08 16:22:53 +01003410 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003411 ASSERT(instance_size_delta >= 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003412 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
3413 instance_size_delta);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003414 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
3415 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
3416 -instance_size_delta);
3417 }
3418
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003419
Steve Blocka7e24c12009-10-30 11:49:00 +00003420 set_map(new_map);
Ben Murdoch257744e2011-11-30 15:57:28 +00003421 new_map->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00003422
3423 set_properties(dictionary);
3424
Ben Murdoch8b112d22011-06-08 16:22:53 +01003425 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00003426
3427#ifdef DEBUG
3428 if (FLAG_trace_normalization) {
3429 PrintF("Object properties have been normalized:\n");
3430 Print();
3431 }
3432#endif
3433 return this;
3434}
3435
3436
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003437void JSObject::TransformToFastProperties(Handle<JSObject> object,
3438 int unused_property_fields) {
3439 CALL_HEAP_FUNCTION_VOID(
3440 object->GetIsolate(),
3441 object->TransformToFastProperties(unused_property_fields));
3442}
3443
3444
John Reck59135872010-11-02 12:39:01 -07003445MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003446 if (HasFastProperties()) return this;
3447 ASSERT(!IsGlobalObject());
3448 return property_dictionary()->
3449 TransformPropertiesToFastFor(this, unused_property_fields);
3450}
3451
3452
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003453Handle<SeededNumberDictionary> JSObject::NormalizeElements(
3454 Handle<JSObject> object) {
3455 CALL_HEAP_FUNCTION(object->GetIsolate(),
3456 object->NormalizeElements(),
3457 SeededNumberDictionary);
3458}
3459
3460
John Reck59135872010-11-02 12:39:01 -07003461MaybeObject* JSObject::NormalizeElements() {
Steve Block44f0eee2011-05-26 01:26:41 +01003462 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01003463
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003464 // Find the backing store.
3465 FixedArrayBase* array = FixedArrayBase::cast(elements());
3466 Map* old_map = array->map();
3467 bool is_arguments =
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003468 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003469 if (is_arguments) {
3470 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
John Reck59135872010-11-02 12:39:01 -07003471 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003472 if (array->IsDictionary()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00003473
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003474 ASSERT(HasFastElements() ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003475 HasFastSmiOnlyElements() ||
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003476 HasFastDoubleElements() ||
3477 HasFastArgumentsElements());
3478 // Compute the effective length and allocate a new backing store.
3479 int length = IsJSArray()
3480 ? Smi::cast(JSArray::cast(this)->length())->value()
3481 : array->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003482 int old_capacity = 0;
3483 int used_elements = 0;
3484 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdochc7cc0282012-03-05 14:35:55 +00003485 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003486 { Object* object;
Ben Murdochc7cc0282012-03-05 14:35:55 +00003487 MaybeObject* maybe = SeededNumberDictionary::Allocate(used_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003488 if (!maybe->ToObject(&object)) return maybe;
Ben Murdochc7cc0282012-03-05 14:35:55 +00003489 dictionary = SeededNumberDictionary::cast(object);
John Reck59135872010-11-02 12:39:01 -07003490 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003491
3492 // Copy the elements to the new backing store.
3493 bool has_double_elements = array->IsFixedDoubleArray();
Steve Blocka7e24c12009-10-30 11:49:00 +00003494 for (int i = 0; i < length; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003495 Object* value = NULL;
3496 if (has_double_elements) {
3497 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
3498 if (double_array->is_the_hole(i)) {
3499 value = GetIsolate()->heap()->the_hole_value();
3500 } else {
3501 // Objects must be allocated in the old object space, since the
3502 // overall number of HeapNumbers needed for the conversion might
3503 // exceed the capacity of new space, and we would fail repeatedly
3504 // trying to convert the FixedDoubleArray.
3505 MaybeObject* maybe_value_object =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003506 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003507 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
John Reck59135872010-11-02 12:39:01 -07003508 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003509 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003510 ASSERT(old_map->has_fast_elements() ||
3511 old_map->has_fast_smi_only_elements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003512 value = FixedArray::cast(array)->get(i);
3513 }
3514 PropertyDetails details = PropertyDetails(NONE, NORMAL);
3515 if (!value->IsTheHole()) {
3516 Object* result;
3517 MaybeObject* maybe_result =
3518 dictionary->AddNumberEntry(i, value, details);
3519 if (!maybe_result->ToObject(&result)) return maybe_result;
Ben Murdochc7cc0282012-03-05 14:35:55 +00003520 dictionary = SeededNumberDictionary::cast(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00003521 }
3522 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003523
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003524 // Switch to using the dictionary as the backing storage for elements.
3525 if (is_arguments) {
3526 FixedArray::cast(elements())->set(1, dictionary);
3527 } else {
3528 // Set the new map first to satify the elements type assert in
3529 // set_elements().
3530 Object* new_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003531 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
3532 DICTIONARY_ELEMENTS);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003533 if (!maybe->ToObject(&new_map)) return maybe;
3534 set_map(Map::cast(new_map));
3535 set_elements(dictionary);
3536 }
3537
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003538 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
3539 Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00003540
3541#ifdef DEBUG
3542 if (FLAG_trace_normalization) {
3543 PrintF("Object elements have been normalized:\n");
3544 Print();
3545 }
3546#endif
3547
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003548 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
3549 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00003550}
3551
3552
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003553Smi* JSReceiver::GenerateIdentityHash() {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003554 Isolate* isolate = GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003555
3556 int hash_value;
3557 int attempts = 0;
3558 do {
3559 // Generate a random 32-bit hash value but limit range to fit
3560 // within a smi.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003561 hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003562 attempts++;
3563 } while (hash_value == 0 && attempts < 30);
3564 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
3565
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003566 return Smi::FromInt(hash_value);
3567}
3568
3569
3570MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
3571 MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3572 hash);
3573 if (maybe->IsFailure()) return maybe;
3574 return this;
3575}
3576
3577
3578int JSObject::GetIdentityHash(Handle<JSObject> obj) {
3579 CALL_AND_RETRY(obj->GetIsolate(),
3580 obj->GetIdentityHash(ALLOW_CREATION),
3581 return Smi::cast(__object__)->value(),
3582 return 0);
3583}
3584
3585
3586MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
3587 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
3588 if (stored_value->IsSmi()) return stored_value;
3589
3590 // Do not generate permanent identity hash code if not requested.
3591 if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
3592
3593 Smi* hash = GenerateIdentityHash();
3594 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3595 hash);
3596 if (result->IsFailure()) return result;
3597 if (result->ToObjectUnchecked()->IsUndefined()) {
3598 // Trying to get hash of detached proxy.
3599 return Smi::FromInt(0);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003600 }
3601 return hash;
3602}
3603
3604
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003605MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
3606 Object* hash = this->hash();
3607 if (!hash->IsSmi() && flag == ALLOW_CREATION) {
3608 hash = GenerateIdentityHash();
3609 set_hash(hash);
3610 }
3611 return hash;
3612}
3613
3614
3615Object* JSObject::GetHiddenProperty(String* key) {
3616 if (IsJSGlobalProxy()) {
3617 // For a proxy, use the prototype as target object.
3618 Object* proxy_parent = GetPrototype();
3619 // If the proxy is detached, return undefined.
3620 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3621 ASSERT(proxy_parent->IsJSGlobalObject());
3622 return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
3623 }
3624 ASSERT(!IsJSGlobalProxy());
3625 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3626 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3627 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
3628 return GetHeap()->undefined_value();
3629 }
3630 StringDictionary* dictionary =
3631 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3632 int entry = dictionary->FindEntry(key);
3633 if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
3634 return dictionary->ValueAt(entry);
3635}
3636
3637
3638Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
3639 Handle<String> key,
3640 Handle<Object> value) {
3641 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3642 obj->SetHiddenProperty(*key, *value),
3643 Object);
3644}
3645
3646
3647MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
3648 if (IsJSGlobalProxy()) {
3649 // For a proxy, use the prototype as target object.
3650 Object* proxy_parent = GetPrototype();
3651 // If the proxy is detached, return undefined.
3652 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3653 ASSERT(proxy_parent->IsJSGlobalObject());
3654 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
3655 }
3656 ASSERT(!IsJSGlobalProxy());
3657 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
3658 StringDictionary* dictionary;
3659 if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
3660
3661 // If it was found, check if the key is already in the dictionary.
3662 int entry = dictionary->FindEntry(key);
3663 if (entry != StringDictionary::kNotFound) {
3664 // If key was found, just update the value.
3665 dictionary->ValueAtPut(entry, value);
3666 return this;
3667 }
3668 // Key was not already in the dictionary, so add the entry.
3669 MaybeObject* insert_result = dictionary->Add(key,
3670 value,
3671 PropertyDetails(NONE, NORMAL));
3672 StringDictionary* new_dict;
3673 if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
3674 if (new_dict != dictionary) {
3675 // If adding the key expanded the dictionary (i.e., Add returned a new
3676 // dictionary), store it back to the object.
3677 MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
3678 if (store_result->IsFailure()) return store_result;
3679 }
3680 // Return this to mark success.
3681 return this;
3682}
3683
3684
3685void JSObject::DeleteHiddenProperty(String* key) {
3686 if (IsJSGlobalProxy()) {
3687 // For a proxy, use the prototype as target object.
3688 Object* proxy_parent = GetPrototype();
3689 // If the proxy is detached, return immediately.
3690 if (proxy_parent->IsNull()) return;
3691 ASSERT(proxy_parent->IsJSGlobalObject());
3692 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
3693 return;
3694 }
3695 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3696 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3697 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
3698 StringDictionary* dictionary =
3699 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3700 int entry = dictionary->FindEntry(key);
3701 if (entry == StringDictionary::kNotFound) {
3702 // Key wasn't in dictionary. Deletion is a success.
3703 return;
3704 }
3705 // Key was in the dictionary. Remove it.
3706 dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
3707}
3708
3709
3710bool JSObject::HasHiddenProperties() {
3711 return GetPropertyAttributePostInterceptor(this,
3712 GetHeap()->hidden_symbol(),
3713 false) != ABSENT;
3714}
3715
3716
3717MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
3718 ASSERT(!IsJSGlobalProxy());
3719 if (HasFastProperties()) {
3720 // If the object has fast properties, check whether the first slot
3721 // in the descriptor array matches the hidden symbol. Since the
3722 // hidden symbols hash code is zero (and no other string has hash
3723 // code zero) it will always occupy the first entry if present.
3724 DescriptorArray* descriptors = this->map()->instance_descriptors();
3725 if ((descriptors->number_of_descriptors() > 0) &&
3726 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3727 if (descriptors->GetType(0) == FIELD) {
3728 Object* hidden_store =
3729 this->FastPropertyAt(descriptors->GetFieldIndex(0));
3730 return StringDictionary::cast(hidden_store);
3731 } else {
3732 ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
3733 descriptors->GetType(0) == MAP_TRANSITION);
3734 }
3735 }
3736 } else {
3737 PropertyAttributes attributes;
3738 // You can't install a getter on a property indexed by the hidden symbol,
3739 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
3740 // object.
3741 Object* lookup =
3742 GetLocalPropertyPostInterceptor(this,
3743 GetHeap()->hidden_symbol(),
3744 &attributes)->ToObjectUnchecked();
3745 if (!lookup->IsUndefined()) {
3746 return StringDictionary::cast(lookup);
3747 }
3748 }
3749 if (!create_if_absent) return GetHeap()->undefined_value();
3750 const int kInitialSize = 5;
3751 MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
3752 StringDictionary* dictionary;
3753 if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
3754 MaybeObject* store_result =
3755 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3756 dictionary,
3757 DONT_ENUM,
3758 kNonStrictMode);
3759 if (store_result->IsFailure()) return store_result;
3760 return dictionary;
3761}
3762
3763
3764MaybeObject* JSObject::SetHiddenPropertiesDictionary(
3765 StringDictionary* dictionary) {
3766 ASSERT(!IsJSGlobalProxy());
3767 ASSERT(HasHiddenProperties());
3768 if (HasFastProperties()) {
3769 // If the object has fast properties, check whether the first slot
3770 // in the descriptor array matches the hidden symbol. Since the
3771 // hidden symbols hash code is zero (and no other string has hash
3772 // code zero) it will always occupy the first entry if present.
3773 DescriptorArray* descriptors = this->map()->instance_descriptors();
3774 if ((descriptors->number_of_descriptors() > 0) &&
3775 (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
3776 if (descriptors->GetType(0) == FIELD) {
3777 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
3778 return this;
3779 } else {
3780 ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
3781 descriptors->GetType(0) == MAP_TRANSITION);
3782 }
3783 }
3784 }
3785 MaybeObject* store_result =
3786 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3787 dictionary,
3788 DONT_ENUM,
3789 kNonStrictMode);
3790 if (store_result->IsFailure()) return store_result;
3791 return this;
3792}
3793
3794
John Reck59135872010-11-02 12:39:01 -07003795MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3796 DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003797 // Check local property, ignore interceptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003798 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00003799 LocalLookupRealNamedProperty(name, &result);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003800 if (!result.IsProperty()) return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003801
3802 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003803 Object* obj;
3804 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3805 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3806 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003807
3808 return DeleteNormalizedProperty(name, mode);
3809}
3810
3811
John Reck59135872010-11-02 12:39:01 -07003812MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +01003813 Isolate* isolate = GetIsolate();
3814 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003815 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3816 Handle<String> name_handle(name);
3817 Handle<JSObject> this_handle(this);
3818 if (!interceptor->deleter()->IsUndefined()) {
3819 v8::NamedPropertyDeleter deleter =
3820 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
Steve Block44f0eee2011-05-26 01:26:41 +01003821 LOG(isolate,
3822 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3823 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003824 v8::AccessorInfo info(args.end());
3825 v8::Handle<v8::Boolean> result;
3826 {
3827 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003828 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003829 result = deleter(v8::Utils::ToLocal(name_handle), info);
3830 }
Steve Block44f0eee2011-05-26 01:26:41 +01003831 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003832 if (!result.IsEmpty()) {
3833 ASSERT(result->IsBoolean());
3834 return *v8::Utils::OpenHandle(*result);
3835 }
3836 }
John Reck59135872010-11-02 12:39:01 -07003837 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00003838 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003839 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003840 return raw_result;
3841}
3842
3843
John Reck59135872010-11-02 12:39:01 -07003844MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01003845 Isolate* isolate = GetIsolate();
3846 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003847 // Make sure that the top context does not change when doing
3848 // callbacks or interceptor calls.
3849 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01003850 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003851 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Steve Block44f0eee2011-05-26 01:26:41 +01003852 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003853 v8::IndexedPropertyDeleter deleter =
3854 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3855 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01003856 LOG(isolate,
3857 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3858 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003859 v8::AccessorInfo info(args.end());
3860 v8::Handle<v8::Boolean> result;
3861 {
3862 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003863 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003864 result = deleter(index, info);
3865 }
Steve Block44f0eee2011-05-26 01:26:41 +01003866 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003867 if (!result.IsEmpty()) {
3868 ASSERT(result->IsBoolean());
3869 return *v8::Utils::OpenHandle(*result);
3870 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003871 MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3872 *this_handle,
3873 index,
3874 NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003875 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003876 return raw_result;
3877}
3878
3879
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003880Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
3881 uint32_t index) {
3882 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3883 obj->DeleteElement(index, JSObject::NORMAL_DELETION),
3884 Object);
3885}
3886
3887
John Reck59135872010-11-02 12:39:01 -07003888MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003889 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003890 // Check access rights if needed.
3891 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003892 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3893 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3894 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003895 }
3896
3897 if (IsJSGlobalProxy()) {
3898 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003899 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003900 ASSERT(proto->IsJSGlobalObject());
3901 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
3902 }
3903
3904 if (HasIndexedInterceptor()) {
3905 // Skip interceptor if forcing deletion.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003906 if (mode != FORCE_DELETION) {
3907 return DeleteElementWithInterceptor(index);
3908 }
3909 mode = JSReceiver::FORCE_DELETION;
Steve Blocka7e24c12009-10-30 11:49:00 +00003910 }
3911
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003912 return GetElementsAccessor()->Delete(this, index, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003913}
3914
3915
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003916Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj,
3917 Handle<String> prop) {
3918 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3919 obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
3920 Object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003921}
3922
3923
John Reck59135872010-11-02 12:39:01 -07003924MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003925 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003926 // ECMA-262, 3rd, 8.6.2.5
3927 ASSERT(name->IsString());
3928
3929 // Check access rights if needed.
3930 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003931 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3932 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3933 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003934 }
3935
3936 if (IsJSGlobalProxy()) {
3937 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003938 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003939 ASSERT(proto->IsJSGlobalObject());
3940 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
3941 }
3942
3943 uint32_t index = 0;
3944 if (name->AsArrayIndex(&index)) {
3945 return DeleteElement(index, mode);
3946 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003947 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003948 LocalLookup(name, &result);
Steve Block44f0eee2011-05-26 01:26:41 +01003949 if (!result.IsProperty()) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003950 // Ignore attributes if forcing a deletion.
3951 if (result.IsDontDelete() && mode != FORCE_DELETION) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003952 if (mode == STRICT_DELETION) {
3953 // Deleting a non-configurable property in strict mode.
Steve Block44f0eee2011-05-26 01:26:41 +01003954 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003955 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01003956 return isolate->Throw(*isolate->factory()->NewTypeError(
3957 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003958 }
Steve Block44f0eee2011-05-26 01:26:41 +01003959 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003960 }
3961 // Check for interceptor.
3962 if (result.type() == INTERCEPTOR) {
3963 // Skip interceptor if forcing a deletion.
3964 if (mode == FORCE_DELETION) {
3965 return DeletePropertyPostInterceptor(name, mode);
3966 }
3967 return DeletePropertyWithInterceptor(name);
3968 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003969 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003970 Object* obj;
3971 { MaybeObject* maybe_obj =
3972 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3973 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3974 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003975 // Make sure the properties are normalized before removing the entry.
3976 return DeleteNormalizedProperty(name, mode);
3977 }
3978}
3979
3980
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003981MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
3982 if (IsJSProxy()) {
3983 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
3984 }
3985 return JSObject::cast(this)->DeleteElement(index, mode);
3986}
3987
3988
3989MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3990 if (IsJSProxy()) {
3991 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
3992 }
3993 return JSObject::cast(this)->DeleteProperty(name, mode);
3994}
3995
3996
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003997bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
3998 ElementsKind kind,
3999 Object* object) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004000 ASSERT(kind == FAST_ELEMENTS ||
4001 kind == DICTIONARY_ELEMENTS);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004002 if (kind == FAST_ELEMENTS) {
4003 int length = IsJSArray()
4004 ? Smi::cast(JSArray::cast(this)->length())->value()
4005 : elements->length();
4006 for (int i = 0; i < length; ++i) {
4007 Object* element = elements->get(i);
4008 if (!element->IsTheHole() && element == object) return true;
4009 }
4010 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004011 Object* key =
4012 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004013 if (!key->IsUndefined()) return true;
4014 }
4015 return false;
4016}
4017
4018
Steve Blocka7e24c12009-10-30 11:49:00 +00004019// Check whether this object references another object.
4020bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01004021 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004022 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004023 AssertNoAllocation no_alloc;
4024
4025 // Is the object the constructor for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01004026 if (map_of_this->constructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004027 return true;
4028 }
4029
4030 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01004031 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004032 return true;
4033 }
4034
4035 // Check if the object is among the named properties.
4036 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01004037 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004038 return true;
4039 }
4040
4041 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004042 ElementsKind kind = GetElementsKind();
4043 switch (kind) {
Steve Block44f0eee2011-05-26 01:26:41 +01004044 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00004045 case EXTERNAL_BYTE_ELEMENTS:
4046 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4047 case EXTERNAL_SHORT_ELEMENTS:
4048 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4049 case EXTERNAL_INT_ELEMENTS:
4050 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4051 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00004052 case EXTERNAL_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004053 case FAST_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00004054 // Raw pixels and external arrays do not reference other
4055 // objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00004056 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004057 case FAST_SMI_ONLY_ELEMENTS:
4058 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004059 case FAST_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00004060 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004061 FixedArray* elements = FixedArray::cast(this->elements());
4062 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00004063 break;
4064 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004065 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4066 FixedArray* parameter_map = FixedArray::cast(elements());
4067 // Check the mapped parameters.
4068 int length = parameter_map->length();
4069 for (int i = 2; i < length; ++i) {
4070 Object* value = parameter_map->get(i);
4071 if (!value->IsTheHole() && value == obj) return true;
4072 }
4073 // Check the arguments.
4074 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4075 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
4076 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00004077 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004078 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004079 }
4080
Steve Block6ded16b2010-05-10 14:33:55 +01004081 // For functions check the context.
4082 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004083 // Get the constructor function for arguments array.
4084 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +01004085 heap->isolate()->context()->global_context()->
4086 arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +00004087 JSFunction* arguments_function =
4088 JSFunction::cast(arguments_boilerplate->map()->constructor());
4089
4090 // Get the context and don't check if it is the global context.
4091 JSFunction* f = JSFunction::cast(this);
4092 Context* context = f->context();
4093 if (context->IsGlobalContext()) {
4094 return false;
4095 }
4096
4097 // Check the non-special context slots.
4098 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
4099 // Only check JS objects.
4100 if (context->get(i)->IsJSObject()) {
4101 JSObject* ctxobj = JSObject::cast(context->get(i));
4102 // If it is an arguments array check the content.
4103 if (ctxobj->map()->constructor() == arguments_function) {
4104 if (ctxobj->ReferencesObject(obj)) {
4105 return true;
4106 }
4107 } else if (ctxobj == obj) {
4108 return true;
4109 }
4110 }
4111 }
4112
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004113 // Check the context extension (if any) if it can have references.
4114 if (context->has_extension() && !context->IsCatchContext()) {
4115 return JSObject::cast(context->extension())->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00004116 }
4117 }
4118
4119 // No references to object.
4120 return false;
4121}
4122
4123
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004124Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
4125 CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
4126}
4127
4128
John Reck59135872010-11-02 12:39:01 -07004129MaybeObject* JSObject::PreventExtensions() {
Steve Block44f0eee2011-05-26 01:26:41 +01004130 Isolate* isolate = GetIsolate();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004131 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004132 !isolate->MayNamedAccess(this,
4133 isolate->heap()->undefined_value(),
4134 v8::ACCESS_KEYS)) {
4135 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
4136 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01004137 }
4138
Steve Block1e0659c2011-05-24 12:43:12 +01004139 if (IsJSGlobalProxy()) {
4140 Object* proto = GetPrototype();
4141 if (proto->IsNull()) return this;
4142 ASSERT(proto->IsJSGlobalObject());
4143 return JSObject::cast(proto)->PreventExtensions();
4144 }
4145
Ben Murdoch257744e2011-11-30 15:57:28 +00004146 // It's not possible to seal objects with external array elements
4147 if (HasExternalArrayElements()) {
4148 HandleScope scope(isolate);
4149 Handle<Object> object(this);
4150 Handle<Object> error =
4151 isolate->factory()->NewTypeError(
4152 "cant_prevent_ext_external_array_elements",
4153 HandleVector(&object, 1));
4154 return isolate->Throw(*error);
4155 }
4156
Steve Block8defd9f2010-07-08 12:39:36 +01004157 // If there are fast elements we normalize.
Ben Murdochc7cc0282012-03-05 14:35:55 +00004158 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004159 { MaybeObject* maybe = NormalizeElements();
Ben Murdochc7cc0282012-03-05 14:35:55 +00004160 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
Steve Block8defd9f2010-07-08 12:39:36 +01004161 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004162 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Block8defd9f2010-07-08 12:39:36 +01004163 // Make sure that we never go back to fast case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004164 dictionary->set_requires_slow_elements();
Steve Block8defd9f2010-07-08 12:39:36 +01004165
4166 // Do a map transition, other objects with this map may still
4167 // be extensible.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004168 Map* new_map;
4169 { MaybeObject* maybe = map()->CopyDropTransitions();
4170 if (!maybe->To<Map>(&new_map)) return maybe;
John Reck59135872010-11-02 12:39:01 -07004171 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004172 new_map->set_is_extensible(false);
4173 set_map(new_map);
Steve Block8defd9f2010-07-08 12:39:36 +01004174 ASSERT(!map()->is_extensible());
4175 return new_map;
4176}
4177
4178
Steve Blocka7e24c12009-10-30 11:49:00 +00004179// Tests for the fast common case for property enumeration:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004180// - This object and all prototypes has an enum cache (which means that
4181// it is no proxy, has no interceptors and needs no access checks).
Steve Blockd0582a62009-12-15 09:54:21 +00004182// - This object has no elements.
4183// - No prototype has enumerable properties/elements.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004184bool JSReceiver::IsSimpleEnum() {
Steve Block44f0eee2011-05-26 01:26:41 +01004185 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004186 for (Object* o = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004187 o != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004188 o = JSObject::cast(o)->GetPrototype()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004189 if (!o->IsJSObject()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004190 JSObject* curr = JSObject::cast(o);
Steve Blocka7e24c12009-10-30 11:49:00 +00004191 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00004192 ASSERT(!curr->HasNamedInterceptor());
4193 ASSERT(!curr->HasIndexedInterceptor());
4194 ASSERT(!curr->IsAccessCheckNeeded());
Steve Blocka7e24c12009-10-30 11:49:00 +00004195 if (curr->NumberOfEnumElements() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004196 if (curr != this) {
4197 FixedArray* curr_fixed_array =
4198 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
Steve Blockd0582a62009-12-15 09:54:21 +00004199 if (curr_fixed_array->length() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004200 }
4201 }
4202 return true;
4203}
4204
4205
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004206int Map::NumberOfDescribedProperties(PropertyAttributes filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004207 int result = 0;
4208 DescriptorArray* descs = instance_descriptors();
4209 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004210 PropertyDetails details(descs->GetDetails(i));
4211 if (descs->IsProperty(i) && (details.attributes() & filter) == 0) {
4212 result++;
4213 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004214 }
4215 return result;
4216}
4217
4218
4219int Map::PropertyIndexFor(String* name) {
4220 DescriptorArray* descs = instance_descriptors();
4221 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4222 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
4223 return descs->GetFieldIndex(i);
4224 }
4225 }
4226 return -1;
4227}
4228
4229
4230int Map::NextFreePropertyIndex() {
4231 int max_index = -1;
4232 DescriptorArray* descs = instance_descriptors();
4233 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4234 if (descs->GetType(i) == FIELD) {
4235 int current_index = descs->GetFieldIndex(i);
4236 if (current_index > max_index) max_index = current_index;
4237 }
4238 }
4239 return max_index + 1;
4240}
4241
4242
4243AccessorDescriptor* Map::FindAccessor(String* name) {
4244 DescriptorArray* descs = instance_descriptors();
4245 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4246 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
4247 return descs->GetCallbacks(i);
4248 }
4249 }
4250 return NULL;
4251}
4252
4253
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004254void JSReceiver::LocalLookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004255 ASSERT(name->IsString());
4256
Steve Block44f0eee2011-05-26 01:26:41 +01004257 Heap* heap = GetHeap();
4258
Steve Blocka7e24c12009-10-30 11:49:00 +00004259 if (IsJSGlobalProxy()) {
4260 Object* proto = GetPrototype();
4261 if (proto->IsNull()) return result->NotFound();
4262 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004263 return JSReceiver::cast(proto)->LocalLookup(name, result);
4264 }
4265
4266 if (IsJSProxy()) {
4267 result->HandlerResult(JSProxy::cast(this));
4268 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004269 }
4270
4271 // Do not use inline caching if the object is a non-global object
4272 // that requires access checks.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004273 if (IsAccessCheckNeeded()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004274 result->DisallowCaching();
4275 }
4276
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004277 JSObject* js_object = JSObject::cast(this);
4278
Steve Blocka7e24c12009-10-30 11:49:00 +00004279 // Check __proto__ before interceptor.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004280 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004281 result->ConstantResult(js_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00004282 return;
4283 }
4284
4285 // Check for lookup interceptor except when bootstrapping.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004286 if (js_object->HasNamedInterceptor() &&
4287 !heap->isolate()->bootstrapper()->IsActive()) {
4288 result->InterceptorResult(js_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00004289 return;
4290 }
4291
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004292 js_object->LocalLookupRealNamedProperty(name, result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004293}
4294
4295
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004296void JSReceiver::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004297 // Ecma-262 3rd 8.6.2.4
Steve Block44f0eee2011-05-26 01:26:41 +01004298 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004299 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004300 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004301 current = JSObject::cast(current)->GetPrototype()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004302 JSReceiver::cast(current)->LocalLookup(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00004303 if (result->IsProperty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004304 }
4305 result->NotFound();
4306}
4307
4308
4309// Search object and it's prototype chain for callback properties.
4310void JSObject::LookupCallback(String* name, LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01004311 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004312 for (Object* current = this;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004313 current != heap->null_value() && current->IsJSObject();
Steve Blocka7e24c12009-10-30 11:49:00 +00004314 current = JSObject::cast(current)->GetPrototype()) {
4315 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004316 if (result->IsFound() && result->type() == CALLBACKS) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00004317 }
4318 result->NotFound();
4319}
4320
4321
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004322// Try to update an accessor in an elements dictionary. Return true if the
4323// update succeeded, and false otherwise.
4324static bool UpdateGetterSetterInDictionary(
4325 SeededNumberDictionary* dictionary,
4326 uint32_t index,
4327 Object* getter,
4328 Object* setter,
4329 PropertyAttributes attributes) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004330 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004331 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004332 Object* result = dictionary->ValueAt(entry);
4333 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004334 if (details.type() == CALLBACKS && result->IsAccessorPair()) {
4335 ASSERT(!details.IsDontDelete());
4336 if (details.attributes() != attributes) {
4337 dictionary->DetailsAtPut(entry,
4338 PropertyDetails(attributes, CALLBACKS, index));
4339 }
4340 AccessorPair::cast(result)->SetComponents(getter, setter);
4341 return true;
4342 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004343 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004344 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004345}
4346
4347
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004348MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
4349 Object* getter,
4350 Object* setter,
4351 PropertyAttributes attributes) {
4352 switch (GetElementsKind()) {
4353 case FAST_SMI_ONLY_ELEMENTS:
4354 case FAST_ELEMENTS:
4355 case FAST_DOUBLE_ELEMENTS:
4356 break;
4357 case EXTERNAL_PIXEL_ELEMENTS:
4358 case EXTERNAL_BYTE_ELEMENTS:
4359 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4360 case EXTERNAL_SHORT_ELEMENTS:
4361 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4362 case EXTERNAL_INT_ELEMENTS:
4363 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4364 case EXTERNAL_FLOAT_ELEMENTS:
4365 case EXTERNAL_DOUBLE_ELEMENTS:
4366 // Ignore getters and setters on pixel and external array elements.
4367 return GetHeap()->undefined_value();
4368 case DICTIONARY_ELEMENTS:
4369 if (UpdateGetterSetterInDictionary(element_dictionary(),
4370 index,
4371 getter,
4372 setter,
4373 attributes)) {
4374 return GetHeap()->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004375 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004376 break;
4377 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4378 // Ascertain whether we have read-only properties or an existing
4379 // getter/setter pair in an arguments elements dictionary backing
4380 // store.
4381 FixedArray* parameter_map = FixedArray::cast(elements());
4382 uint32_t length = parameter_map->length();
4383 Object* probe =
4384 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
4385 if (probe == NULL || probe->IsTheHole()) {
4386 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4387 if (arguments->IsDictionary()) {
4388 SeededNumberDictionary* dictionary =
4389 SeededNumberDictionary::cast(arguments);
4390 if (UpdateGetterSetterInDictionary(dictionary,
4391 index,
4392 getter,
4393 setter,
4394 attributes)) {
4395 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004396 }
4397 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004398 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004399 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00004400 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004401 }
4402
4403 AccessorPair* accessors;
4404 { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
4405 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4406 }
4407 accessors->SetComponents(getter, setter);
4408
4409 return SetElementCallback(index, accessors, attributes);
4410}
4411
4412
4413MaybeObject* JSObject::DefinePropertyAccessor(String* name,
4414 Object* getter,
4415 Object* setter,
4416 PropertyAttributes attributes) {
4417 // Lookup the name.
4418 LookupResult result(GetHeap()->isolate());
4419 LocalLookupRealNamedProperty(name, &result);
4420 if (result.IsFound()) {
4421 if (result.type() == CALLBACKS) {
4422 ASSERT(!result.IsDontDelete());
4423 Object* obj = result.GetCallbackObject();
4424 // Need to preserve old getters/setters.
4425 if (obj->IsAccessorPair()) {
4426 AccessorPair* copy;
4427 { MaybeObject* maybe_copy =
4428 AccessorPair::cast(obj)->CopyWithoutTransitions();
4429 if (!maybe_copy->To(&copy)) return maybe_copy;
Leon Clarked91b9f72010-01-27 17:25:45 +00004430 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004431 copy->SetComponents(getter, setter);
4432 // Use set to update attributes.
4433 return SetPropertyCallback(name, copy, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00004434 }
4435 }
4436 }
4437
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004438 AccessorPair* accessors;
4439 { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
4440 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
John Reck59135872010-11-02 12:39:01 -07004441 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004442 accessors->SetComponents(getter, setter);
Steve Blocka7e24c12009-10-30 11:49:00 +00004443
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004444 return SetPropertyCallback(name, accessors, attributes);
Leon Clarkef7060e22010-06-03 12:02:55 +01004445}
4446
4447
4448bool JSObject::CanSetCallback(String* name) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004449 ASSERT(!IsAccessCheckNeeded() ||
4450 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
Leon Clarkef7060e22010-06-03 12:02:55 +01004451
4452 // Check if there is an API defined callback object which prohibits
4453 // callback overwriting in this object or it's prototype chain.
4454 // This mechanism is needed for instance in a browser setting, where
4455 // certain accessors such as window.location should not be allowed
4456 // to be overwritten because allowing overwriting could potentially
4457 // cause security problems.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004458 LookupResult callback_result(GetIsolate());
Leon Clarkef7060e22010-06-03 12:02:55 +01004459 LookupCallback(name, &callback_result);
4460 if (callback_result.IsProperty()) {
4461 Object* obj = callback_result.GetCallbackObject();
4462 if (obj->IsAccessorInfo() &&
4463 AccessorInfo::cast(obj)->prohibits_overwriting()) {
4464 return false;
4465 }
4466 }
4467
4468 return true;
4469}
4470
4471
John Reck59135872010-11-02 12:39:01 -07004472MaybeObject* JSObject::SetElementCallback(uint32_t index,
4473 Object* structure,
4474 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004475 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4476
4477 // Normalize elements to make this operation simple.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004478 SeededNumberDictionary* dictionary;
4479 { MaybeObject* maybe_dictionary = NormalizeElements();
4480 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
John Reck59135872010-11-02 12:39:01 -07004481 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004482 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Leon Clarkef7060e22010-06-03 12:02:55 +01004483
4484 // Update the dictionary with the new CALLBACKS property.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004485 { MaybeObject* maybe_dictionary = dictionary->Set(index, structure, details);
4486 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
John Reck59135872010-11-02 12:39:01 -07004487 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004488
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004489 dictionary->set_requires_slow_elements();
4490 // Update the dictionary backing store on the object.
4491 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
4492 // Also delete any parameter alias.
4493 //
4494 // TODO(kmillikin): when deleting the last parameter alias we could
4495 // switch to a direct backing store without the parameter map. This
4496 // would allow GC of the context.
4497 FixedArray* parameter_map = FixedArray::cast(elements());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004498 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004499 parameter_map->set(index + 2, GetHeap()->the_hole_value());
4500 }
4501 parameter_map->set(1, dictionary);
4502 } else {
4503 set_elements(dictionary);
4504 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004505
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004506 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004507}
4508
4509
John Reck59135872010-11-02 12:39:01 -07004510MaybeObject* JSObject::SetPropertyCallback(String* name,
4511 Object* structure,
4512 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01004513 // Normalize object to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07004514 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004515 if (maybe_ok->IsFailure()) return maybe_ok;
John Reck59135872010-11-02 12:39:01 -07004516 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004517
4518 // For the global object allocate a new map to invalidate the global inline
4519 // caches which have a global property cell reference directly in the code.
4520 if (IsGlobalObject()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004521 Map* new_map;
John Reck59135872010-11-02 12:39:01 -07004522 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004523 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07004524 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004525 set_map(new_map);
Ben Murdochb0fe1622011-05-05 13:52:32 +01004526 // When running crankshaft, changing the map is not enough. We
4527 // need to deoptimize all functions that rely on this global
4528 // object.
4529 Deoptimizer::DeoptimizeGlobalObject(this);
Leon Clarkef7060e22010-06-03 12:02:55 +01004530 }
4531
4532 // Update the dictionary with the new CALLBACKS property.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004533 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4534 { MaybeObject* maybe_ok = SetNormalizedProperty(name, structure, details);
4535 if (maybe_ok->IsFailure()) return maybe_ok;
John Reck59135872010-11-02 12:39:01 -07004536 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004537
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004538 return GetHeap()->undefined_value();
4539}
4540
4541
4542void JSObject::DefineAccessor(Handle<JSObject> object,
4543 Handle<String> name,
4544 Handle<Object> getter,
4545 Handle<Object> setter,
4546 PropertyAttributes attributes) {
4547 CALL_HEAP_FUNCTION_VOID(
4548 object->GetIsolate(),
4549 object->DefineAccessor(*name, *getter, *setter, attributes));
Leon Clarkef7060e22010-06-03 12:02:55 +01004550}
4551
John Reck59135872010-11-02 12:39:01 -07004552MaybeObject* JSObject::DefineAccessor(String* name,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004553 Object* getter,
4554 Object* setter,
John Reck59135872010-11-02 12:39:01 -07004555 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01004556 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00004557 // Check access rights if needed.
4558 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004559 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4560 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4561 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004562 }
4563
4564 if (IsJSGlobalProxy()) {
4565 Object* proto = GetPrototype();
4566 if (proto->IsNull()) return this;
4567 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004568 return JSObject::cast(proto)->DefineAccessor(
4569 name, getter, setter, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00004570 }
4571
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004572 // Make sure that the top context does not change when doing callbacks or
4573 // interceptor calls.
4574 AssertNoContextChange ncc;
4575
4576 // Try to flatten before operating on the string.
4577 name->TryFlatten();
4578
4579 if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
4580
4581 uint32_t index = 0;
4582 return name->AsArrayIndex(&index) ?
4583 DefineElementAccessor(index, getter, setter, attributes) :
4584 DefinePropertyAccessor(name, getter, setter, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00004585}
4586
4587
John Reck59135872010-11-02 12:39:01 -07004588MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Steve Block44f0eee2011-05-26 01:26:41 +01004589 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01004590 String* name = String::cast(info->name());
4591 // Check access rights if needed.
4592 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004593 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4594 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4595 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004596 }
4597
4598 if (IsJSGlobalProxy()) {
4599 Object* proto = GetPrototype();
4600 if (proto->IsNull()) return this;
4601 ASSERT(proto->IsJSGlobalObject());
4602 return JSObject::cast(proto)->DefineAccessor(info);
4603 }
4604
4605 // Make sure that the top context does not change when doing callbacks or
4606 // interceptor calls.
4607 AssertNoContextChange ncc;
4608
4609 // Try to flatten before operating on the string.
4610 name->TryFlatten();
4611
4612 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01004613 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004614 }
4615
4616 uint32_t index = 0;
4617 bool is_element = name->AsArrayIndex(&index);
4618
4619 if (is_element) {
Steve Block44f0eee2011-05-26 01:26:41 +01004620 if (IsJSArray()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004621
4622 // Accessors overwrite previous callbacks (cf. with getters/setters).
4623 switch (GetElementsKind()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004624 case FAST_SMI_ONLY_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004625 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004626 case FAST_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004627 break;
Steve Block44f0eee2011-05-26 01:26:41 +01004628 case EXTERNAL_PIXEL_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004629 case EXTERNAL_BYTE_ELEMENTS:
4630 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4631 case EXTERNAL_SHORT_ELEMENTS:
4632 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4633 case EXTERNAL_INT_ELEMENTS:
4634 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4635 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00004636 case EXTERNAL_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01004637 // Ignore getters and setters on pixel and external array
4638 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01004639 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004640 case DICTIONARY_ELEMENTS:
4641 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004642 case NON_STRICT_ARGUMENTS_ELEMENTS:
4643 UNIMPLEMENTED();
Leon Clarkef7060e22010-06-03 12:02:55 +01004644 break;
4645 }
4646
John Reck59135872010-11-02 12:39:01 -07004647 { MaybeObject* maybe_ok =
4648 SetElementCallback(index, info, info->property_attributes());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004649 if (maybe_ok->IsFailure()) return maybe_ok;
John Reck59135872010-11-02 12:39:01 -07004650 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004651 } else {
4652 // Lookup the name.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004653 LookupResult result(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01004654 LocalLookup(name, &result);
4655 // ES5 forbids turning a property into an accessor if it's not
4656 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
4657 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
Steve Block44f0eee2011-05-26 01:26:41 +01004658 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01004659 }
John Reck59135872010-11-02 12:39:01 -07004660 { MaybeObject* maybe_ok =
4661 SetPropertyCallback(name, info, info->property_attributes());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004662 if (maybe_ok->IsFailure()) return maybe_ok;
John Reck59135872010-11-02 12:39:01 -07004663 }
Leon Clarkef7060e22010-06-03 12:02:55 +01004664 }
4665
4666 return this;
4667}
4668
4669
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004670Object* JSObject::LookupAccessor(String* name, AccessorComponent component) {
Steve Block44f0eee2011-05-26 01:26:41 +01004671 Heap* heap = GetHeap();
4672
Steve Blocka7e24c12009-10-30 11:49:00 +00004673 // Make sure that the top context does not change when doing callbacks or
4674 // interceptor calls.
4675 AssertNoContextChange ncc;
4676
4677 // Check access rights if needed.
4678 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01004679 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
4680 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4681 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004682 }
4683
4684 // Make the lookup and include prototypes.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004685 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00004686 if (name->AsArrayIndex(&index)) {
4687 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004688 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004689 obj = JSObject::cast(obj)->GetPrototype()) {
4690 JSObject* js_object = JSObject::cast(obj);
4691 if (js_object->HasDictionaryElements()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00004692 SeededNumberDictionary* dictionary = js_object->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +00004693 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00004694 if (entry != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004695 Object* element = dictionary->ValueAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004696 if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
4697 element->IsAccessorPair()) {
4698 return AccessorPair::cast(element)->GetComponent(component);
Steve Blocka7e24c12009-10-30 11:49:00 +00004699 }
4700 }
4701 }
4702 }
4703 } else {
4704 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004705 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004706 obj = JSObject::cast(obj)->GetPrototype()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004707 LookupResult result(heap->isolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00004708 JSObject::cast(obj)->LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00004709 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004710 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004711 if (result.type() == CALLBACKS) {
4712 Object* obj = result.GetCallbackObject();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004713 if (obj->IsAccessorPair()) {
4714 return AccessorPair::cast(obj)->GetComponent(component);
Steve Blocka7e24c12009-10-30 11:49:00 +00004715 }
4716 }
4717 }
4718 }
4719 }
Steve Block44f0eee2011-05-26 01:26:41 +01004720 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004721}
4722
4723
4724Object* JSObject::SlowReverseLookup(Object* value) {
4725 if (HasFastProperties()) {
4726 DescriptorArray* descs = map()->instance_descriptors();
4727 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4728 if (descs->GetType(i) == FIELD) {
4729 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
4730 return descs->GetKey(i);
4731 }
4732 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
4733 if (descs->GetConstantFunction(i) == value) {
4734 return descs->GetKey(i);
4735 }
4736 }
4737 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01004738 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004739 } else {
4740 return property_dictionary()->SlowReverseLookup(value);
4741 }
4742}
4743
4744
John Reck59135872010-11-02 12:39:01 -07004745MaybeObject* Map::CopyDropDescriptors() {
Steve Block44f0eee2011-05-26 01:26:41 +01004746 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07004747 Object* result;
4748 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004749 heap->AllocateMap(instance_type(), instance_size());
John Reck59135872010-11-02 12:39:01 -07004750 if (!maybe_result->ToObject(&result)) return maybe_result;
4751 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004752 Map::cast(result)->set_prototype(prototype());
4753 Map::cast(result)->set_constructor(constructor());
4754 // Don't copy descriptors, so map transitions always remain a forest.
4755 // If we retained the same descriptors we would have two maps
4756 // pointing to the same transition which is bad because the garbage
4757 // collector relies on being able to reverse pointers from transitions
4758 // to maps. If properties need to be retained use CopyDropTransitions.
Ben Murdoch257744e2011-11-30 15:57:28 +00004759 Map::cast(result)->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00004760 // Please note instance_type and instance_size are set when allocated.
4761 Map::cast(result)->set_inobject_properties(inobject_properties());
4762 Map::cast(result)->set_unused_property_fields(unused_property_fields());
4763
4764 // If the map has pre-allocated properties always start out with a descriptor
4765 // array describing these properties.
4766 if (pre_allocated_property_fields() > 0) {
4767 ASSERT(constructor()->IsJSFunction());
4768 JSFunction* ctor = JSFunction::cast(constructor());
John Reck59135872010-11-02 12:39:01 -07004769 Object* descriptors;
4770 { MaybeObject* maybe_descriptors =
4771 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4772 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4773 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004774 Map::cast(result)->set_instance_descriptors(
4775 DescriptorArray::cast(descriptors));
4776 Map::cast(result)->set_pre_allocated_property_fields(
4777 pre_allocated_property_fields());
4778 }
4779 Map::cast(result)->set_bit_field(bit_field());
4780 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004781 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004782 Map::cast(result)->set_is_shared(false);
Steve Block44f0eee2011-05-26 01:26:41 +01004783 Map::cast(result)->ClearCodeCache(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00004784 return result;
4785}
4786
4787
John Reck59135872010-11-02 12:39:01 -07004788MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4789 NormalizedMapSharingMode sharing) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004790 int new_instance_size = instance_size();
4791 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4792 new_instance_size -= inobject_properties() * kPointerSize;
4793 }
4794
John Reck59135872010-11-02 12:39:01 -07004795 Object* result;
4796 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004797 GetHeap()->AllocateMap(instance_type(), new_instance_size);
John Reck59135872010-11-02 12:39:01 -07004798 if (!maybe_result->ToObject(&result)) return maybe_result;
4799 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004800
4801 if (mode != CLEAR_INOBJECT_PROPERTIES) {
4802 Map::cast(result)->set_inobject_properties(inobject_properties());
4803 }
4804
4805 Map::cast(result)->set_prototype(prototype());
4806 Map::cast(result)->set_constructor(constructor());
4807
4808 Map::cast(result)->set_bit_field(bit_field());
4809 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004810 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004811
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004812 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4813
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004814#ifdef DEBUG
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004815 if (FLAG_verify_heap && Map::cast(result)->is_shared()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004816 Map::cast(result)->SharedMapVerify();
4817 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004818#endif
4819
4820 return result;
4821}
4822
4823
John Reck59135872010-11-02 12:39:01 -07004824MaybeObject* Map::CopyDropTransitions() {
4825 Object* new_map;
4826 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4827 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4828 }
4829 Object* descriptors;
4830 { MaybeObject* maybe_descriptors =
4831 instance_descriptors()->RemoveTransitions();
4832 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4833 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004834 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
Steve Block8defd9f2010-07-08 12:39:36 +01004835 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00004836}
4837
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004838void Map::UpdateCodeCache(Handle<Map> map,
4839 Handle<String> name,
4840 Handle<Code> code) {
4841 Isolate* isolate = map->GetIsolate();
4842 CALL_HEAP_FUNCTION_VOID(isolate,
4843 map->UpdateCodeCache(*name, *code));
4844}
Steve Blocka7e24c12009-10-30 11:49:00 +00004845
John Reck59135872010-11-02 12:39:01 -07004846MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004847 // Allocate the code cache if not present.
4848 if (code_cache()->IsFixedArray()) {
John Reck59135872010-11-02 12:39:01 -07004849 Object* result;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004850 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
John Reck59135872010-11-02 12:39:01 -07004851 if (!maybe_result->ToObject(&result)) return maybe_result;
4852 }
Steve Block6ded16b2010-05-10 14:33:55 +01004853 set_code_cache(result);
4854 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004855
Steve Block6ded16b2010-05-10 14:33:55 +01004856 // Update the code cache.
4857 return CodeCache::cast(code_cache())->Update(name, code);
4858}
4859
4860
4861Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4862 // Do a lookup if a code cache exists.
4863 if (!code_cache()->IsFixedArray()) {
4864 return CodeCache::cast(code_cache())->Lookup(name, flags);
4865 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004866 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004867 }
4868}
4869
4870
4871int Map::IndexInCodeCache(Object* name, Code* code) {
4872 // Get the internal index if a code cache exists.
4873 if (!code_cache()->IsFixedArray()) {
4874 return CodeCache::cast(code_cache())->GetIndex(name, code);
4875 }
4876 return -1;
4877}
4878
4879
4880void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4881 // No GC is supposed to happen between a call to IndexInCodeCache and
4882 // RemoveFromCodeCache so the code cache must be there.
4883 ASSERT(!code_cache()->IsFixedArray());
4884 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4885}
4886
4887
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004888// An iterator over all map transitions in an descriptor array, reusing the map
4889// field of the contens array while it is running.
4890class IntrusiveMapTransitionIterator {
4891 public:
4892 explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array)
4893 : descriptor_array_(descriptor_array) { }
4894
4895 void Start() {
4896 ASSERT(!IsIterating());
4897 if (HasContentArray()) *ContentHeader() = Smi::FromInt(0);
4898 }
4899
4900 bool IsIterating() {
4901 return HasContentArray() && (*ContentHeader())->IsSmi();
4902 }
4903
4904 Map* Next() {
4905 ASSERT(IsIterating());
4906 FixedArray* contents = ContentArray();
4907 // Attention, tricky index manipulation ahead: Every entry in the contents
4908 // array consists of a value/details pair, so the index is typically even.
4909 // An exception is made for CALLBACKS entries: An even index means we look
4910 // at its getter, and an odd index means we look at its setter.
4911 int index = Smi::cast(*ContentHeader())->value();
4912 while (index < contents->length()) {
4913 PropertyDetails details(Smi::cast(contents->get(index | 1)));
4914 switch (details.type()) {
4915 case MAP_TRANSITION:
4916 case CONSTANT_TRANSITION:
4917 case ELEMENTS_TRANSITION:
4918 // We definitely have a map transition.
4919 *ContentHeader() = Smi::FromInt(index + 2);
4920 return static_cast<Map*>(contents->get(index));
4921 case CALLBACKS: {
4922 // We might have a map transition in a getter or in a setter.
4923 AccessorPair* accessors =
4924 static_cast<AccessorPair*>(contents->get(index & ~1));
4925 Object* accessor =
4926 ((index & 1) == 0) ? accessors->getter() : accessors->setter();
4927 index++;
4928 if (accessor->IsMap()) {
4929 *ContentHeader() = Smi::FromInt(index);
4930 return static_cast<Map*>(accessor);
4931 }
Steve Block053d10c2011-06-13 19:13:29 +01004932 break;
4933 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004934 case NORMAL:
4935 case FIELD:
4936 case CONSTANT_FUNCTION:
4937 case HANDLER:
4938 case INTERCEPTOR:
4939 case NULL_DESCRIPTOR:
4940 // We definitely have no map transition.
4941 index += 2;
4942 break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004943 }
4944 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004945 *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map();
4946 return NULL;
4947 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00004948
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004949 private:
4950 bool HasContentArray() {
4951 return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex;
4952 }
4953
4954 FixedArray* ContentArray() {
4955 Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex);
4956 return static_cast<FixedArray*>(array);
4957 }
4958
4959 Object** ContentHeader() {
4960 return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset);
4961 }
4962
4963 DescriptorArray* descriptor_array_;
4964};
4965
4966
4967// An iterator over all prototype transitions, reusing the map field of the
4968// underlying array while it is running.
4969class IntrusivePrototypeTransitionIterator {
4970 public:
4971 explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
4972 : proto_trans_(proto_trans) { }
4973
4974 void Start() {
4975 ASSERT(!IsIterating());
4976 if (HasTransitions()) *Header() = Smi::FromInt(0);
4977 }
4978
4979 bool IsIterating() {
4980 return HasTransitions() && (*Header())->IsSmi();
4981 }
4982
4983 Map* Next() {
4984 ASSERT(IsIterating());
4985 int transitionNumber = Smi::cast(*Header())->value();
4986 if (transitionNumber < NumberOfTransitions()) {
4987 *Header() = Smi::FromInt(transitionNumber + 1);
4988 return GetTransition(transitionNumber);
4989 }
4990 *Header() = proto_trans_->GetHeap()->fixed_array_map();
4991 return NULL;
4992 }
4993
4994 private:
4995 bool HasTransitions() {
4996 return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
4997 }
4998
4999 Object** Header() {
5000 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
5001 }
5002
5003 int NumberOfTransitions() {
5004 Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
5005 return Smi::cast(num)->value();
5006 }
5007
5008 Map* GetTransition(int transitionNumber) {
5009 return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
5010 }
5011
5012 int IndexFor(int transitionNumber) {
5013 return Map::kProtoTransitionHeaderSize +
5014 Map::kProtoTransitionMapOffset +
5015 transitionNumber * Map::kProtoTransitionElementsPerEntry;
5016 }
5017
5018 FixedArray* proto_trans_;
5019};
5020
5021
5022// To traverse the transition tree iteratively, we have to store two kinds of
5023// information in a map: The parent map in the traversal and which children of a
5024// node have already been visited. To do this without additional memory, we
5025// temporarily reuse two maps with known values:
5026//
5027// (1) The map of the map temporarily holds the parent, and is restored to the
5028// meta map afterwards.
5029//
5030// (2) The info which children have already been visited depends on which part
5031// of the map we currently iterate:
5032//
5033// (a) If we currently follow normal map transitions, we temporarily store
5034// the current index in the map of the FixedArray of the desciptor
5035// array's contents, and restore it to the fixed array map afterwards.
5036// Note that a single descriptor can have 0, 1, or 2 transitions.
5037//
5038// (b) If we currently follow prototype transitions, we temporarily store
5039// the current index in the map of the FixedArray holding the prototype
5040// transitions, and restore it to the fixed array map afterwards.
5041//
5042// Note that the child iterator is just a concatenation of two iterators: One
5043// iterating over map transitions and one iterating over prototype transisitons.
5044class TraversableMap : public Map {
5045 public:
5046 // Record the parent in the traversal within this map. Note that this destroys
5047 // this map's map!
5048 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
5049
5050 // Reset the current map's map, returning the parent previously stored in it.
5051 TraversableMap* GetAndResetParent() {
5052 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
5053 set_map_no_write_barrier(GetHeap()->meta_map());
5054 return old_parent;
5055 }
5056
5057 // Start iterating over this map's children, possibly destroying a FixedArray
5058 // map (see explanation above).
5059 void ChildIteratorStart() {
5060 IntrusiveMapTransitionIterator(instance_descriptors()).Start();
5061 IntrusivePrototypeTransitionIterator(
5062 unchecked_prototype_transitions()).Start();
5063 }
5064
5065 // If we have an unvisited child map, return that one and advance. If we have
5066 // none, return NULL and reset any destroyed FixedArray maps.
5067 TraversableMap* ChildIteratorNext() {
5068 IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors());
5069 if (descriptor_iterator.IsIterating()) {
5070 Map* next = descriptor_iterator.Next();
5071 if (next != NULL) return static_cast<TraversableMap*>(next);
5072 }
5073 IntrusivePrototypeTransitionIterator
5074 proto_iterator(unchecked_prototype_transitions());
5075 if (proto_iterator.IsIterating()) {
5076 Map* next = proto_iterator.Next();
5077 if (next != NULL) return static_cast<TraversableMap*>(next);
5078 }
5079 return NULL;
5080 }
5081};
5082
5083
5084// Traverse the transition tree in postorder without using the C++ stack by
5085// doing pointer reversal.
5086void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
5087 TraversableMap* current = static_cast<TraversableMap*>(this);
5088 current->ChildIteratorStart();
5089 while (true) {
5090 TraversableMap* child = current->ChildIteratorNext();
5091 if (child != NULL) {
5092 child->ChildIteratorStart();
5093 child->SetParent(current);
5094 current = child;
5095 } else {
5096 TraversableMap* parent = current->GetAndResetParent();
5097 callback(current, data);
5098 if (current == this) break;
5099 current = parent;
5100 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005101 }
5102}
5103
5104
John Reck59135872010-11-02 12:39:01 -07005105MaybeObject* CodeCache::Update(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01005106 // The number of monomorphic stubs for normal load/store/call IC's can grow to
5107 // a large number and therefore they need to go into a hash table. They are
5108 // used to load global properties from cells.
5109 if (code->type() == NORMAL) {
5110 // Make sure that a hash table is allocated for the normal load code cache.
5111 if (normal_type_cache()->IsUndefined()) {
John Reck59135872010-11-02 12:39:01 -07005112 Object* result;
5113 { MaybeObject* maybe_result =
5114 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
5115 if (!maybe_result->ToObject(&result)) return maybe_result;
5116 }
Steve Block6ded16b2010-05-10 14:33:55 +01005117 set_normal_type_cache(result);
5118 }
5119 return UpdateNormalTypeCache(name, code);
5120 } else {
5121 ASSERT(default_cache()->IsFixedArray());
5122 return UpdateDefaultCache(name, code);
5123 }
5124}
5125
5126
John Reck59135872010-11-02 12:39:01 -07005127MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01005128 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00005129 // flags. This allows call constant stubs to overwrite call field
5130 // stubs, etc.
5131 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
5132
5133 // First check whether we can update existing code cache without
5134 // extending it.
Steve Block6ded16b2010-05-10 14:33:55 +01005135 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005136 int length = cache->length();
5137 int deleted_index = -1;
Steve Block6ded16b2010-05-10 14:33:55 +01005138 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005139 Object* key = cache->get(i);
5140 if (key->IsNull()) {
5141 if (deleted_index < 0) deleted_index = i;
5142 continue;
5143 }
5144 if (key->IsUndefined()) {
5145 if (deleted_index >= 0) i = deleted_index;
Steve Block6ded16b2010-05-10 14:33:55 +01005146 cache->set(i + kCodeCacheEntryNameOffset, name);
5147 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00005148 return this;
5149 }
5150 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01005151 Code::Flags found =
5152 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
Steve Blocka7e24c12009-10-30 11:49:00 +00005153 if (Code::RemoveTypeFromFlags(found) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01005154 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00005155 return this;
5156 }
5157 }
5158 }
5159
5160 // Reached the end of the code cache. If there were deleted
5161 // elements, reuse the space for the first of them.
5162 if (deleted_index >= 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01005163 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
5164 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00005165 return this;
5166 }
5167
Steve Block6ded16b2010-05-10 14:33:55 +01005168 // Extend the code cache with some new entries (at least one). Must be a
5169 // multiple of the entry size.
5170 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
5171 new_length = new_length - new_length % kCodeCacheEntrySize;
5172 ASSERT((new_length % kCodeCacheEntrySize) == 0);
John Reck59135872010-11-02 12:39:01 -07005173 Object* result;
5174 { MaybeObject* maybe_result = cache->CopySize(new_length);
5175 if (!maybe_result->ToObject(&result)) return maybe_result;
5176 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005177
5178 // Add the (name, code) pair to the new cache.
5179 cache = FixedArray::cast(result);
Steve Block6ded16b2010-05-10 14:33:55 +01005180 cache->set(length + kCodeCacheEntryNameOffset, name);
5181 cache->set(length + kCodeCacheEntryCodeOffset, code);
5182 set_default_cache(cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00005183 return this;
5184}
5185
5186
John Reck59135872010-11-02 12:39:01 -07005187MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01005188 // Adding a new entry can cause a new cache to be allocated.
5189 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
John Reck59135872010-11-02 12:39:01 -07005190 Object* new_cache;
5191 { MaybeObject* maybe_new_cache = cache->Put(name, code);
5192 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5193 }
Steve Block6ded16b2010-05-10 14:33:55 +01005194 set_normal_type_cache(new_cache);
5195 return this;
5196}
5197
5198
5199Object* CodeCache::Lookup(String* name, Code::Flags flags) {
5200 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
5201 return LookupNormalTypeCache(name, flags);
5202 } else {
5203 return LookupDefaultCache(name, flags);
5204 }
5205}
5206
5207
5208Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
5209 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005210 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01005211 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
5212 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00005213 // Skip deleted elements.
5214 if (key->IsNull()) continue;
5215 if (key->IsUndefined()) return key;
5216 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01005217 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
5218 if (code->flags() == flags) {
5219 return code;
5220 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005221 }
5222 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01005223 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00005224}
5225
5226
Steve Block6ded16b2010-05-10 14:33:55 +01005227Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
5228 if (!normal_type_cache()->IsUndefined()) {
5229 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5230 return cache->Lookup(name, flags);
5231 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005232 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005233 }
5234}
5235
5236
5237int CodeCache::GetIndex(Object* name, Code* code) {
5238 if (code->type() == NORMAL) {
5239 if (normal_type_cache()->IsUndefined()) return -1;
5240 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5241 return cache->GetIndex(String::cast(name), code->flags());
5242 }
5243
5244 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005245 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01005246 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
5247 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00005248 }
5249 return -1;
5250}
5251
5252
Steve Block6ded16b2010-05-10 14:33:55 +01005253void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
5254 if (code->type() == NORMAL) {
5255 ASSERT(!normal_type_cache()->IsUndefined());
5256 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5257 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
5258 cache->RemoveByIndex(index);
5259 } else {
5260 FixedArray* array = default_cache();
5261 ASSERT(array->length() >= index && array->get(index)->IsCode());
5262 // Use null instead of undefined for deleted elements to distinguish
5263 // deleted elements from unused elements. This distinction is used
5264 // when looking up in the cache and when updating the cache.
5265 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
5266 array->set_null(index - 1); // Name.
5267 array->set_null(index); // Code.
5268 }
5269}
5270
5271
5272// The key in the code cache hash table consists of the property name and the
5273// code object. The actual match is on the name and the code flags. If a key
5274// is created using the flags and not a code object it can only be used for
5275// lookup not to create a new entry.
5276class CodeCacheHashTableKey : public HashTableKey {
5277 public:
5278 CodeCacheHashTableKey(String* name, Code::Flags flags)
5279 : name_(name), flags_(flags), code_(NULL) { }
5280
5281 CodeCacheHashTableKey(String* name, Code* code)
5282 : name_(name),
5283 flags_(code->flags()),
5284 code_(code) { }
5285
5286
5287 bool IsMatch(Object* other) {
5288 if (!other->IsFixedArray()) return false;
5289 FixedArray* pair = FixedArray::cast(other);
5290 String* name = String::cast(pair->get(0));
5291 Code::Flags flags = Code::cast(pair->get(1))->flags();
5292 if (flags != flags_) {
5293 return false;
5294 }
5295 return name_->Equals(name);
5296 }
5297
5298 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
5299 return name->Hash() ^ flags;
5300 }
5301
5302 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
5303
5304 uint32_t HashForObject(Object* obj) {
5305 FixedArray* pair = FixedArray::cast(obj);
5306 String* name = String::cast(pair->get(0));
5307 Code* code = Code::cast(pair->get(1));
5308 return NameFlagsHashHelper(name, code->flags());
5309 }
5310
John Reck59135872010-11-02 12:39:01 -07005311 MUST_USE_RESULT MaybeObject* AsObject() {
Steve Block6ded16b2010-05-10 14:33:55 +01005312 ASSERT(code_ != NULL);
John Reck59135872010-11-02 12:39:01 -07005313 Object* obj;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005314 { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07005315 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5316 }
Steve Block6ded16b2010-05-10 14:33:55 +01005317 FixedArray* pair = FixedArray::cast(obj);
5318 pair->set(0, name_);
5319 pair->set(1, code_);
5320 return pair;
5321 }
5322
5323 private:
5324 String* name_;
5325 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005326 // TODO(jkummerow): We should be able to get by without this.
Steve Block6ded16b2010-05-10 14:33:55 +01005327 Code* code_;
5328};
5329
5330
5331Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
5332 CodeCacheHashTableKey key(name, flags);
5333 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01005334 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01005335 return get(EntryToIndex(entry) + 1);
5336}
5337
5338
John Reck59135872010-11-02 12:39:01 -07005339MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01005340 CodeCacheHashTableKey key(name, code);
John Reck59135872010-11-02 12:39:01 -07005341 Object* obj;
5342 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5343 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5344 }
Steve Block6ded16b2010-05-10 14:33:55 +01005345
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005346 // Don't use |this|, as the table might have grown.
Steve Block6ded16b2010-05-10 14:33:55 +01005347 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
5348
5349 int entry = cache->FindInsertionEntry(key.Hash());
John Reck59135872010-11-02 12:39:01 -07005350 Object* k;
5351 { MaybeObject* maybe_k = key.AsObject();
5352 if (!maybe_k->ToObject(&k)) return maybe_k;
5353 }
Steve Block6ded16b2010-05-10 14:33:55 +01005354
5355 cache->set(EntryToIndex(entry), k);
5356 cache->set(EntryToIndex(entry) + 1, code);
5357 cache->ElementAdded();
5358 return cache;
5359}
5360
5361
5362int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
5363 CodeCacheHashTableKey key(name, flags);
5364 int entry = FindEntry(&key);
5365 return (entry == kNotFound) ? -1 : entry;
5366}
5367
5368
5369void CodeCacheHashTable::RemoveByIndex(int index) {
5370 ASSERT(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01005371 Heap* heap = GetHeap();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005372 set(EntryToIndex(index), heap->the_hole_value());
5373 set(EntryToIndex(index) + 1, heap->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01005374 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00005375}
5376
5377
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005378void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
5379 MapHandleList* maps,
5380 Code::Flags flags,
5381 Handle<Code> code) {
5382 Isolate* isolate = cache->GetIsolate();
5383 CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
5384}
5385
5386
5387MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005388 Code::Flags flags,
5389 Code* code) {
5390 // Initialize cache if necessary.
5391 if (cache()->IsUndefined()) {
5392 Object* result;
5393 { MaybeObject* maybe_result =
5394 PolymorphicCodeCacheHashTable::Allocate(
5395 PolymorphicCodeCacheHashTable::kInitialSize);
5396 if (!maybe_result->ToObject(&result)) return maybe_result;
5397 }
5398 set_cache(result);
5399 } else {
5400 // This entry shouldn't be contained in the cache yet.
5401 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
5402 ->Lookup(maps, flags)->IsUndefined());
5403 }
5404 PolymorphicCodeCacheHashTable* hash_table =
5405 PolymorphicCodeCacheHashTable::cast(cache());
5406 Object* new_cache;
5407 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
5408 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5409 }
5410 set_cache(new_cache);
5411 return this;
5412}
5413
5414
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005415Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
5416 Code::Flags flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005417 if (!cache()->IsUndefined()) {
5418 PolymorphicCodeCacheHashTable* hash_table =
5419 PolymorphicCodeCacheHashTable::cast(cache());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005420 return Handle<Object>(hash_table->Lookup(maps, flags));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005421 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005422 return GetIsolate()->factory()->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005423 }
5424}
5425
5426
5427// Despite their name, object of this class are not stored in the actual
5428// hash table; instead they're temporarily used for lookups. It is therefore
5429// safe to have a weak (non-owning) pointer to a MapList as a member field.
5430class PolymorphicCodeCacheHashTableKey : public HashTableKey {
5431 public:
5432 // Callers must ensure that |maps| outlives the newly constructed object.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005433 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005434 : maps_(maps),
5435 code_flags_(code_flags) {}
5436
5437 bool IsMatch(Object* other) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005438 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005439 int other_flags;
5440 FromObject(other, &other_flags, &other_maps);
5441 if (code_flags_ != other_flags) return false;
5442 if (maps_->length() != other_maps.length()) return false;
5443 // Compare just the hashes first because it's faster.
5444 int this_hash = MapsHashHelper(maps_, code_flags_);
5445 int other_hash = MapsHashHelper(&other_maps, other_flags);
5446 if (this_hash != other_hash) return false;
5447
5448 // Full comparison: for each map in maps_, look for an equivalent map in
5449 // other_maps. This implementation is slow, but probably good enough for
5450 // now because the lists are short (<= 4 elements currently).
5451 for (int i = 0; i < maps_->length(); ++i) {
5452 bool match_found = false;
5453 for (int j = 0; j < other_maps.length(); ++j) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005454 if (*(maps_->at(i)) == *(other_maps.at(j))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005455 match_found = true;
5456 break;
5457 }
5458 }
5459 if (!match_found) return false;
5460 }
5461 return true;
5462 }
5463
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005464 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005465 uint32_t hash = code_flags;
5466 for (int i = 0; i < maps->length(); ++i) {
5467 hash ^= maps->at(i)->Hash();
5468 }
5469 return hash;
5470 }
5471
5472 uint32_t Hash() {
5473 return MapsHashHelper(maps_, code_flags_);
5474 }
5475
5476 uint32_t HashForObject(Object* obj) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005477 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005478 int other_flags;
5479 FromObject(obj, &other_flags, &other_maps);
5480 return MapsHashHelper(&other_maps, other_flags);
5481 }
5482
5483 MUST_USE_RESULT MaybeObject* AsObject() {
5484 Object* obj;
5485 // The maps in |maps_| must be copied to a newly allocated FixedArray,
5486 // both because the referenced MapList is short-lived, and because C++
5487 // objects can't be stored in the heap anyway.
5488 { MaybeObject* maybe_obj =
5489 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
5490 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5491 }
5492 FixedArray* list = FixedArray::cast(obj);
5493 list->set(0, Smi::FromInt(code_flags_));
5494 for (int i = 0; i < maps_->length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005495 list->set(i + 1, *maps_->at(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005496 }
5497 return list;
5498 }
5499
5500 private:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005501 static MapHandleList* FromObject(Object* obj,
5502 int* code_flags,
5503 MapHandleList* maps) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005504 FixedArray* list = FixedArray::cast(obj);
5505 maps->Rewind(0);
5506 *code_flags = Smi::cast(list->get(0))->value();
5507 for (int i = 1; i < list->length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005508 maps->Add(Handle<Map>(Map::cast(list->get(i))));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005509 }
5510 return maps;
5511 }
5512
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005513 MapHandleList* maps_; // weak.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005514 int code_flags_;
5515 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
5516};
5517
5518
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005519Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
5520 int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005521 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5522 int entry = FindEntry(&key);
5523 if (entry == kNotFound) return GetHeap()->undefined_value();
5524 return get(EntryToIndex(entry) + 1);
5525}
5526
5527
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005528MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005529 int code_flags,
5530 Code* code) {
5531 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5532 Object* obj;
5533 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5534 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5535 }
5536 PolymorphicCodeCacheHashTable* cache =
5537 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
5538 int entry = cache->FindInsertionEntry(key.Hash());
5539 { MaybeObject* maybe_obj = key.AsObject();
5540 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5541 }
5542 cache->set(EntryToIndex(entry), obj);
5543 cache->set(EntryToIndex(entry) + 1, code);
5544 cache->ElementAdded();
5545 return cache;
5546}
5547
5548
John Reck59135872010-11-02 12:39:01 -07005549MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005550 ElementsAccessor* accessor = array->GetElementsAccessor();
5551 MaybeObject* maybe_result =
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005552 accessor->AddElementsToFixedArray(array, array, this);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005553 FixedArray* result;
5554 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
5555#ifdef DEBUG
5556 if (FLAG_enable_slow_asserts) {
5557 for (int i = 0; i < result->length(); i++) {
5558 Object* current = result->get(i);
5559 ASSERT(current->IsNumber() || current->IsString());
Steve Blocka7e24c12009-10-30 11:49:00 +00005560 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005561 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005562#endif
5563 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00005564}
5565
5566
John Reck59135872010-11-02 12:39:01 -07005567MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005568 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
5569 MaybeObject* maybe_result =
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005570 accessor->AddElementsToFixedArray(NULL, NULL, this, other);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005571 FixedArray* result;
5572 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
Ben Murdochf87a2032010-10-22 12:50:53 +01005573#ifdef DEBUG
5574 if (FLAG_enable_slow_asserts) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005575 for (int i = 0; i < result->length(); i++) {
5576 Object* current = result->get(i);
5577 ASSERT(current->IsNumber() || current->IsString());
Ben Murdochf87a2032010-10-22 12:50:53 +01005578 }
5579 }
5580#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00005581 return result;
5582}
5583
5584
John Reck59135872010-11-02 12:39:01 -07005585MaybeObject* FixedArray::CopySize(int new_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01005586 Heap* heap = GetHeap();
5587 if (new_length == 0) return heap->empty_fixed_array();
John Reck59135872010-11-02 12:39:01 -07005588 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01005589 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
John Reck59135872010-11-02 12:39:01 -07005590 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5591 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005592 FixedArray* result = FixedArray::cast(obj);
5593 // Copy the content
Leon Clarke4515c472010-02-03 11:58:03 +00005594 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00005595 int len = length();
5596 if (new_length < len) len = new_length;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005597 // We are taking the map from the old fixed array so the map is sure to
5598 // be an immortal immutable object.
5599 result->set_map_no_write_barrier(map());
Leon Clarke4515c472010-02-03 11:58:03 +00005600 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00005601 for (int i = 0; i < len; i++) {
5602 result->set(i, get(i), mode);
5603 }
5604 return result;
5605}
5606
5607
5608void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Leon Clarke4515c472010-02-03 11:58:03 +00005609 AssertNoAllocation no_gc;
5610 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00005611 for (int index = 0; index < len; index++) {
5612 dest->set(dest_pos+index, get(pos+index), mode);
5613 }
5614}
5615
5616
5617#ifdef DEBUG
5618bool FixedArray::IsEqualTo(FixedArray* other) {
5619 if (length() != other->length()) return false;
5620 for (int i = 0 ; i < length(); ++i) {
5621 if (get(i) != other->get(i)) return false;
5622 }
5623 return true;
5624}
5625#endif
5626
5627
John Reck59135872010-11-02 12:39:01 -07005628MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01005629 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005630 if (number_of_descriptors == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01005631 return heap->empty_descriptor_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00005632 }
5633 // Allocate the array of keys.
John Reck59135872010-11-02 12:39:01 -07005634 Object* array;
5635 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01005636 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
John Reck59135872010-11-02 12:39:01 -07005637 if (!maybe_array->ToObject(&array)) return maybe_array;
5638 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005639 // Do not use DescriptorArray::cast on incomplete object.
5640 FixedArray* result = FixedArray::cast(array);
5641
5642 // Allocate the content array and set it in the descriptor array.
John Reck59135872010-11-02 12:39:01 -07005643 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01005644 heap->AllocateFixedArray(number_of_descriptors << 1);
John Reck59135872010-11-02 12:39:01 -07005645 if (!maybe_array->ToObject(&array)) return maybe_array;
5646 }
Ben Murdoch257744e2011-11-30 15:57:28 +00005647 result->set(kBitField3StorageIndex, Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00005648 result->set(kContentArrayIndex, array);
5649 result->set(kEnumerationIndexIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00005650 Smi::FromInt(PropertyDetails::kInitialIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00005651 return result;
5652}
5653
5654
5655void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005656 FixedArray* new_cache,
5657 Object* new_index_cache) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005658 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005659 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
Steve Blocka7e24c12009-10-30 11:49:00 +00005660 if (HasEnumCache()) {
5661 FixedArray::cast(get(kEnumerationIndexIndex))->
5662 set(kEnumCacheBridgeCacheIndex, new_cache);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005663 FixedArray::cast(get(kEnumerationIndexIndex))->
5664 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00005665 } else {
5666 if (IsEmpty()) return; // Do nothing for empty descriptor array.
5667 FixedArray::cast(bridge_storage)->
5668 set(kEnumCacheBridgeCacheIndex, new_cache);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005669 FixedArray::cast(bridge_storage)->
5670 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
5671 NoWriteBarrierSet(FixedArray::cast(bridge_storage),
5672 kEnumCacheBridgeEnumIndex,
5673 get(kEnumerationIndexIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00005674 set(kEnumerationIndexIndex, bridge_storage);
5675 }
5676}
5677
5678
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005679static bool InsertionPointFound(String* key1, String* key2) {
5680 return key1->Hash() > key2->Hash() || key1 == key2;
5681}
5682
5683
5684void DescriptorArray::CopyFrom(Handle<DescriptorArray> dst,
5685 int dst_index,
5686 Handle<DescriptorArray> src,
5687 int src_index,
5688 const WhitenessWitness& witness) {
5689 CALL_HEAP_FUNCTION_VOID(dst->GetIsolate(),
5690 dst->CopyFrom(dst_index, *src, src_index, witness));
5691}
5692
5693
5694MaybeObject* DescriptorArray::CopyFrom(int dst_index,
5695 DescriptorArray* src,
5696 int src_index,
5697 const WhitenessWitness& witness) {
5698 Object* value = src->GetValue(src_index);
5699 PropertyDetails details(src->GetDetails(src_index));
5700 if (details.type() == CALLBACKS && value->IsAccessorPair()) {
5701 MaybeObject* maybe_copy =
5702 AccessorPair::cast(value)->CopyWithoutTransitions();
5703 if (!maybe_copy->To(&value)) return maybe_copy;
5704 }
5705 Descriptor desc(src->GetKey(src_index), value, details);
5706 Set(dst_index, &desc, witness);
5707 return this;
5708}
5709
5710
John Reck59135872010-11-02 12:39:01 -07005711MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
5712 TransitionFlag transition_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005713 // Transitions are only kept when inserting another transition.
5714 // This precondition is not required by this function's implementation, but
5715 // is currently required by the semantics of maps, so we check it.
5716 // Conversely, we filter after replacing, so replacing a transition and
5717 // removing all other transitions is not supported.
5718 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005719 ASSERT(remove_transitions == !descriptor->ContainsTransition());
Steve Blocka7e24c12009-10-30 11:49:00 +00005720 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
5721
5722 // Ensure the key is a symbol.
John Reck59135872010-11-02 12:39:01 -07005723 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005724 if (maybe_result->IsFailure()) return maybe_result;
John Reck59135872010-11-02 12:39:01 -07005725 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005726
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005727 int new_size = 0;
5728 for (int i = 0; i < number_of_descriptors(); i++) {
5729 if (IsNullDescriptor(i)) continue;
5730 if (remove_transitions && IsTransitionOnly(i)) continue;
5731 new_size++;
Steve Blocka7e24c12009-10-30 11:49:00 +00005732 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005733
5734 // If key is in descriptor, we replace it in-place when filtering.
5735 // Count a null descriptor for key as inserted, not replaced.
5736 int index = Search(descriptor->GetKey());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005737 const bool replacing = (index != kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +00005738 bool keep_enumeration_index = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00005739 if (replacing) {
5740 // We are replacing an existing descriptor. We keep the enumeration
5741 // index of a visible property.
5742 PropertyType t = PropertyDetails(GetDetails(index)).type();
5743 if (t == CONSTANT_FUNCTION ||
5744 t == FIELD ||
5745 t == CALLBACKS ||
5746 t == INTERCEPTOR) {
5747 keep_enumeration_index = true;
5748 } else if (remove_transitions) {
5749 // Replaced descriptor has been counted as removed if it is
5750 // a transition that will be replaced. Adjust count in this case.
5751 ++new_size;
5752 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005753 } else {
5754 ++new_size;
Steve Blocka7e24c12009-10-30 11:49:00 +00005755 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005756
5757 DescriptorArray* new_descriptors;
John Reck59135872010-11-02 12:39:01 -07005758 { MaybeObject* maybe_result = Allocate(new_size);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005759 if (!maybe_result->To(&new_descriptors)) return maybe_result;
John Reck59135872010-11-02 12:39:01 -07005760 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005761
5762 DescriptorArray::WhitenessWitness witness(new_descriptors);
5763
Steve Blocka7e24c12009-10-30 11:49:00 +00005764 // Set the enumeration index in the descriptors and set the enumeration index
5765 // in the result.
5766 int enumeration_index = NextEnumerationIndex();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005767 if (!descriptor->ContainsTransition()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005768 if (keep_enumeration_index) {
5769 descriptor->SetEnumerationIndex(
5770 PropertyDetails(GetDetails(index)).index());
5771 } else {
5772 descriptor->SetEnumerationIndex(enumeration_index);
5773 ++enumeration_index;
5774 }
5775 }
5776 new_descriptors->SetNextEnumerationIndex(enumeration_index);
5777
5778 // Copy the descriptors, filtering out transitions and null descriptors,
5779 // and inserting or replacing a descriptor.
Ben Murdoch85b71792012-04-11 18:30:58 +01005780 int to_index = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005781 int insertion_index = -1;
5782 int from_index = 0;
5783 while (from_index < number_of_descriptors()) {
5784 if (insertion_index < 0 &&
5785 InsertionPointFound(GetKey(from_index), descriptor->GetKey())) {
5786 insertion_index = to_index++;
5787 if (replacing) from_index++;
5788 } else {
5789 if (!(IsNullDescriptor(from_index) ||
5790 (remove_transitions && IsTransitionOnly(from_index)))) {
5791 MaybeObject* copy_result =
5792 new_descriptors->CopyFrom(to_index++, this, from_index, witness);
5793 if (copy_result->IsFailure()) return copy_result;
5794 }
5795 from_index++;
Steve Blocka7e24c12009-10-30 11:49:00 +00005796 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005797 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005798 if (insertion_index < 0) insertion_index = to_index++;
5799 new_descriptors->Set(insertion_index, descriptor, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +00005800
5801 ASSERT(to_index == new_descriptors->number_of_descriptors());
5802 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
5803
5804 return new_descriptors;
5805}
5806
5807
John Reck59135872010-11-02 12:39:01 -07005808MaybeObject* DescriptorArray::RemoveTransitions() {
Ben Murdoch85b71792012-04-11 18:30:58 +01005809 // Allocate the new descriptor array.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005810 int new_number_of_descriptors = 0;
5811 for (int i = 0; i < number_of_descriptors(); i++) {
5812 if (IsProperty(i)) new_number_of_descriptors++;
Ben Murdoch85b71792012-04-11 18:30:58 +01005813 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005814 DescriptorArray* new_descriptors;
5815 { MaybeObject* maybe_result = Allocate(new_number_of_descriptors);
5816 if (!maybe_result->To(&new_descriptors)) return maybe_result;
5817 }
Ben Murdoch85b71792012-04-11 18:30:58 +01005818
Steve Blocka7e24c12009-10-30 11:49:00 +00005819 // Copy the content.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005820 DescriptorArray::WhitenessWitness witness(new_descriptors);
Steve Blocka7e24c12009-10-30 11:49:00 +00005821 int next_descriptor = 0;
5822 for (int i = 0; i < number_of_descriptors(); i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005823 if (IsProperty(i)) {
5824 MaybeObject* copy_result =
5825 new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
5826 if (copy_result->IsFailure()) return copy_result;
5827 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005828 }
5829 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
5830
5831 return new_descriptors;
5832}
5833
5834
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005835void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005836 // In-place heap sort.
5837 int len = number_of_descriptors();
5838
5839 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01005840 // Index of the last node with children
5841 const int max_parent_index = (len / 2) - 1;
5842 for (int i = max_parent_index; i >= 0; --i) {
5843 int parent_index = i;
5844 const uint32_t parent_hash = GetKey(i)->Hash();
5845 while (parent_index <= max_parent_index) {
5846 int child_index = 2 * parent_index + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00005847 uint32_t child_hash = GetKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01005848 if (child_index + 1 < len) {
5849 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5850 if (right_child_hash > child_hash) {
5851 child_index++;
5852 child_hash = right_child_hash;
5853 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005854 }
Steve Block6ded16b2010-05-10 14:33:55 +01005855 if (child_hash <= parent_hash) break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005856 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01005857 // Now element at child_index could be < its children.
5858 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00005859 }
5860 }
5861
5862 // Extract elements and create sorted array.
5863 for (int i = len - 1; i > 0; --i) {
5864 // Put max element at the back of the array.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005865 NoIncrementalWriteBarrierSwapDescriptors(0, i);
5866 // Shift down the new top element.
Steve Blocka7e24c12009-10-30 11:49:00 +00005867 int parent_index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01005868 const uint32_t parent_hash = GetKey(parent_index)->Hash();
5869 const int max_parent_index = (i / 2) - 1;
5870 while (parent_index <= max_parent_index) {
5871 int child_index = parent_index * 2 + 1;
5872 uint32_t child_hash = GetKey(child_index)->Hash();
5873 if (child_index + 1 < i) {
5874 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5875 if (right_child_hash > child_hash) {
5876 child_index++;
5877 child_hash = right_child_hash;
5878 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005879 }
Steve Block6ded16b2010-05-10 14:33:55 +01005880 if (child_hash <= parent_hash) break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005881 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01005882 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00005883 }
5884 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005885}
Steve Blocka7e24c12009-10-30 11:49:00 +00005886
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005887
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005888void DescriptorArray::Sort(const WhitenessWitness& witness) {
5889 SortUnchecked(witness);
Steve Blocka7e24c12009-10-30 11:49:00 +00005890 SLOW_ASSERT(IsSortedNoDuplicates());
5891}
5892
5893
5894int DescriptorArray::BinarySearch(String* name, int low, int high) {
5895 uint32_t hash = name->Hash();
5896
5897 while (low <= high) {
5898 int mid = (low + high) / 2;
5899 String* mid_name = GetKey(mid);
5900 uint32_t mid_hash = mid_name->Hash();
5901
5902 if (mid_hash > hash) {
5903 high = mid - 1;
5904 continue;
5905 }
5906 if (mid_hash < hash) {
5907 low = mid + 1;
5908 continue;
5909 }
5910 // Found an element with the same hash-code.
5911 ASSERT(hash == mid_hash);
5912 // There might be more, so we find the first one and
5913 // check them all to see if we have a match.
5914 if (name == mid_name && !is_null_descriptor(mid)) return mid;
5915 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
5916 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
5917 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
5918 }
5919 break;
5920 }
5921 return kNotFound;
5922}
5923
5924
5925int DescriptorArray::LinearSearch(String* name, int len) {
5926 uint32_t hash = name->Hash();
5927 for (int number = 0; number < len; number++) {
5928 String* entry = GetKey(number);
5929 if ((entry->Hash() == hash) &&
5930 name->Equals(entry) &&
5931 !is_null_descriptor(number)) {
5932 return number;
5933 }
5934 }
5935 return kNotFound;
5936}
5937
5938
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005939MaybeObject* AccessorPair::CopyWithoutTransitions() {
5940 Heap* heap = GetHeap();
5941 AccessorPair* copy;
5942 { MaybeObject* maybe_copy = heap->AllocateAccessorPair();
5943 if (!maybe_copy->To(&copy)) return maybe_copy;
5944 }
5945 copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter());
5946 copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter());
5947 return copy;
5948}
5949
5950
5951Object* AccessorPair::GetComponent(AccessorComponent component) {
5952 Object* accessor = (component == ACCESSOR_GETTER) ? getter() : setter();
5953 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
5954}
5955
5956
Ben Murdochb0fe1622011-05-05 13:52:32 +01005957MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5958 PretenureFlag pretenure) {
5959 ASSERT(deopt_entry_count > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01005960 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005961 pretenure);
5962}
5963
5964
5965MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5966 PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01005967 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5968 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005969 pretenure);
5970}
5971
5972
Steve Blocka7e24c12009-10-30 11:49:00 +00005973#ifdef DEBUG
5974bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5975 if (IsEmpty()) return other->IsEmpty();
5976 if (other->IsEmpty()) return false;
5977 if (length() != other->length()) return false;
5978 for (int i = 0; i < length(); ++i) {
5979 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5980 }
5981 return GetContentArray()->IsEqualTo(other->GetContentArray());
5982}
5983#endif
5984
5985
Steve Blocka7e24c12009-10-30 11:49:00 +00005986bool String::LooksValid() {
Steve Block44f0eee2011-05-26 01:26:41 +01005987 if (!Isolate::Current()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00005988 return true;
5989}
5990
5991
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005992String::FlatContent String::GetFlatContent() {
Steve Blocka7e24c12009-10-30 11:49:00 +00005993 int length = this->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005994 StringShape shape(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00005995 String* string = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00005996 int offset = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005997 if (shape.representation_tag() == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005998 ConsString* cons = ConsString::cast(string);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005999 if (cons->second()->length() != 0) {
6000 return FlatContent();
6001 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006002 string = cons->first();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006003 shape = StringShape(string);
Steve Blocka7e24c12009-10-30 11:49:00 +00006004 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006005 if (shape.representation_tag() == kSlicedStringTag) {
6006 SlicedString* slice = SlicedString::cast(string);
6007 offset = slice->offset();
6008 string = slice->parent();
6009 shape = StringShape(string);
6010 ASSERT(shape.representation_tag() != kConsStringTag &&
6011 shape.representation_tag() != kSlicedStringTag);
Steve Blocka7e24c12009-10-30 11:49:00 +00006012 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006013 if (shape.encoding_tag() == kAsciiStringTag) {
6014 const char* start;
6015 if (shape.representation_tag() == kSeqStringTag) {
6016 start = SeqAsciiString::cast(string)->GetChars();
6017 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006018 start = ExternalAsciiString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006019 }
6020 return FlatContent(Vector<const char>(start + offset, length));
6021 } else {
6022 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
6023 const uc16* start;
6024 if (shape.representation_tag() == kSeqStringTag) {
6025 start = SeqTwoByteString::cast(string)->GetChars();
6026 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006027 start = ExternalTwoByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006028 }
6029 return FlatContent(Vector<const uc16>(start + offset, length));
6030 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006031}
6032
6033
Ben Murdoch589d6972011-11-30 16:04:58 +00006034SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6035 RobustnessFlag robust_flag,
6036 int offset,
6037 int length,
6038 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006039 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00006040 return SmartArrayPointer<char>(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00006041 }
Steve Block44f0eee2011-05-26 01:26:41 +01006042 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006043
6044 // Negative length means the to the end of the string.
6045 if (length < 0) length = kMaxInt - offset;
6046
6047 // Compute the size of the UTF-8 string. Start at the specified offset.
Steve Block44f0eee2011-05-26 01:26:41 +01006048 Access<StringInputBuffer> buffer(
6049 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00006050 buffer->Reset(offset, this);
6051 int character_position = offset;
6052 int utf8_bytes = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006053 int last = unibrow::Utf16::kNoPreviousCharacter;
6054 while (buffer->has_more() && character_position++ < offset + length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006055 uint16_t character = buffer->GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006056 utf8_bytes += unibrow::Utf8::Length(character, last);
6057 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +00006058 }
6059
6060 if (length_return) {
6061 *length_return = utf8_bytes;
6062 }
6063
6064 char* result = NewArray<char>(utf8_bytes + 1);
6065
6066 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
6067 buffer->Rewind();
6068 buffer->Seek(offset);
6069 character_position = offset;
6070 int utf8_byte_position = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006071 last = unibrow::Utf16::kNoPreviousCharacter;
6072 while (buffer->has_more() && character_position++ < offset + length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006073 uint16_t character = buffer->GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006074 if (allow_nulls == DISALLOW_NULLS && character == 0) {
6075 character = ' ';
Steve Blocka7e24c12009-10-30 11:49:00 +00006076 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006077 utf8_byte_position +=
6078 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
6079 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +00006080 }
6081 result[utf8_byte_position] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00006082 return SmartArrayPointer<char>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00006083}
6084
6085
Ben Murdoch589d6972011-11-30 16:04:58 +00006086SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6087 RobustnessFlag robust_flag,
6088 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006089 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
6090}
6091
6092
6093const uc16* String::GetTwoByteData() {
6094 return GetTwoByteData(0);
6095}
6096
6097
6098const uc16* String::GetTwoByteData(unsigned start) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006099 ASSERT(!IsAsciiRepresentationUnderneath());
Steve Blocka7e24c12009-10-30 11:49:00 +00006100 switch (StringShape(this).representation_tag()) {
6101 case kSeqStringTag:
6102 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
6103 case kExternalStringTag:
6104 return ExternalTwoByteString::cast(this)->
6105 ExternalTwoByteStringGetData(start);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006106 case kSlicedStringTag: {
6107 SlicedString* slice = SlicedString::cast(this);
6108 return slice->parent()->GetTwoByteData(start + slice->offset());
6109 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006110 case kConsStringTag:
6111 UNREACHABLE();
6112 return NULL;
6113 }
6114 UNREACHABLE();
6115 return NULL;
6116}
6117
6118
Ben Murdoch589d6972011-11-30 16:04:58 +00006119SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006120 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00006121 return SmartArrayPointer<uc16>();
Steve Blocka7e24c12009-10-30 11:49:00 +00006122 }
Steve Block44f0eee2011-05-26 01:26:41 +01006123 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006124
Steve Block44f0eee2011-05-26 01:26:41 +01006125 Access<StringInputBuffer> buffer(
6126 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00006127 buffer->Reset(this);
6128
6129 uc16* result = NewArray<uc16>(length() + 1);
6130
6131 int i = 0;
6132 while (buffer->has_more()) {
6133 uint16_t character = buffer->GetNext();
6134 result[i++] = character;
6135 }
6136 result[i] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00006137 return SmartArrayPointer<uc16>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00006138}
6139
6140
6141const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
6142 return reinterpret_cast<uc16*>(
6143 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
6144}
6145
6146
6147void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6148 unsigned* offset_ptr,
6149 unsigned max_chars) {
6150 unsigned chars_read = 0;
6151 unsigned offset = *offset_ptr;
6152 while (chars_read < max_chars) {
6153 uint16_t c = *reinterpret_cast<uint16_t*>(
6154 reinterpret_cast<char*>(this) -
6155 kHeapObjectTag + kHeaderSize + offset * kShortSize);
6156 if (c <= kMaxAsciiCharCode) {
6157 // Fast case for ASCII characters. Cursor is an input output argument.
6158 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6159 rbb->util_buffer,
6160 rbb->capacity,
6161 rbb->cursor)) {
6162 break;
6163 }
6164 } else {
6165 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6166 rbb->util_buffer,
6167 rbb->capacity,
6168 rbb->cursor)) {
6169 break;
6170 }
6171 }
6172 offset++;
6173 chars_read++;
6174 }
6175 *offset_ptr = offset;
6176 rbb->remaining += chars_read;
6177}
6178
6179
6180const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
6181 unsigned* remaining,
6182 unsigned* offset_ptr,
6183 unsigned max_chars) {
6184 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
6185 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
6186 *remaining = max_chars;
6187 *offset_ptr += max_chars;
6188 return b;
6189}
6190
6191
6192// This will iterate unless the block of string data spans two 'halves' of
6193// a ConsString, in which case it will recurse. Since the block of string
6194// data to be read has a maximum size this limits the maximum recursion
6195// depth to something sane. Since C++ does not have tail call recursion
6196// elimination, the iteration must be explicit. Since this is not an
6197// -IntoBuffer method it can delegate to one of the efficient
6198// *AsciiStringReadBlock routines.
6199const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
6200 unsigned* offset_ptr,
6201 unsigned max_chars) {
6202 ConsString* current = this;
6203 unsigned offset = *offset_ptr;
6204 int offset_correction = 0;
6205
6206 while (true) {
6207 String* left = current->first();
6208 unsigned left_length = (unsigned)left->length();
6209 if (left_length > offset &&
6210 (max_chars <= left_length - offset ||
6211 (rbb->capacity <= left_length - offset &&
6212 (max_chars = left_length - offset, true)))) { // comma operator!
6213 // Left hand side only - iterate unless we have reached the bottom of
6214 // the cons tree. The assignment on the left of the comma operator is
6215 // in order to make use of the fact that the -IntoBuffer routines can
6216 // produce at most 'capacity' characters. This enables us to postpone
6217 // the point where we switch to the -IntoBuffer routines (below) in order
6218 // to maximize the chances of delegating a big chunk of work to the
6219 // efficient *AsciiStringReadBlock routines.
6220 if (StringShape(left).IsCons()) {
6221 current = ConsString::cast(left);
6222 continue;
6223 } else {
6224 const unibrow::byte* answer =
6225 String::ReadBlock(left, rbb, &offset, max_chars);
6226 *offset_ptr = offset + offset_correction;
6227 return answer;
6228 }
6229 } else if (left_length <= offset) {
6230 // Right hand side only - iterate unless we have reached the bottom of
6231 // the cons tree.
6232 String* right = current->second();
6233 offset -= left_length;
6234 offset_correction += left_length;
6235 if (StringShape(right).IsCons()) {
6236 current = ConsString::cast(right);
6237 continue;
6238 } else {
6239 const unibrow::byte* answer =
6240 String::ReadBlock(right, rbb, &offset, max_chars);
6241 *offset_ptr = offset + offset_correction;
6242 return answer;
6243 }
6244 } else {
6245 // The block to be read spans two sides of the ConsString, so we call the
6246 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
6247 // are able to assemble data from several part strings because they use
6248 // the util_buffer to store their data and never return direct pointers
6249 // to their storage. We don't try to read more than the buffer capacity
6250 // here or we can get too much recursion.
6251 ASSERT(rbb->remaining == 0);
6252 ASSERT(rbb->cursor == 0);
6253 current->ConsStringReadBlockIntoBuffer(
6254 rbb,
6255 &offset,
6256 max_chars > rbb->capacity ? rbb->capacity : max_chars);
6257 *offset_ptr = offset + offset_correction;
6258 return rbb->util_buffer;
6259 }
6260 }
6261}
6262
6263
Steve Blocka7e24c12009-10-30 11:49:00 +00006264const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
6265 unsigned* remaining,
6266 unsigned* offset_ptr,
6267 unsigned max_chars) {
6268 // Cast const char* to unibrow::byte* (signedness difference).
6269 const unibrow::byte* b =
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006270 reinterpret_cast<const unibrow::byte*>(GetChars()) + *offset_ptr;
Steve Blocka7e24c12009-10-30 11:49:00 +00006271 *remaining = max_chars;
6272 *offset_ptr += max_chars;
6273 return b;
6274}
6275
6276
Steve Blocka7e24c12009-10-30 11:49:00 +00006277void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
6278 ReadBlockBuffer* rbb,
6279 unsigned* offset_ptr,
6280 unsigned max_chars) {
6281 unsigned chars_read = 0;
6282 unsigned offset = *offset_ptr;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006283 const uint16_t* data = GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006284 while (chars_read < max_chars) {
6285 uint16_t c = data[offset];
6286 if (c <= kMaxAsciiCharCode) {
6287 // Fast case for ASCII characters. Cursor is an input output argument.
6288 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6289 rbb->util_buffer,
6290 rbb->capacity,
6291 rbb->cursor))
6292 break;
6293 } else {
6294 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6295 rbb->util_buffer,
6296 rbb->capacity,
6297 rbb->cursor))
6298 break;
6299 }
6300 offset++;
6301 chars_read++;
6302 }
6303 *offset_ptr = offset;
6304 rbb->remaining += chars_read;
6305}
6306
6307
6308void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6309 unsigned* offset_ptr,
6310 unsigned max_chars) {
6311 unsigned capacity = rbb->capacity - rbb->cursor;
6312 if (max_chars > capacity) max_chars = capacity;
6313 memcpy(rbb->util_buffer + rbb->cursor,
6314 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
6315 *offset_ptr * kCharSize,
6316 max_chars);
6317 rbb->remaining += max_chars;
6318 *offset_ptr += max_chars;
6319 rbb->cursor += max_chars;
6320}
6321
6322
6323void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
6324 ReadBlockBuffer* rbb,
6325 unsigned* offset_ptr,
6326 unsigned max_chars) {
6327 unsigned capacity = rbb->capacity - rbb->cursor;
6328 if (max_chars > capacity) max_chars = capacity;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006329 memcpy(rbb->util_buffer + rbb->cursor, GetChars() + *offset_ptr, max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006330 rbb->remaining += max_chars;
6331 *offset_ptr += max_chars;
6332 rbb->cursor += max_chars;
6333}
6334
6335
6336// This method determines the type of string involved and then copies
6337// a whole chunk of characters into a buffer, or returns a pointer to a buffer
6338// where they can be found. The pointer is not necessarily valid across a GC
6339// (see AsciiStringReadBlock).
6340const unibrow::byte* String::ReadBlock(String* input,
6341 ReadBlockBuffer* rbb,
6342 unsigned* offset_ptr,
6343 unsigned max_chars) {
6344 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
6345 if (max_chars == 0) {
6346 rbb->remaining = 0;
6347 return NULL;
6348 }
6349 switch (StringShape(input).representation_tag()) {
6350 case kSeqStringTag:
6351 if (input->IsAsciiRepresentation()) {
6352 SeqAsciiString* str = SeqAsciiString::cast(input);
6353 return str->SeqAsciiStringReadBlock(&rbb->remaining,
6354 offset_ptr,
6355 max_chars);
6356 } else {
6357 SeqTwoByteString* str = SeqTwoByteString::cast(input);
6358 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6359 offset_ptr,
6360 max_chars);
6361 return rbb->util_buffer;
6362 }
6363 case kConsStringTag:
6364 return ConsString::cast(input)->ConsStringReadBlock(rbb,
6365 offset_ptr,
6366 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006367 case kExternalStringTag:
6368 if (input->IsAsciiRepresentation()) {
6369 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
6370 &rbb->remaining,
6371 offset_ptr,
6372 max_chars);
6373 } else {
6374 ExternalTwoByteString::cast(input)->
6375 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6376 offset_ptr,
6377 max_chars);
6378 return rbb->util_buffer;
6379 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006380 case kSlicedStringTag:
6381 return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
6382 offset_ptr,
6383 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006384 default:
6385 break;
6386 }
6387
6388 UNREACHABLE();
6389 return 0;
6390}
6391
6392
Steve Blocka7e24c12009-10-30 11:49:00 +00006393void Relocatable::PostGarbageCollectionProcessing() {
Steve Block44f0eee2011-05-26 01:26:41 +01006394 Isolate* isolate = Isolate::Current();
6395 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00006396 while (current != NULL) {
6397 current->PostGarbageCollection();
6398 current = current->prev_;
6399 }
6400}
6401
6402
6403// Reserve space for statics needing saving and restoring.
6404int Relocatable::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +01006405 return sizeof(Isolate::Current()->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00006406}
6407
6408
6409// Archive statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00006410char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01006411 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
6412 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00006413 return to + ArchiveSpacePerThread();
6414}
6415
6416
6417// Restore statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00006418char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01006419 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00006420 return from + ArchiveSpacePerThread();
6421}
6422
6423
6424char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
6425 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
6426 Iterate(v, top);
6427 return thread_storage + ArchiveSpacePerThread();
6428}
6429
6430
6431void Relocatable::Iterate(ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01006432 Isolate* isolate = Isolate::Current();
6433 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00006434}
6435
6436
6437void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
6438 Relocatable* current = top;
6439 while (current != NULL) {
6440 current->IterateInstance(v);
6441 current = current->prev_;
6442 }
6443}
6444
6445
Steve Block44f0eee2011-05-26 01:26:41 +01006446FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
6447 : Relocatable(isolate),
6448 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00006449 length_(str->length()) {
6450 PostGarbageCollection();
6451}
6452
6453
Steve Block44f0eee2011-05-26 01:26:41 +01006454FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
6455 : Relocatable(isolate),
6456 str_(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00006457 is_ascii_(true),
6458 length_(input.length()),
6459 start_(input.start()) { }
6460
6461
6462void FlatStringReader::PostGarbageCollection() {
6463 if (str_ == NULL) return;
6464 Handle<String> str(str_);
6465 ASSERT(str->IsFlat());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006466 String::FlatContent content = str->GetFlatContent();
6467 ASSERT(content.IsFlat());
6468 is_ascii_ = content.IsAscii();
Steve Blocka7e24c12009-10-30 11:49:00 +00006469 if (is_ascii_) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006470 start_ = content.ToAsciiVector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00006471 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006472 start_ = content.ToUC16Vector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00006473 }
6474}
6475
6476
6477void StringInputBuffer::Seek(unsigned pos) {
6478 Reset(pos, input_);
6479}
6480
6481
6482void SafeStringInputBuffer::Seek(unsigned pos) {
6483 Reset(pos, input_);
6484}
6485
6486
6487// This method determines the type of string involved and then copies
6488// a whole chunk of characters into a buffer. It can be used with strings
6489// that have been glued together to form a ConsString and which must cooperate
6490// to fill up a buffer.
6491void String::ReadBlockIntoBuffer(String* input,
6492 ReadBlockBuffer* rbb,
6493 unsigned* offset_ptr,
6494 unsigned max_chars) {
6495 ASSERT(*offset_ptr <= (unsigned)input->length());
6496 if (max_chars == 0) return;
6497
6498 switch (StringShape(input).representation_tag()) {
6499 case kSeqStringTag:
6500 if (input->IsAsciiRepresentation()) {
6501 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
6502 offset_ptr,
6503 max_chars);
6504 return;
6505 } else {
6506 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6507 offset_ptr,
6508 max_chars);
6509 return;
6510 }
6511 case kConsStringTag:
6512 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
6513 offset_ptr,
6514 max_chars);
6515 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00006516 case kExternalStringTag:
6517 if (input->IsAsciiRepresentation()) {
Steve Blockd0582a62009-12-15 09:54:21 +00006518 ExternalAsciiString::cast(input)->
6519 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
6520 } else {
6521 ExternalTwoByteString::cast(input)->
6522 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6523 offset_ptr,
6524 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00006525 }
6526 return;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006527 case kSlicedStringTag:
6528 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
6529 offset_ptr,
6530 max_chars);
6531 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00006532 default:
6533 break;
6534 }
6535
6536 UNREACHABLE();
6537 return;
6538}
6539
6540
6541const unibrow::byte* String::ReadBlock(String* input,
6542 unibrow::byte* util_buffer,
6543 unsigned capacity,
6544 unsigned* remaining,
6545 unsigned* offset_ptr) {
6546 ASSERT(*offset_ptr <= (unsigned)input->length());
6547 unsigned chars = input->length() - *offset_ptr;
6548 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6549 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
6550 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6551 *remaining = rbb.remaining;
6552 return answer;
6553}
6554
6555
6556const unibrow::byte* String::ReadBlock(String** raw_input,
6557 unibrow::byte* util_buffer,
6558 unsigned capacity,
6559 unsigned* remaining,
6560 unsigned* offset_ptr) {
6561 Handle<String> input(raw_input);
6562 ASSERT(*offset_ptr <= (unsigned)input->length());
6563 unsigned chars = input->length() - *offset_ptr;
6564 if (chars > capacity) chars = capacity;
6565 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6566 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
6567 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
6568 *remaining = rbb.remaining;
6569 return rbb.util_buffer;
6570}
6571
6572
6573// This will iterate unless the block of string data spans two 'halves' of
6574// a ConsString, in which case it will recurse. Since the block of string
6575// data to be read has a maximum size this limits the maximum recursion
6576// depth to something sane. Since C++ does not have tail call recursion
6577// elimination, the iteration must be explicit.
6578void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6579 unsigned* offset_ptr,
6580 unsigned max_chars) {
6581 ConsString* current = this;
6582 unsigned offset = *offset_ptr;
6583 int offset_correction = 0;
6584
6585 while (true) {
6586 String* left = current->first();
6587 unsigned left_length = (unsigned)left->length();
6588 if (left_length > offset &&
6589 max_chars <= left_length - offset) {
6590 // Left hand side only - iterate unless we have reached the bottom of
6591 // the cons tree.
6592 if (StringShape(left).IsCons()) {
6593 current = ConsString::cast(left);
6594 continue;
6595 } else {
6596 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
6597 *offset_ptr = offset + offset_correction;
6598 return;
6599 }
6600 } else if (left_length <= offset) {
6601 // Right hand side only - iterate unless we have reached the bottom of
6602 // the cons tree.
6603 offset -= left_length;
6604 offset_correction += left_length;
6605 String* right = current->second();
6606 if (StringShape(right).IsCons()) {
6607 current = ConsString::cast(right);
6608 continue;
6609 } else {
6610 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6611 *offset_ptr = offset + offset_correction;
6612 return;
6613 }
6614 } else {
6615 // The block to be read spans two sides of the ConsString, so we recurse.
6616 // First recurse on the left.
6617 max_chars -= left_length - offset;
6618 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
6619 // We may have reached the max or there may not have been enough space
6620 // in the buffer for the characters in the left hand side.
6621 if (offset == left_length) {
6622 // Recurse on the right.
6623 String* right = String::cast(current->second());
6624 offset -= left_length;
6625 offset_correction += left_length;
6626 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6627 }
6628 *offset_ptr = offset + offset_correction;
6629 return;
6630 }
6631 }
6632}
6633
6634
Steve Blocka7e24c12009-10-30 11:49:00 +00006635uint16_t ConsString::ConsStringGet(int index) {
6636 ASSERT(index >= 0 && index < this->length());
6637
6638 // Check for a flattened cons string
6639 if (second()->length() == 0) {
6640 String* left = first();
6641 return left->Get(index);
6642 }
6643
6644 String* string = String::cast(this);
6645
6646 while (true) {
6647 if (StringShape(string).IsCons()) {
6648 ConsString* cons_string = ConsString::cast(string);
6649 String* left = cons_string->first();
6650 if (left->length() > index) {
6651 string = left;
6652 } else {
6653 index -= left->length();
6654 string = cons_string->second();
6655 }
6656 } else {
6657 return string->Get(index);
6658 }
6659 }
6660
6661 UNREACHABLE();
6662 return 0;
6663}
6664
6665
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006666uint16_t SlicedString::SlicedStringGet(int index) {
6667 return parent()->Get(offset() + index);
6668}
6669
6670
6671const unibrow::byte* SlicedString::SlicedStringReadBlock(
6672 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6673 unsigned offset = this->offset();
6674 *offset_ptr += offset;
6675 const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
6676 buffer, offset_ptr, chars);
6677 *offset_ptr -= offset;
6678 return answer;
6679}
6680
6681
6682void SlicedString::SlicedStringReadBlockIntoBuffer(
6683 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6684 unsigned offset = this->offset();
6685 *offset_ptr += offset;
6686 String::ReadBlockIntoBuffer(String::cast(parent()),
6687 buffer, offset_ptr, chars);
6688 *offset_ptr -= offset;
6689}
6690
Steve Blocka7e24c12009-10-30 11:49:00 +00006691template <typename sinkchar>
6692void String::WriteToFlat(String* src,
6693 sinkchar* sink,
6694 int f,
6695 int t) {
6696 String* source = src;
6697 int from = f;
6698 int to = t;
6699 while (true) {
6700 ASSERT(0 <= from && from <= to && to <= source->length());
6701 switch (StringShape(source).full_representation_tag()) {
6702 case kAsciiStringTag | kExternalStringTag: {
6703 CopyChars(sink,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006704 ExternalAsciiString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +00006705 to - from);
6706 return;
6707 }
6708 case kTwoByteStringTag | kExternalStringTag: {
6709 const uc16* data =
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006710 ExternalTwoByteString::cast(source)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006711 CopyChars(sink,
6712 data + from,
6713 to - from);
6714 return;
6715 }
6716 case kAsciiStringTag | kSeqStringTag: {
6717 CopyChars(sink,
6718 SeqAsciiString::cast(source)->GetChars() + from,
6719 to - from);
6720 return;
6721 }
6722 case kTwoByteStringTag | kSeqStringTag: {
6723 CopyChars(sink,
6724 SeqTwoByteString::cast(source)->GetChars() + from,
6725 to - from);
6726 return;
6727 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006728 case kAsciiStringTag | kConsStringTag:
6729 case kTwoByteStringTag | kConsStringTag: {
6730 ConsString* cons_string = ConsString::cast(source);
6731 String* first = cons_string->first();
6732 int boundary = first->length();
6733 if (to - boundary >= boundary - from) {
6734 // Right hand side is longer. Recurse over left.
6735 if (from < boundary) {
6736 WriteToFlat(first, sink, from, boundary);
6737 sink += boundary - from;
6738 from = 0;
6739 } else {
6740 from -= boundary;
6741 }
6742 to -= boundary;
6743 source = cons_string->second();
6744 } else {
6745 // Left hand side is longer. Recurse over right.
6746 if (to > boundary) {
6747 String* second = cons_string->second();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006748 // When repeatedly appending to a string, we get a cons string that
6749 // is unbalanced to the left, a list, essentially. We inline the
6750 // common case of sequential ascii right child.
6751 if (to - boundary == 1) {
6752 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
6753 } else if (second->IsSeqAsciiString()) {
6754 CopyChars(sink + boundary - from,
6755 SeqAsciiString::cast(second)->GetChars(),
Steve Blocka7e24c12009-10-30 11:49:00 +00006756 to - boundary);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006757 } else {
6758 WriteToFlat(second,
6759 sink + boundary - from,
6760 0,
6761 to - boundary);
6762 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006763 to = boundary;
6764 }
6765 source = first;
6766 }
6767 break;
6768 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006769 case kAsciiStringTag | kSlicedStringTag:
6770 case kTwoByteStringTag | kSlicedStringTag: {
6771 SlicedString* slice = SlicedString::cast(source);
6772 unsigned offset = slice->offset();
6773 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
6774 return;
6775 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006776 }
6777 }
6778}
6779
6780
Steve Blocka7e24c12009-10-30 11:49:00 +00006781template <typename IteratorA, typename IteratorB>
6782static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
6783 // General slow case check. We know that the ia and ib iterators
6784 // have the same length.
6785 while (ia->has_more()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006786 uint32_t ca = ia->GetNext();
6787 uint32_t cb = ib->GetNext();
6788 ASSERT(ca <= unibrow::Utf16::kMaxNonSurrogateCharCode);
6789 ASSERT(cb <= unibrow::Utf16::kMaxNonSurrogateCharCode);
Steve Blocka7e24c12009-10-30 11:49:00 +00006790 if (ca != cb)
6791 return false;
6792 }
6793 return true;
6794}
6795
6796
6797// Compares the contents of two strings by reading and comparing
6798// int-sized blocks of characters.
6799template <typename Char>
6800static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
6801 int length = a.length();
6802 ASSERT_EQ(length, b.length());
6803 const Char* pa = a.start();
6804 const Char* pb = b.start();
6805 int i = 0;
6806#ifndef V8_HOST_CAN_READ_UNALIGNED
6807 // If this architecture isn't comfortable reading unaligned ints
6808 // then we have to check that the strings are aligned before
6809 // comparing them blockwise.
6810 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
6811 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
6812 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
6813 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
6814#endif
6815 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
6816 int endpoint = length - kStepSize;
6817 // Compare blocks until we reach near the end of the string.
6818 for (; i <= endpoint; i += kStepSize) {
6819 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
6820 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
6821 if (wa != wb) {
6822 return false;
6823 }
6824 }
6825#ifndef V8_HOST_CAN_READ_UNALIGNED
6826 }
6827#endif
6828 // Compare the remaining characters that didn't fit into a block.
6829 for (; i < length; i++) {
6830 if (a[i] != b[i]) {
6831 return false;
6832 }
6833 }
6834 return true;
6835}
6836
6837
Steve Blocka7e24c12009-10-30 11:49:00 +00006838template <typename IteratorA>
Steve Block44f0eee2011-05-26 01:26:41 +01006839static inline bool CompareStringContentsPartial(Isolate* isolate,
6840 IteratorA* ia,
6841 String* b) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006842 String::FlatContent content = b->GetFlatContent();
6843 if (content.IsFlat()) {
6844 if (content.IsAscii()) {
6845 VectorIterator<char> ib(content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006846 return CompareStringContents(ia, &ib);
6847 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006848 VectorIterator<uc16> ib(content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006849 return CompareStringContents(ia, &ib);
6850 }
6851 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006852 isolate->objects_string_compare_buffer_b()->Reset(0, b);
6853 return CompareStringContents(ia,
6854 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006855 }
6856}
6857
6858
Steve Blocka7e24c12009-10-30 11:49:00 +00006859bool String::SlowEquals(String* other) {
6860 // Fast check: negative check with lengths.
6861 int len = length();
6862 if (len != other->length()) return false;
6863 if (len == 0) return true;
6864
6865 // Fast check: if hash code is computed for both strings
6866 // a fast negative check can be performed.
6867 if (HasHashCode() && other->HasHashCode()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00006868#ifdef DEBUG
6869 if (FLAG_enable_slow_asserts) {
6870 if (Hash() != other->Hash()) {
6871 bool found_difference = false;
6872 for (int i = 0; i < len; i++) {
6873 if (Get(i) != other->Get(i)) {
6874 found_difference = true;
6875 break;
6876 }
6877 }
6878 ASSERT(found_difference);
6879 }
6880 }
6881#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00006882 if (Hash() != other->Hash()) return false;
6883 }
6884
Leon Clarkef7060e22010-06-03 12:02:55 +01006885 // We know the strings are both non-empty. Compare the first chars
6886 // before we try to flatten the strings.
6887 if (this->Get(0) != other->Get(0)) return false;
6888
6889 String* lhs = this->TryFlattenGetString();
6890 String* rhs = other->TryFlattenGetString();
6891
6892 if (StringShape(lhs).IsSequentialAscii() &&
6893 StringShape(rhs).IsSequentialAscii()) {
6894 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
6895 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006896 return CompareRawStringContents(Vector<const char>(str1, len),
6897 Vector<const char>(str2, len));
6898 }
6899
Steve Block44f0eee2011-05-26 01:26:41 +01006900 Isolate* isolate = GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006901 String::FlatContent lhs_content = lhs->GetFlatContent();
6902 String::FlatContent rhs_content = rhs->GetFlatContent();
6903 if (lhs_content.IsFlat()) {
6904 if (lhs_content.IsAscii()) {
6905 Vector<const char> vec1 = lhs_content.ToAsciiVector();
6906 if (rhs_content.IsFlat()) {
6907 if (rhs_content.IsAscii()) {
6908 Vector<const char> vec2 = rhs_content.ToAsciiVector();
Steve Blocka7e24c12009-10-30 11:49:00 +00006909 return CompareRawStringContents(vec1, vec2);
6910 } else {
6911 VectorIterator<char> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006912 VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006913 return CompareStringContents(&buf1, &ib);
6914 }
6915 } else {
6916 VectorIterator<char> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01006917 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6918 return CompareStringContents(&buf1,
6919 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006920 }
6921 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006922 Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
6923 if (rhs_content.IsFlat()) {
6924 if (rhs_content.IsAscii()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006925 VectorIterator<uc16> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006926 VectorIterator<char> ib(rhs_content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006927 return CompareStringContents(&buf1, &ib);
6928 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006929 Vector<const uc16> vec2(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006930 return CompareRawStringContents(vec1, vec2);
6931 }
6932 } else {
6933 VectorIterator<uc16> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01006934 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6935 return CompareStringContents(&buf1,
6936 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006937 }
6938 }
6939 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006940 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
6941 return CompareStringContentsPartial(isolate,
6942 isolate->objects_string_compare_buffer_a(), rhs);
Steve Blocka7e24c12009-10-30 11:49:00 +00006943 }
6944}
6945
6946
6947bool String::MarkAsUndetectable() {
6948 if (StringShape(this).IsSymbol()) return false;
6949
6950 Map* map = this->map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006951 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01006952 if (map == heap->string_map()) {
6953 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006954 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01006955 } else if (map == heap->ascii_string_map()) {
6956 this->set_map(heap->undetectable_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006957 return true;
6958 }
6959 // Rest cannot be marked as undetectable
6960 return false;
6961}
6962
6963
6964bool String::IsEqualTo(Vector<const char> str) {
Steve Block44f0eee2011-05-26 01:26:41 +01006965 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006966 int slen = length();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006967 Access<UnicodeCache::Utf8Decoder>
6968 decoder(isolate->unicode_cache()->utf8_decoder());
Steve Blocka7e24c12009-10-30 11:49:00 +00006969 decoder->Reset(str.start(), str.length());
6970 int i;
6971 for (i = 0; i < slen && decoder->has_more(); i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006972 uint32_t r = decoder->GetNext();
6973 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
6974 if (i > slen - 1) return false;
6975 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
6976 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
6977 } else {
6978 if (Get(i) != r) return false;
6979 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006980 }
6981 return i == slen && !decoder->has_more();
6982}
6983
6984
Steve Block9fac8402011-05-12 15:51:54 +01006985bool String::IsAsciiEqualTo(Vector<const char> str) {
6986 int slen = length();
6987 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006988 FlatContent content = GetFlatContent();
6989 if (content.IsAscii()) {
6990 return CompareChars(content.ToAsciiVector().start(),
6991 str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006992 }
6993 for (int i = 0; i < slen; i++) {
6994 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +01006995 }
6996 return true;
6997}
6998
6999
7000bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
7001 int slen = length();
7002 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007003 FlatContent content = GetFlatContent();
7004 if (content.IsTwoByte()) {
7005 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007006 }
Steve Block9fac8402011-05-12 15:51:54 +01007007 for (int i = 0; i < slen; i++) {
7008 if (Get(i) != str[i]) return false;
7009 }
7010 return true;
7011}
7012
7013
Steve Blocka7e24c12009-10-30 11:49:00 +00007014uint32_t String::ComputeAndSetHash() {
7015 // Should only be called if hash code has not yet been computed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007016 ASSERT(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00007017
Steve Block6ded16b2010-05-10 14:33:55 +01007018 const int len = length();
7019
Steve Blocka7e24c12009-10-30 11:49:00 +00007020 // Compute the hash code.
Steve Block6ded16b2010-05-10 14:33:55 +01007021 uint32_t field = 0;
7022 if (StringShape(this).IsSequentialAscii()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00007023 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(),
7024 len,
7025 GetHeap()->HashSeed());
Steve Block6ded16b2010-05-10 14:33:55 +01007026 } else if (StringShape(this).IsSequentialTwoByte()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00007027 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(),
7028 len,
7029 GetHeap()->HashSeed());
Steve Block6ded16b2010-05-10 14:33:55 +01007030 } else {
7031 StringInputBuffer buffer(this);
Ben Murdochc7cc0282012-03-05 14:35:55 +00007032 field = ComputeHashField(&buffer, len, GetHeap()->HashSeed());
Steve Block6ded16b2010-05-10 14:33:55 +01007033 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007034
7035 // Store the hash code in the object.
Steve Blockd0582a62009-12-15 09:54:21 +00007036 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00007037
7038 // Check the hash code is there.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007039 ASSERT(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00007040 uint32_t result = field >> kHashShift;
7041 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
7042 return result;
7043}
7044
7045
7046bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
7047 uint32_t* index,
7048 int length) {
7049 if (length == 0 || length > kMaxArrayIndexSize) return false;
7050 uc32 ch = buffer->GetNext();
7051
7052 // If the string begins with a '0' character, it must only consist
7053 // of it to be a legal array index.
7054 if (ch == '0') {
7055 *index = 0;
7056 return length == 1;
7057 }
7058
7059 // Convert string to uint32 array index; character by character.
7060 int d = ch - '0';
7061 if (d < 0 || d > 9) return false;
7062 uint32_t result = d;
7063 while (buffer->has_more()) {
7064 d = buffer->GetNext() - '0';
7065 if (d < 0 || d > 9) return false;
7066 // Check that the new result is below the 32 bit limit.
7067 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
7068 result = (result * 10) + d;
7069 }
7070
7071 *index = result;
7072 return true;
7073}
7074
7075
7076bool String::SlowAsArrayIndex(uint32_t* index) {
7077 if (length() <= kMaxCachedArrayIndexLength) {
7078 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00007079 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007080 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00007081 // Isolate the array index form the full hash field.
7082 *index = (kArrayIndexHashMask & field) >> kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00007083 return true;
7084 } else {
7085 StringInputBuffer buffer(this);
7086 return ComputeArrayIndex(&buffer, index, length());
7087 }
7088}
7089
7090
Iain Merrick9ac36c92010-09-13 15:29:50 +01007091uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01007092 // For array indexes mix the length into the hash as an array index could
7093 // be zero.
7094 ASSERT(length > 0);
7095 ASSERT(length <= String::kMaxArrayIndexSize);
7096 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
7097 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01007098
7099 value <<= String::kHashShift;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01007100 value |= length << String::kArrayIndexHashLengthShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01007101
7102 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
7103 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
7104 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01007105 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00007106}
7107
7108
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007109void StringHasher::AddSurrogatePair(uc32 c) {
7110 uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
7111 AddCharacter(lead);
7112 uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
7113 AddCharacter(trail);
7114}
7115
7116
7117void StringHasher::AddSurrogatePairNoIndex(uc32 c) {
7118 uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
7119 AddCharacterNoIndex(lead);
7120 uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
7121 AddCharacterNoIndex(trail);
7122}
7123
7124
Steve Blocka7e24c12009-10-30 11:49:00 +00007125uint32_t StringHasher::GetHashField() {
7126 ASSERT(is_valid());
Steve Blockd0582a62009-12-15 09:54:21 +00007127 if (length_ <= String::kMaxHashCalcLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007128 if (is_array_index()) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01007129 return MakeArrayIndexHash(array_index(), length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00007130 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01007131 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00007132 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01007133 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00007134 }
7135}
7136
7137
Steve Blockd0582a62009-12-15 09:54:21 +00007138uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
Ben Murdochc7cc0282012-03-05 14:35:55 +00007139 int length,
7140 uint32_t seed) {
7141 StringHasher hasher(length, seed);
Steve Blocka7e24c12009-10-30 11:49:00 +00007142
7143 // Very long strings have a trivial hash that doesn't inspect the
7144 // string contents.
7145 if (hasher.has_trivial_hash()) {
7146 return hasher.GetHashField();
7147 }
7148
7149 // Do the iterative array index computation as long as there is a
7150 // chance this is an array index.
7151 while (buffer->has_more() && hasher.is_array_index()) {
7152 hasher.AddCharacter(buffer->GetNext());
7153 }
7154
7155 // Process the remaining characters without updating the array
7156 // index.
7157 while (buffer->has_more()) {
7158 hasher.AddCharacterNoIndex(buffer->GetNext());
7159 }
7160
7161 return hasher.GetHashField();
7162}
7163
7164
John Reck59135872010-11-02 12:39:01 -07007165MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01007166 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007167 if (start == 0 && end == length()) return this;
Steve Block44f0eee2011-05-26 01:26:41 +01007168 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
Steve Blockd0582a62009-12-15 09:54:21 +00007169 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007170}
7171
7172
7173void String::PrintOn(FILE* file) {
7174 int length = this->length();
7175 for (int i = 0; i < length; i++) {
7176 fprintf(file, "%c", Get(i));
7177 }
7178}
7179
7180
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007181void Map::CreateOneBackPointer(Object* transition_target) {
7182 if (!transition_target->IsMap()) return;
7183 Map* target = Map::cast(transition_target);
7184#ifdef DEBUG
7185 // Verify target.
7186 Object* source_prototype = prototype();
7187 Object* target_prototype = target->prototype();
7188 ASSERT(source_prototype->IsJSReceiver() ||
7189 source_prototype->IsMap() ||
7190 source_prototype->IsNull());
7191 ASSERT(target_prototype->IsJSReceiver() ||
7192 target_prototype->IsNull());
7193 ASSERT(source_prototype->IsMap() ||
7194 source_prototype == target_prototype);
7195#endif
7196 // Point target back to source. set_prototype() will not let us set
7197 // the prototype to a map, as we do here.
7198 *RawField(target, kPrototypeOffset) = this;
7199}
7200
7201
Steve Blocka7e24c12009-10-30 11:49:00 +00007202void Map::CreateBackPointers() {
7203 DescriptorArray* descriptors = instance_descriptors();
7204 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007205 switch (descriptors->GetType(i)) {
7206 case MAP_TRANSITION:
7207 case CONSTANT_TRANSITION:
7208 CreateOneBackPointer(descriptors->GetValue(i));
7209 break;
7210 case ELEMENTS_TRANSITION: {
7211 Object* object = descriptors->GetValue(i);
7212 if (object->IsMap()) {
7213 CreateOneBackPointer(object);
7214 } else {
7215 FixedArray* array = FixedArray::cast(object);
7216 for (int i = 0; i < array->length(); ++i) {
7217 CreateOneBackPointer(array->get(i));
7218 }
7219 }
7220 break;
7221 }
7222 case CALLBACKS: {
7223 Object* object = descriptors->GetValue(i);
7224 if (object->IsAccessorPair()) {
7225 AccessorPair* accessors = AccessorPair::cast(object);
7226 CreateOneBackPointer(accessors->getter());
7227 CreateOneBackPointer(accessors->setter());
7228 }
7229 break;
7230 }
7231 case NORMAL:
7232 case FIELD:
7233 case CONSTANT_FUNCTION:
7234 case HANDLER:
7235 case INTERCEPTOR:
7236 case NULL_DESCRIPTOR:
7237 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007238 }
7239 }
7240}
7241
7242
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007243bool Map::RestoreOneBackPointer(Object* object,
7244 Object* real_prototype,
7245 bool* keep_entry) {
7246 if (!object->IsMap()) return false;
7247 Map* map = Map::cast(object);
7248 if (Marking::MarkBitFrom(map).Get()) {
7249 *keep_entry = true;
7250 return false;
7251 }
7252 ASSERT(map->prototype() == this || map->prototype() == real_prototype);
7253 // Getter prototype() is read-only, set_prototype() has side effects.
7254 *RawField(map, Map::kPrototypeOffset) = real_prototype;
7255 return true;
7256}
7257
7258
Steve Block44f0eee2011-05-26 01:26:41 +01007259void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007260 DescriptorArray* d = DescriptorArray::cast(
Ben Murdoch257744e2011-11-30 15:57:28 +00007261 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
7262 if (d->IsEmpty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00007263 Smi* NullDescriptorDetails =
7264 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007265 FixedArray* contents = FixedArray::cast(
Steve Blocka7e24c12009-10-30 11:49:00 +00007266 d->get(DescriptorArray::kContentArrayIndex));
7267 ASSERT(contents->length() >= 2);
7268 for (int i = 0; i < contents->length(); i += 2) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007269 // If the pair (value, details) is a map transition, check if the target is
7270 // live. If not, null the descriptor. Also drop the back pointer for that
7271 // map transition, so that this map is not reached again by following a back
7272 // pointer from a non-live object.
7273 bool keep_entry = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007274 PropertyDetails details(Smi::cast(contents->get(i + 1)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007275 switch (details.type()) {
7276 case MAP_TRANSITION:
7277 case CONSTANT_TRANSITION:
7278 RestoreOneBackPointer(contents->get(i), real_prototype, &keep_entry);
7279 break;
7280 case ELEMENTS_TRANSITION: {
7281 Object* object = contents->get(i);
7282 if (object->IsMap()) {
7283 RestoreOneBackPointer(object, real_prototype, &keep_entry);
7284 } else {
7285 FixedArray* array = FixedArray::cast(object);
7286 for (int j = 0; j < array->length(); ++j) {
7287 if (RestoreOneBackPointer(array->get(j),
7288 real_prototype,
7289 &keep_entry)) {
7290 array->set_undefined(j);
7291 }
7292 }
7293 }
7294 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007295 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007296 case CALLBACKS: {
7297 Object* object = contents->get(i);
7298 if (object->IsAccessorPair()) {
7299 AccessorPair* accessors = AccessorPair::cast(object);
7300 if (RestoreOneBackPointer(accessors->getter(),
7301 real_prototype,
7302 &keep_entry)) {
7303 accessors->set_getter(heap->the_hole_value());
7304 }
7305 if (RestoreOneBackPointer(accessors->setter(),
7306 real_prototype,
7307 &keep_entry)) {
7308 accessors->set_setter(heap->the_hole_value());
7309 }
7310 } else {
7311 keep_entry = true;
7312 }
7313 break;
7314 }
7315 case NORMAL:
7316 case FIELD:
7317 case CONSTANT_FUNCTION:
7318 case HANDLER:
7319 case INTERCEPTOR:
7320 case NULL_DESCRIPTOR:
7321 keep_entry = true;
7322 break;
7323 }
7324 // Make sure that an entry containing only dead transitions gets collected.
7325 // What we *really* want to do here is removing this entry completely, but
7326 // for technical reasons we can't do this, so we zero it out instead.
7327 if (!keep_entry) {
7328 contents->set_unchecked(i + 1, NullDescriptorDetails);
7329 contents->set_null_unchecked(heap, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00007330 }
7331 }
7332}
7333
7334
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007335int Map::Hash() {
7336 // For performance reasons we only hash the 3 most variable fields of a map:
7337 // constructor, prototype and bit_field2.
7338
7339 // Shift away the tag.
7340 int hash = (static_cast<uint32_t>(
7341 reinterpret_cast<uintptr_t>(constructor())) >> 2);
7342
7343 // XOR-ing the prototype and constructor directly yields too many zero bits
7344 // when the two pointers are close (which is fairly common).
7345 // To avoid this we shift the prototype 4 bits relatively to the constructor.
7346 hash ^= (static_cast<uint32_t>(
7347 reinterpret_cast<uintptr_t>(prototype())) << 2);
7348
7349 return hash ^ (hash >> 16) ^ bit_field2();
7350}
7351
7352
7353bool Map::EquivalentToForNormalization(Map* other,
7354 PropertyNormalizationMode mode) {
7355 return
7356 constructor() == other->constructor() &&
7357 prototype() == other->prototype() &&
7358 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
7359 0 :
7360 other->inobject_properties()) &&
7361 instance_type() == other->instance_type() &&
7362 bit_field() == other->bit_field() &&
7363 bit_field2() == other->bit_field2() &&
7364 (bit_field3() & ~(1<<Map::kIsShared)) ==
7365 (other->bit_field3() & ~(1<<Map::kIsShared));
7366}
7367
7368
Steve Block791712a2010-08-27 10:21:07 +01007369void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
7370 // Iterate over all fields in the body but take care in dealing with
7371 // the code entry.
7372 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
7373 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
7374 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
7375}
7376
7377
Ben Murdochb0fe1622011-05-05 13:52:32 +01007378void JSFunction::MarkForLazyRecompilation() {
7379 ASSERT(is_compiled() && !IsOptimized());
Ben Murdochb8e0da22011-05-16 14:20:40 +01007380 ASSERT(shared()->allows_lazy_compilation() ||
7381 code()->optimizable());
Steve Block44f0eee2011-05-26 01:26:41 +01007382 Builtins* builtins = GetIsolate()->builtins();
7383 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007384}
7385
7386
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007387bool SharedFunctionInfo::EnsureCompiled(Handle<SharedFunctionInfo> shared,
7388 ClearExceptionFlag flag) {
7389 return shared->is_compiled() || CompileLazy(shared, flag);
7390}
7391
7392
7393static bool CompileLazyHelper(CompilationInfo* info,
7394 ClearExceptionFlag flag) {
7395 // Compile the source information to a code object.
7396 ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
7397 ASSERT(!info->isolate()->has_pending_exception());
7398 bool result = Compiler::CompileLazy(info);
7399 ASSERT(result != Isolate::Current()->has_pending_exception());
7400 if (!result && flag == CLEAR_EXCEPTION) {
7401 info->isolate()->clear_pending_exception();
7402 }
7403 return result;
7404}
7405
7406
7407bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
7408 ClearExceptionFlag flag) {
7409 CompilationInfo info(shared);
7410 return CompileLazyHelper(&info, flag);
7411}
7412
7413
7414bool JSFunction::CompileLazy(Handle<JSFunction> function,
7415 ClearExceptionFlag flag) {
7416 bool result = true;
7417 if (function->shared()->is_compiled()) {
7418 function->ReplaceCode(function->shared()->code());
7419 function->shared()->set_code_age(0);
7420 } else {
7421 CompilationInfo info(function);
7422 result = CompileLazyHelper(&info, flag);
7423 ASSERT(!result || function->is_compiled());
7424 }
7425 return result;
7426}
7427
7428
7429bool JSFunction::CompileOptimized(Handle<JSFunction> function,
7430 int osr_ast_id,
7431 ClearExceptionFlag flag) {
7432 CompilationInfo info(function);
7433 info.SetOptimizing(osr_ast_id);
7434 return CompileLazyHelper(&info, flag);
7435}
7436
7437
Ben Murdochb0fe1622011-05-05 13:52:32 +01007438bool JSFunction::IsInlineable() {
7439 if (IsBuiltin()) return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007440 SharedFunctionInfo* shared_info = shared();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007441 // Check that the function has a script associated with it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007442 if (!shared_info->script()->IsScript()) return false;
7443 if (shared_info->optimization_disabled()) return false;
7444 Code* code = shared_info->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007445 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
7446 // If we never ran this (unlikely) then lets try to optimize it.
7447 if (code->kind() != Code::FUNCTION) return true;
7448 return code->optimizable();
7449}
7450
7451
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007452MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
7453 ASSERT(value->IsJSReceiver());
Steve Block44f0eee2011-05-26 01:26:41 +01007454 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007455 if (has_initial_map()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007456 // If the function has allocated the initial map
7457 // replace it with a copy containing the new prototype.
7458 Map* new_map;
7459 MaybeObject* maybe_new_map = initial_map()->CopyDropTransitions();
7460 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
7461 new_map->set_prototype(value);
7462 MaybeObject* maybe_object =
7463 set_initial_map_and_cache_transitions(new_map);
7464 if (maybe_object->IsFailure()) return maybe_object;
Steve Blocka7e24c12009-10-30 11:49:00 +00007465 } else {
7466 // Put the value in the initial map field until an initial map is
7467 // needed. At that point, a new initial map is created and the
7468 // prototype is put into the initial map where it belongs.
7469 set_prototype_or_initial_map(value);
7470 }
Steve Block44f0eee2011-05-26 01:26:41 +01007471 heap->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00007472 return value;
7473}
7474
7475
John Reck59135872010-11-02 12:39:01 -07007476MaybeObject* JSFunction::SetPrototype(Object* value) {
Steve Block6ded16b2010-05-10 14:33:55 +01007477 ASSERT(should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +00007478 Object* construct_prototype = value;
7479
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007480 // If the value is not a JSReceiver, store the value in the map's
Steve Blocka7e24c12009-10-30 11:49:00 +00007481 // constructor field so it can be accessed. Also, set the prototype
7482 // used for constructing objects to the original object prototype.
7483 // See ECMA-262 13.2.2.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007484 if (!value->IsJSReceiver()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007485 // Copy the map so this does not affect unrelated functions.
7486 // Remove map transitions because they point to maps with a
7487 // different prototype.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007488 Map* new_map;
John Reck59135872010-11-02 12:39:01 -07007489 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007490 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07007491 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007492 Heap* heap = new_map->GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007493 set_map(new_map);
7494 new_map->set_constructor(value);
7495 new_map->set_non_instance_prototype(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00007496 construct_prototype =
Steve Block44f0eee2011-05-26 01:26:41 +01007497 heap->isolate()->context()->global_context()->
7498 initial_object_prototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00007499 } else {
7500 map()->set_non_instance_prototype(false);
7501 }
7502
7503 return SetInstancePrototype(construct_prototype);
7504}
7505
7506
Steve Block6ded16b2010-05-10 14:33:55 +01007507Object* JSFunction::RemovePrototype() {
Steve Block44f0eee2011-05-26 01:26:41 +01007508 Context* global_context = context()->global_context();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007509 Map* no_prototype_map = shared()->is_classic_mode()
7510 ? global_context->function_without_prototype_map()
7511 : global_context->strict_mode_function_without_prototype_map();
Steve Block44f0eee2011-05-26 01:26:41 +01007512
7513 if (map() == no_prototype_map) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007514 // Be idempotent.
7515 return this;
7516 }
Steve Block44f0eee2011-05-26 01:26:41 +01007517
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007518 ASSERT(map() == (shared()->is_classic_mode()
7519 ? global_context->function_map()
7520 : global_context->strict_mode_function_map()));
Steve Block44f0eee2011-05-26 01:26:41 +01007521
7522 set_map(no_prototype_map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007523 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01007524 return this;
7525}
7526
7527
Steve Blocka7e24c12009-10-30 11:49:00 +00007528Object* JSFunction::SetInstanceClassName(String* name) {
7529 shared()->set_instance_class_name(name);
7530 return this;
7531}
7532
7533
Ben Murdochb0fe1622011-05-05 13:52:32 +01007534void JSFunction::PrintName(FILE* out) {
Ben Murdoch589d6972011-11-30 16:04:58 +00007535 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007536 PrintF(out, "%s", *name);
7537}
7538
7539
Steve Blocka7e24c12009-10-30 11:49:00 +00007540Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
7541 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
7542}
7543
7544
Steve Block44f0eee2011-05-26 01:26:41 +01007545MaybeObject* Oddball::Initialize(const char* to_string,
7546 Object* to_number,
7547 byte kind) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007548 String* symbol;
Steve Block44f0eee2011-05-26 01:26:41 +01007549 { MaybeObject* maybe_symbol =
7550 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007551 if (!maybe_symbol->To(&symbol)) return maybe_symbol;
John Reck59135872010-11-02 12:39:01 -07007552 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007553 set_to_string(symbol);
Steve Blocka7e24c12009-10-30 11:49:00 +00007554 set_to_number(to_number);
Steve Block44f0eee2011-05-26 01:26:41 +01007555 set_kind(kind);
Steve Blocka7e24c12009-10-30 11:49:00 +00007556 return this;
7557}
7558
7559
Ben Murdochf87a2032010-10-22 12:50:53 +01007560String* SharedFunctionInfo::DebugName() {
7561 Object* n = name();
7562 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
7563 return String::cast(n);
7564}
7565
7566
Steve Blocka7e24c12009-10-30 11:49:00 +00007567bool SharedFunctionInfo::HasSourceCode() {
7568 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01007569 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00007570}
7571
7572
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007573Handle<Object> SharedFunctionInfo::GetSourceCode() {
7574 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
7575 Handle<String> source(String::cast(Script::cast(script())->source()));
7576 return SubString(source, start_position(), end_position());
Steve Blocka7e24c12009-10-30 11:49:00 +00007577}
7578
7579
Ben Murdochb0fe1622011-05-05 13:52:32 +01007580int SharedFunctionInfo::SourceSize() {
7581 return end_position() - start_position();
7582}
7583
7584
Steve Blocka7e24c12009-10-30 11:49:00 +00007585int SharedFunctionInfo::CalculateInstanceSize() {
7586 int instance_size =
7587 JSObject::kHeaderSize +
7588 expected_nof_properties() * kPointerSize;
7589 if (instance_size > JSObject::kMaxInstanceSize) {
7590 instance_size = JSObject::kMaxInstanceSize;
7591 }
7592 return instance_size;
7593}
7594
7595
7596int SharedFunctionInfo::CalculateInObjectProperties() {
7597 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
7598}
7599
7600
Andrei Popescu402d9372010-02-26 13:31:12 +00007601bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
7602 // Check the basic conditions for generating inline constructor code.
7603 if (!FLAG_inline_new
7604 || !has_only_simple_this_property_assignments()
7605 || this_property_assignments_count() == 0) {
7606 return false;
7607 }
7608
7609 // If the prototype is null inline constructors cause no problems.
7610 if (!prototype->IsJSObject()) {
7611 ASSERT(prototype->IsNull());
7612 return true;
7613 }
7614
Ben Murdoch8b112d22011-06-08 16:22:53 +01007615 Heap* heap = GetHeap();
7616
Andrei Popescu402d9372010-02-26 13:31:12 +00007617 // Traverse the proposed prototype chain looking for setters for properties of
7618 // the same names as are set by the inline constructor.
7619 for (Object* obj = prototype;
Steve Block44f0eee2011-05-26 01:26:41 +01007620 obj != heap->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00007621 obj = obj->GetPrototype()) {
7622 JSObject* js_object = JSObject::cast(obj);
7623 for (int i = 0; i < this_property_assignments_count(); i++) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007624 LookupResult result(heap->isolate());
Andrei Popescu402d9372010-02-26 13:31:12 +00007625 String* name = GetThisPropertyAssignmentName(i);
7626 js_object->LocalLookupRealNamedProperty(name, &result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007627 if (result.IsFound() && result.type() == CALLBACKS) {
Andrei Popescu402d9372010-02-26 13:31:12 +00007628 return false;
7629 }
7630 }
7631 }
7632
7633 return true;
7634}
7635
7636
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007637void SharedFunctionInfo::ForbidInlineConstructor() {
7638 set_compiler_hints(BooleanBit::set(compiler_hints(),
7639 kHasOnlySimpleThisPropertyAssignments,
7640 false));
7641}
7642
7643
Steve Blocka7e24c12009-10-30 11:49:00 +00007644void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +00007645 bool only_simple_this_property_assignments,
7646 FixedArray* assignments) {
7647 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00007648 kHasOnlySimpleThisPropertyAssignments,
7649 only_simple_this_property_assignments));
7650 set_this_property_assignments(assignments);
7651 set_this_property_assignments_count(assignments->length() / 3);
7652}
7653
7654
7655void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
Steve Block44f0eee2011-05-26 01:26:41 +01007656 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007657 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00007658 kHasOnlySimpleThisPropertyAssignments,
7659 false));
Steve Block44f0eee2011-05-26 01:26:41 +01007660 set_this_property_assignments(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00007661 set_this_property_assignments_count(0);
7662}
7663
7664
7665String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
7666 Object* obj = this_property_assignments();
7667 ASSERT(obj->IsFixedArray());
7668 ASSERT(index < this_property_assignments_count());
7669 obj = FixedArray::cast(obj)->get(index * 3);
7670 ASSERT(obj->IsString());
7671 return String::cast(obj);
7672}
7673
7674
7675bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
7676 Object* obj = this_property_assignments();
7677 ASSERT(obj->IsFixedArray());
7678 ASSERT(index < this_property_assignments_count());
7679 obj = FixedArray::cast(obj)->get(index * 3 + 1);
7680 return Smi::cast(obj)->value() != -1;
7681}
7682
7683
7684int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
7685 ASSERT(IsThisPropertyAssignmentArgument(index));
7686 Object* obj =
7687 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
7688 return Smi::cast(obj)->value();
7689}
7690
7691
7692Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
7693 ASSERT(!IsThisPropertyAssignmentArgument(index));
7694 Object* obj =
7695 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
7696 return obj;
7697}
7698
7699
Steve Blocka7e24c12009-10-30 11:49:00 +00007700// Support function for printing the source code to a StringStream
7701// without any allocation in the heap.
7702void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
7703 int max_length) {
7704 // For some native functions there is no source.
Ben Murdochb0fe1622011-05-05 13:52:32 +01007705 if (!HasSourceCode()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007706 accumulator->Add("<No Source>");
7707 return;
7708 }
7709
Steve Blockd0582a62009-12-15 09:54:21 +00007710 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00007711 // Don't use String::cast because we don't want more assertion errors while
7712 // we are already creating a stack dump.
7713 String* script_source =
7714 reinterpret_cast<String*>(Script::cast(script())->source());
7715
7716 if (!script_source->LooksValid()) {
7717 accumulator->Add("<Invalid Source>");
7718 return;
7719 }
7720
7721 if (!is_toplevel()) {
7722 accumulator->Add("function ");
7723 Object* name = this->name();
7724 if (name->IsString() && String::cast(name)->length() > 0) {
7725 accumulator->PrintName(name);
7726 }
7727 }
7728
7729 int len = end_position() - start_position();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007730 if (len <= max_length || max_length < 0) {
7731 accumulator->Put(script_source, start_position(), end_position());
7732 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00007733 accumulator->Put(script_source,
7734 start_position(),
7735 start_position() + max_length);
7736 accumulator->Add("...\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00007737 }
7738}
7739
7740
Ben Murdochb0fe1622011-05-05 13:52:32 +01007741static bool IsCodeEquivalent(Code* code, Code* recompiled) {
7742 if (code->instruction_size() != recompiled->instruction_size()) return false;
7743 ByteArray* code_relocation = code->relocation_info();
7744 ByteArray* recompiled_relocation = recompiled->relocation_info();
7745 int length = code_relocation->length();
7746 if (length != recompiled_relocation->length()) return false;
7747 int compare = memcmp(code_relocation->GetDataStartAddress(),
7748 recompiled_relocation->GetDataStartAddress(),
7749 length);
7750 return compare == 0;
7751}
7752
7753
7754void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
7755 ASSERT(!has_deoptimization_support());
7756 AssertNoAllocation no_allocation;
7757 Code* code = this->code();
7758 if (IsCodeEquivalent(code, recompiled)) {
7759 // Copy the deoptimization data from the recompiled code.
7760 code->set_deoptimization_data(recompiled->deoptimization_data());
7761 code->set_has_deoptimization_support(true);
7762 } else {
7763 // TODO(3025757): In case the recompiled isn't equivalent to the
7764 // old code, we have to replace it. We should try to avoid this
7765 // altogether because it flushes valuable type feedback by
7766 // effectively resetting all IC state.
7767 set_code(recompiled);
7768 }
7769 ASSERT(has_deoptimization_support());
7770}
7771
7772
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007773void SharedFunctionInfo::DisableOptimization() {
Ben Murdoch257744e2011-11-30 15:57:28 +00007774 // Disable optimization for the shared function info and mark the
7775 // code as non-optimizable. The marker on the shared function info
7776 // is there because we flush non-optimized code thereby loosing the
7777 // non-optimizable information for the code. When the code is
7778 // regenerated and set on the shared function info it is marked as
7779 // non-optimizable if optimization is disabled for the shared
7780 // function info.
7781 set_optimization_disabled(true);
7782 // Code should be the lazy compilation stub or else unoptimized. If the
7783 // latter, disable optimization for the code too.
7784 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
7785 if (code()->kind() == Code::FUNCTION) {
7786 code()->set_optimizable(false);
7787 }
7788 if (FLAG_trace_opt) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007789 PrintF("[disabled optimization for %s]\n", *DebugName()->ToCString());
Ben Murdoch257744e2011-11-30 15:57:28 +00007790 }
7791}
7792
7793
Ben Murdochb0fe1622011-05-05 13:52:32 +01007794bool SharedFunctionInfo::VerifyBailoutId(int id) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007795 ASSERT(id != AstNode::kNoNumber);
7796 Code* unoptimized = code();
7797 DeoptimizationOutputData* data =
7798 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
7799 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
7800 USE(ignore);
7801 return true; // Return true if there was no ASSERT.
7802}
7803
7804
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007805void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
7806 ASSERT(!IsInobjectSlackTrackingInProgress());
7807
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007808 if (!FLAG_clever_optimizations) return;
7809
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007810 // Only initiate the tracking the first time.
7811 if (live_objects_may_exist()) return;
7812 set_live_objects_may_exist(true);
7813
7814 // No tracking during the snapshot construction phase.
7815 if (Serializer::enabled()) return;
7816
7817 if (map->unused_property_fields() == 0) return;
7818
7819 // Nonzero counter is a leftover from the previous attempt interrupted
7820 // by GC, keep it.
7821 if (construction_count() == 0) {
7822 set_construction_count(kGenerousAllocationCount);
7823 }
7824 set_initial_map(map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007825 Builtins* builtins = map->GetHeap()->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01007826 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007827 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01007828 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007829}
7830
7831
7832// Called from GC, hence reinterpret_cast and unchecked accessors.
7833void SharedFunctionInfo::DetachInitialMap() {
7834 Map* map = reinterpret_cast<Map*>(initial_map());
7835
7836 // Make the map remember to restore the link if it survives the GC.
7837 map->set_bit_field2(
7838 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
7839
7840 // Undo state changes made by StartInobjectTracking (except the
7841 // construction_count). This way if the initial map does not survive the GC
7842 // then StartInobjectTracking will be called again the next time the
7843 // constructor is called. The countdown will continue and (possibly after
7844 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007845 Heap* heap = map->GetHeap();
7846 set_initial_map(heap->raw_unchecked_undefined_value());
7847 Builtins* builtins = heap->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01007848 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007849 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01007850 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007851 // It is safe to clear the flag: it will be set again if the map is live.
7852 set_live_objects_may_exist(false);
7853}
7854
7855
7856// Called from GC, hence reinterpret_cast and unchecked accessors.
7857void SharedFunctionInfo::AttachInitialMap(Map* map) {
7858 map->set_bit_field2(
7859 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
7860
7861 // Resume inobject slack tracking.
7862 set_initial_map(map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007863 Builtins* builtins = map->GetHeap()->isolate()->builtins();
Steve Block44f0eee2011-05-26 01:26:41 +01007864 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007865 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01007866 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007867 // The map survived the gc, so there may be objects referencing it.
7868 set_live_objects_may_exist(true);
7869}
7870
7871
7872static void GetMinInobjectSlack(Map* map, void* data) {
7873 int slack = map->unused_property_fields();
7874 if (*reinterpret_cast<int*>(data) > slack) {
7875 *reinterpret_cast<int*>(data) = slack;
7876 }
7877}
7878
7879
7880static void ShrinkInstanceSize(Map* map, void* data) {
7881 int slack = *reinterpret_cast<int*>(data);
7882 map->set_inobject_properties(map->inobject_properties() - slack);
7883 map->set_unused_property_fields(map->unused_property_fields() - slack);
7884 map->set_instance_size(map->instance_size() - slack * kPointerSize);
7885
7886 // Visitor id might depend on the instance size, recalculate it.
7887 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
7888}
7889
7890
7891void SharedFunctionInfo::CompleteInobjectSlackTracking() {
7892 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
7893 Map* map = Map::cast(initial_map());
7894
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007895 Heap* heap = map->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01007896 set_initial_map(heap->undefined_value());
7897 Builtins* builtins = heap->isolate()->builtins();
7898 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007899 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01007900 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007901
7902 int slack = map->unused_property_fields();
7903 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
7904 if (slack != 0) {
7905 // Resize the initial map and all maps in its transition tree.
7906 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007907
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007908 // Give the correct expected_nof_properties to initial maps created later.
7909 ASSERT(expected_nof_properties() >= slack);
7910 set_expected_nof_properties(expected_nof_properties() - slack);
7911 }
7912}
7913
7914
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007915#define DECLARE_TAG(ignore1, name, ignore2) name,
7916const char* const VisitorSynchronization::kTags[
7917 VisitorSynchronization::kNumberOfSyncTags] = {
7918 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7919};
7920#undef DECLARE_TAG
7921
7922
7923#define DECLARE_TAG(ignore1, ignore2, name) name,
7924const char* const VisitorSynchronization::kTagNames[
7925 VisitorSynchronization::kNumberOfSyncTags] = {
7926 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7927};
7928#undef DECLARE_TAG
7929
7930
Steve Blocka7e24c12009-10-30 11:49:00 +00007931void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
7932 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
7933 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
7934 Object* old_target = target;
7935 VisitPointer(&target);
7936 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
7937}
7938
7939
Steve Block791712a2010-08-27 10:21:07 +01007940void ObjectVisitor::VisitCodeEntry(Address entry_address) {
7941 Object* code = Code::GetObjectFromEntryAddress(entry_address);
7942 Object* old_code = code;
7943 VisitPointer(&code);
7944 if (code != old_code) {
7945 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
7946 }
7947}
7948
7949
Ben Murdochb0fe1622011-05-05 13:52:32 +01007950void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
7951 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
7952 Object* cell = rinfo->target_cell();
7953 Object* old_cell = cell;
7954 VisitPointer(&cell);
7955 if (cell != old_cell) {
7956 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
7957 }
7958}
7959
7960
Steve Blocka7e24c12009-10-30 11:49:00 +00007961void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007962 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
7963 rinfo->IsPatchedReturnSequence()) ||
7964 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
7965 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007966 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
7967 Object* old_target = target;
7968 VisitPointer(&target);
7969 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
7970}
7971
7972
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007973void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
7974 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
7975 VisitPointer(rinfo->target_object_address());
7976}
7977
7978void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
7979 Address* p = rinfo->target_reference_address();
7980 VisitExternalReferences(p, p + 1);
7981}
7982
Ben Murdochb0fe1622011-05-05 13:52:32 +01007983void Code::InvalidateRelocation() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007984 set_relocation_info(GetHeap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007985}
7986
7987
Steve Blockd0582a62009-12-15 09:54:21 +00007988void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007989 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
7990 it.rinfo()->apply(delta);
7991 }
7992 CPU::FlushICache(instruction_start(), instruction_size());
7993}
7994
7995
7996void Code::CopyFrom(const CodeDesc& desc) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007997 ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
7998
Steve Blocka7e24c12009-10-30 11:49:00 +00007999 // copy code
8000 memmove(instruction_start(), desc.buffer, desc.instr_size);
8001
Steve Blocka7e24c12009-10-30 11:49:00 +00008002 // copy reloc info
8003 memmove(relocation_start(),
8004 desc.buffer + desc.buffer_size - desc.reloc_size,
8005 desc.reloc_size);
8006
8007 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +00008008 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +00008009 int mode_mask = RelocInfo::kCodeTargetMask |
8010 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb0fe1622011-05-05 13:52:32 +01008011 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
Steve Blocka7e24c12009-10-30 11:49:00 +00008012 RelocInfo::kApplyMask;
Steve Block3ce2e202009-11-05 08:53:23 +00008013 Assembler* origin = desc.origin; // Needed to find target_object on X64.
Steve Blocka7e24c12009-10-30 11:49:00 +00008014 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
8015 RelocInfo::Mode mode = it.rinfo()->rmode();
8016 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +00008017 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008018 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008019 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008020 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
8021 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
Steve Blocka7e24c12009-10-30 11:49:00 +00008022 } else if (RelocInfo::IsCodeTarget(mode)) {
8023 // rewrite code handles in inline cache targets to direct
8024 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +00008025 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00008026 Code* code = Code::cast(*p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008027 it.rinfo()->set_target_address(code->instruction_start(),
8028 SKIP_WRITE_BARRIER);
Steve Blocka7e24c12009-10-30 11:49:00 +00008029 } else {
8030 it.rinfo()->apply(delta);
8031 }
8032 }
8033 CPU::FlushICache(instruction_start(), instruction_size());
8034}
8035
8036
8037// Locate the source position which is closest to the address in the code. This
8038// is using the source position information embedded in the relocation info.
8039// The position returned is relative to the beginning of the script where the
8040// source for this function is found.
8041int Code::SourcePosition(Address pc) {
8042 int distance = kMaxInt;
8043 int position = RelocInfo::kNoPosition; // Initially no position found.
8044 // Run through all the relocation info to find the best matching source
8045 // position. All the code needs to be considered as the sequence of the
8046 // instructions in the code does not necessarily follow the same order as the
8047 // source.
8048 RelocIterator it(this, RelocInfo::kPositionMask);
8049 while (!it.done()) {
8050 // Only look at positions after the current pc.
8051 if (it.rinfo()->pc() < pc) {
8052 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +00008053
8054 int dist = static_cast<int>(pc - it.rinfo()->pc());
8055 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00008056 // If this position is closer than the current candidate or if it has the
8057 // same distance as the current candidate and the position is higher then
8058 // this position is the new candidate.
8059 if ((dist < distance) ||
8060 (dist == distance && pos > position)) {
8061 position = pos;
8062 distance = dist;
8063 }
8064 }
8065 it.next();
8066 }
8067 return position;
8068}
8069
8070
8071// Same as Code::SourcePosition above except it only looks for statement
8072// positions.
8073int Code::SourceStatementPosition(Address pc) {
8074 // First find the position as close as possible using all position
8075 // information.
8076 int position = SourcePosition(pc);
8077 // Now find the closest statement position before the position.
8078 int statement_position = 0;
8079 RelocIterator it(this, RelocInfo::kPositionMask);
8080 while (!it.done()) {
8081 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +00008082 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00008083 if (statement_position < p && p <= position) {
8084 statement_position = p;
8085 }
8086 }
8087 it.next();
8088 }
8089 return statement_position;
8090}
8091
8092
Ben Murdochb8e0da22011-05-16 14:20:40 +01008093SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008094 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01008095 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008096}
8097
8098
8099void Code::SetNoStackCheckTable() {
8100 // Indicate the absence of a stack-check table by a table start after the
8101 // end of the instructions. Table start must be aligned, so round up.
Steve Block1e0659c2011-05-24 12:43:12 +01008102 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008103}
8104
8105
8106Map* Code::FindFirstMap() {
8107 ASSERT(is_inline_cache_stub());
8108 AssertNoAllocation no_allocation;
8109 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
8110 for (RelocIterator it(this, mask); !it.done(); it.next()) {
8111 RelocInfo* info = it.rinfo();
8112 Object* object = info->target_object();
8113 if (object->IsMap()) return Map::cast(object);
8114 }
8115 return NULL;
8116}
8117
8118
Steve Blocka7e24c12009-10-30 11:49:00 +00008119#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +01008120
Ben Murdochb0fe1622011-05-05 13:52:32 +01008121void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
8122 disasm::NameConverter converter;
8123 int deopt_count = DeoptCount();
8124 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
8125 if (0 == deopt_count) return;
8126
Ben Murdoch2b4ba112012-01-20 14:57:15 +00008127 PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc",
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008128 FLAG_print_code_verbose ? "commands" : "");
Ben Murdochb0fe1622011-05-05 13:52:32 +01008129 for (int i = 0; i < deopt_count; i++) {
Ben Murdoch2b4ba112012-01-20 14:57:15 +00008130 PrintF(out, "%6d %6d %6d %6d",
8131 i,
8132 AstId(i)->value(),
8133 ArgumentsStackHeight(i)->value(),
8134 Pc(i)->value());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008135
8136 if (!FLAG_print_code_verbose) {
8137 PrintF(out, "\n");
8138 continue;
8139 }
8140 // Print details of the frame translation.
Ben Murdochb0fe1622011-05-05 13:52:32 +01008141 int translation_index = TranslationIndex(i)->value();
8142 TranslationIterator iterator(TranslationByteArray(), translation_index);
8143 Translation::Opcode opcode =
8144 static_cast<Translation::Opcode>(iterator.Next());
8145 ASSERT(Translation::BEGIN == opcode);
8146 int frame_count = iterator.Next();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008147 int jsframe_count = iterator.Next();
8148 PrintF(out, " %s {frame count=%d, js frame count=%d}\n",
8149 Translation::StringFor(opcode),
8150 frame_count,
8151 jsframe_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008152
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008153 while (iterator.HasNext() &&
8154 Translation::BEGIN !=
8155 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
8156 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
8157
8158 switch (opcode) {
8159 case Translation::BEGIN:
8160 UNREACHABLE();
8161 break;
8162
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008163 case Translation::JS_FRAME: {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008164 int ast_id = iterator.Next();
8165 int function_id = iterator.Next();
8166 JSFunction* function =
8167 JSFunction::cast(LiteralArray()->get(function_id));
8168 unsigned height = iterator.Next();
Ben Murdoch589d6972011-11-30 16:04:58 +00008169 PrintF(out, "{ast_id=%d, function=", ast_id);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008170 function->PrintName(out);
8171 PrintF(out, ", height=%u}", height);
8172 break;
8173 }
8174
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008175 case Translation::ARGUMENTS_ADAPTOR_FRAME:
8176 case Translation::CONSTRUCT_STUB_FRAME: {
8177 int function_id = iterator.Next();
8178 JSFunction* function =
8179 JSFunction::cast(LiteralArray()->get(function_id));
8180 unsigned height = iterator.Next();
8181 PrintF(out, "{function=");
8182 function->PrintName(out);
8183 PrintF(out, ", height=%u}", height);
8184 break;
8185 }
8186
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008187 case Translation::DUPLICATE:
8188 break;
8189
8190 case Translation::REGISTER: {
8191 int reg_code = iterator.Next();
8192 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8193 break;
8194 }
8195
8196 case Translation::INT32_REGISTER: {
8197 int reg_code = iterator.Next();
8198 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8199 break;
8200 }
8201
8202 case Translation::DOUBLE_REGISTER: {
8203 int reg_code = iterator.Next();
8204 PrintF(out, "{input=%s}",
8205 DoubleRegister::AllocationIndexToString(reg_code));
8206 break;
8207 }
8208
8209 case Translation::STACK_SLOT: {
8210 int input_slot_index = iterator.Next();
8211 PrintF(out, "{input=%d}", input_slot_index);
8212 break;
8213 }
8214
8215 case Translation::INT32_STACK_SLOT: {
8216 int input_slot_index = iterator.Next();
8217 PrintF(out, "{input=%d}", input_slot_index);
8218 break;
8219 }
8220
8221 case Translation::DOUBLE_STACK_SLOT: {
8222 int input_slot_index = iterator.Next();
8223 PrintF(out, "{input=%d}", input_slot_index);
8224 break;
8225 }
8226
8227 case Translation::LITERAL: {
8228 unsigned literal_index = iterator.Next();
8229 PrintF(out, "{literal_id=%u}", literal_index);
8230 break;
8231 }
8232
8233 case Translation::ARGUMENTS_OBJECT:
8234 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01008235 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008236 PrintF(out, "\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01008237 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008238 }
8239}
8240
8241
8242void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
8243 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
8244 this->DeoptPoints());
8245 if (this->DeoptPoints() == 0) return;
8246
8247 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
8248 for (int i = 0; i < this->DeoptPoints(); i++) {
8249 int pc_and_state = this->PcAndState(i)->value();
8250 PrintF("%6d %8d %s\n",
8251 this->AstId(i)->value(),
8252 FullCodeGenerator::PcField::decode(pc_and_state),
8253 FullCodeGenerator::State2String(
8254 FullCodeGenerator::StateField::decode(pc_and_state)));
8255 }
8256}
8257
Ben Murdochb0fe1622011-05-05 13:52:32 +01008258
Steve Blocka7e24c12009-10-30 11:49:00 +00008259// Identify kind of code.
8260const char* Code::Kind2String(Kind kind) {
8261 switch (kind) {
8262 case FUNCTION: return "FUNCTION";
Ben Murdochb0fe1622011-05-05 13:52:32 +01008263 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
Steve Blocka7e24c12009-10-30 11:49:00 +00008264 case STUB: return "STUB";
8265 case BUILTIN: return "BUILTIN";
8266 case LOAD_IC: return "LOAD_IC";
8267 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
8268 case STORE_IC: return "STORE_IC";
8269 case KEYED_STORE_IC: return "KEYED_STORE_IC";
8270 case CALL_IC: return "CALL_IC";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008271 case KEYED_CALL_IC: return "KEYED_CALL_IC";
Ben Murdoch257744e2011-11-30 15:57:28 +00008272 case UNARY_OP_IC: return "UNARY_OP_IC";
8273 case BINARY_OP_IC: return "BINARY_OP_IC";
Ben Murdochb0fe1622011-05-05 13:52:32 +01008274 case COMPARE_IC: return "COMPARE_IC";
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008275 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00008276 }
8277 UNREACHABLE();
8278 return NULL;
8279}
8280
8281
8282const char* Code::ICState2String(InlineCacheState state) {
8283 switch (state) {
8284 case UNINITIALIZED: return "UNINITIALIZED";
8285 case PREMONOMORPHIC: return "PREMONOMORPHIC";
8286 case MONOMORPHIC: return "MONOMORPHIC";
8287 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
8288 case MEGAMORPHIC: return "MEGAMORPHIC";
8289 case DEBUG_BREAK: return "DEBUG_BREAK";
8290 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
8291 }
8292 UNREACHABLE();
8293 return NULL;
8294}
8295
8296
8297const char* Code::PropertyType2String(PropertyType type) {
8298 switch (type) {
8299 case NORMAL: return "NORMAL";
8300 case FIELD: return "FIELD";
8301 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
8302 case CALLBACKS: return "CALLBACKS";
Ben Murdoch257744e2011-11-30 15:57:28 +00008303 case HANDLER: return "HANDLER";
Steve Blocka7e24c12009-10-30 11:49:00 +00008304 case INTERCEPTOR: return "INTERCEPTOR";
8305 case MAP_TRANSITION: return "MAP_TRANSITION";
Ben Murdoch589d6972011-11-30 16:04:58 +00008306 case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
Steve Blocka7e24c12009-10-30 11:49:00 +00008307 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
8308 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
8309 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008310 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +00008311 return NULL;
8312}
8313
Ben Murdochb0fe1622011-05-05 13:52:32 +01008314
Steve Block1e0659c2011-05-24 12:43:12 +01008315void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
8316 const char* name = NULL;
8317 switch (kind) {
8318 case CALL_IC:
8319 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
8320 name = "STRING_INDEX_OUT_OF_BOUNDS";
8321 }
8322 break;
8323 case STORE_IC:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008324 case KEYED_STORE_IC:
8325 if (extra == kStrictMode) {
Steve Block1e0659c2011-05-24 12:43:12 +01008326 name = "STRICT";
8327 }
8328 break;
8329 default:
8330 break;
8331 }
8332 if (name != NULL) {
8333 PrintF(out, "extra_ic_state = %s\n", name);
8334 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008335 PrintF(out, "extra_ic_state = %d\n", extra);
Steve Block1e0659c2011-05-24 12:43:12 +01008336 }
8337}
8338
8339
Ben Murdochb0fe1622011-05-05 13:52:32 +01008340void Code::Disassemble(const char* name, FILE* out) {
8341 PrintF(out, "kind = %s\n", Kind2String(kind()));
Steve Blocka7e24c12009-10-30 11:49:00 +00008342 if (is_inline_cache_stub()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008343 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
Steve Block1e0659c2011-05-24 12:43:12 +01008344 PrintExtraICState(out, kind(), extra_ic_state());
Steve Blocka7e24c12009-10-30 11:49:00 +00008345 if (ic_state() == MONOMORPHIC) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008346 PrintF(out, "type = %s\n", PropertyType2String(type()));
Steve Blocka7e24c12009-10-30 11:49:00 +00008347 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008348 if (is_call_stub() || is_keyed_call_stub()) {
8349 PrintF(out, "argc = %d\n", arguments_count());
8350 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008351 }
8352 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008353 PrintF(out, "name = %s\n", name);
8354 }
8355 if (kind() == OPTIMIZED_FUNCTION) {
8356 PrintF(out, "stack_slots = %d\n", stack_slots());
Steve Blocka7e24c12009-10-30 11:49:00 +00008357 }
8358
Ben Murdochb0fe1622011-05-05 13:52:32 +01008359 PrintF(out, "Instructions (size = %d)\n", instruction_size());
8360 Disassembler::Decode(out, this);
8361 PrintF(out, "\n");
8362
Ben Murdochb0fe1622011-05-05 13:52:32 +01008363 if (kind() == FUNCTION) {
8364 DeoptimizationOutputData* data =
8365 DeoptimizationOutputData::cast(this->deoptimization_data());
8366 data->DeoptimizationOutputDataPrint(out);
8367 } else if (kind() == OPTIMIZED_FUNCTION) {
8368 DeoptimizationInputData* data =
8369 DeoptimizationInputData::cast(this->deoptimization_data());
8370 data->DeoptimizationInputDataPrint(out);
8371 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008372 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01008373
8374 if (kind() == OPTIMIZED_FUNCTION) {
8375 SafepointTable table(this);
8376 PrintF(out, "Safepoints (size = %u)\n", table.size());
8377 for (unsigned i = 0; i < table.length(); i++) {
8378 unsigned pc_offset = table.GetPcOffset(i);
8379 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
8380 table.PrintEntry(i);
8381 PrintF(out, " (sp -> fp)");
Ben Murdochb8e0da22011-05-16 14:20:40 +01008382 SafepointEntry entry = table.GetEntry(i);
8383 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
8384 PrintF(out, " %6d", entry.deoptimization_index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008385 } else {
8386 PrintF(out, " <none>");
8387 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01008388 if (entry.argument_count() > 0) {
8389 PrintF(out, " argc: %d", entry.argument_count());
8390 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008391 PrintF(out, "\n");
8392 }
8393 PrintF(out, "\n");
8394 } else if (kind() == FUNCTION) {
Steve Block1e0659c2011-05-24 12:43:12 +01008395 unsigned offset = stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01008396 // If there is no stack check table, the "table start" will at or after
8397 // (due to alignment) the end of the instruction stream.
8398 if (static_cast<int>(offset) < instruction_size()) {
8399 unsigned* address =
8400 reinterpret_cast<unsigned*>(instruction_start() + offset);
8401 unsigned length = address[0];
8402 PrintF(out, "Stack checks (size = %u)\n", length);
8403 PrintF(out, "ast_id pc_offset\n");
8404 for (unsigned i = 0; i < length; ++i) {
8405 unsigned index = (2 * i) + 1;
8406 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
8407 }
8408 PrintF(out, "\n");
8409 }
8410 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008411
8412 PrintF("RelocInfo (size = %d)\n", relocation_size());
Ben Murdochb0fe1622011-05-05 13:52:32 +01008413 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
8414 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00008415}
8416#endif // ENABLE_DISASSEMBLER
8417
8418
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008419MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8420 int capacity,
8421 int length,
8422 SetFastElementsCapacityMode set_capacity_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01008423 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00008424 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01008425 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01008426
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008427 // Allocate a new fast elements backing store.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008428 FixedArray* new_elements;
8429 { MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
8430 if (!maybe->To(&new_elements)) return maybe;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008431 }
8432
8433 // Find the new map to use for this object if there is a map change.
8434 Map* new_map = NULL;
8435 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008436 // The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces
8437 // it, or if it's allowed and the old elements array contained only SMIs.
8438 bool has_fast_smi_only_elements =
8439 (set_capacity_mode == kForceSmiOnlyElements) ||
8440 ((set_capacity_mode == kAllowSmiOnlyElements) &&
8441 (elements()->map()->has_fast_smi_only_elements() ||
8442 elements() == heap->empty_fixed_array()));
8443 ElementsKind elements_kind = has_fast_smi_only_elements
8444 ? FAST_SMI_ONLY_ELEMENTS
8445 : FAST_ELEMENTS;
8446 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), elements_kind);
8447 if (!maybe->To(&new_map)) return maybe;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008448 }
8449
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008450 FixedArrayBase* old_elements = elements();
8451 ElementsKind elements_kind = GetElementsKind();
8452 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
8453 ElementsKind to_kind = (elements_kind == FAST_SMI_ONLY_ELEMENTS)
8454 ? FAST_SMI_ONLY_ELEMENTS
8455 : FAST_ELEMENTS;
8456 // int copy_size = Min(old_elements_raw->length(), new_elements->length());
8457 accessor->CopyElements(this, new_elements, to_kind);
8458 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
8459 set_map_and_elements(new_map, new_elements);
8460 } else {
8461 FixedArray* parameter_map = FixedArray::cast(old_elements);
8462 parameter_map->set(1, new_elements);
8463 }
8464
8465 if (FLAG_trace_elements_transitions) {
8466 PrintElementsTransition(stdout, elements_kind, old_elements,
8467 GetElementsKind(), new_elements);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008468 }
8469
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008470 // Update the length if necessary.
8471 if (IsJSArray()) {
8472 JSArray::cast(this)->set_length(Smi::FromInt(length));
8473 }
8474
8475 return new_elements;
8476}
8477
8478
8479MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
8480 int capacity,
8481 int length) {
8482 Heap* heap = GetHeap();
8483 // We should never end in here with a pixel or external array.
8484 ASSERT(!HasExternalArrayElements());
8485
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008486 FixedDoubleArray* elems;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008487 { MaybeObject* maybe_obj =
8488 heap->AllocateUninitializedFixedDoubleArray(capacity);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008489 if (!maybe_obj->To(&elems)) return maybe_obj;
John Reck59135872010-11-02 12:39:01 -07008490 }
Steve Block8defd9f2010-07-08 12:39:36 +01008491
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008492 Map* new_map;
8493 { MaybeObject* maybe_obj =
8494 GetElementsTransitionMap(heap->isolate(), FAST_DOUBLE_ELEMENTS);
8495 if (!maybe_obj->To(&new_map)) return maybe_obj;
8496 }
8497
8498 FixedArrayBase* old_elements = elements();
8499 ElementsKind elements_kind = GetElementsKind();
8500 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
8501 accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS);
8502 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
8503 set_map_and_elements(new_map, elems);
8504 } else {
8505 FixedArray* parameter_map = FixedArray::cast(old_elements);
8506 parameter_map->set(1, elems);
8507 }
8508
8509 if (FLAG_trace_elements_transitions) {
8510 PrintElementsTransition(stdout, elements_kind, old_elements,
8511 FAST_DOUBLE_ELEMENTS, elems);
8512 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008513
Steve Block8defd9f2010-07-08 12:39:36 +01008514 if (IsJSArray()) {
8515 JSArray::cast(this)->set_length(Smi::FromInt(length));
8516 }
8517
8518 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00008519}
8520
8521
John Reck59135872010-11-02 12:39:01 -07008522MaybeObject* JSArray::Initialize(int capacity) {
Steve Block44f0eee2011-05-26 01:26:41 +01008523 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008524 ASSERT(capacity >= 0);
Leon Clarke4515c472010-02-03 11:58:03 +00008525 set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00008526 FixedArray* new_elements;
8527 if (capacity == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01008528 new_elements = heap->empty_fixed_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00008529 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008530 MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
8531 if (!maybe_obj->To(&new_elements)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00008532 }
8533 set_elements(new_elements);
8534 return this;
8535}
8536
8537
8538void JSArray::Expand(int required_size) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008539 GetIsolate()->factory()->SetElementsCapacityAndLength(
8540 Handle<JSArray>(this), required_size, required_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00008541}
8542
8543
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008544MaybeObject* JSArray::SetElementsLength(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00008545 // We should never end in here with a pixel or external array.
Steve Block6ded16b2010-05-10 14:33:55 +01008546 ASSERT(AllowsSetElementsLength());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008547 return GetElementsAccessor()->SetLength(this, len);
Steve Blocka7e24c12009-10-30 11:49:00 +00008548}
8549
8550
Steve Block053d10c2011-06-13 19:13:29 +01008551Object* Map::GetPrototypeTransition(Object* prototype) {
8552 FixedArray* cache = prototype_transitions();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008553 int number_of_transitions = NumberOfProtoTransitions();
8554 const int proto_offset =
8555 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
8556 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
8557 const int step = kProtoTransitionElementsPerEntry;
8558 for (int i = 0; i < number_of_transitions; i++) {
8559 if (cache->get(proto_offset + i * step) == prototype) {
8560 Object* map = cache->get(map_offset + i * step);
8561 ASSERT(map->IsMap());
8562 return map;
8563 }
Steve Block053d10c2011-06-13 19:13:29 +01008564 }
8565 return NULL;
8566}
8567
8568
8569MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008570 ASSERT(map->IsMap());
8571 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
Steve Block053d10c2011-06-13 19:13:29 +01008572 // Don't cache prototype transition if this map is shared.
8573 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
8574
8575 FixedArray* cache = prototype_transitions();
8576
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008577 const int step = kProtoTransitionElementsPerEntry;
8578 const int header = kProtoTransitionHeaderSize;
Steve Block053d10c2011-06-13 19:13:29 +01008579
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008580 int capacity = (cache->length() - header) / step;
Steve Block053d10c2011-06-13 19:13:29 +01008581
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008582 int transitions = NumberOfProtoTransitions() + 1;
8583
8584 if (transitions > capacity) {
Steve Block053d10c2011-06-13 19:13:29 +01008585 if (capacity > kMaxCachedPrototypeTransitions) return this;
8586
8587 FixedArray* new_cache;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008588 // Grow array by factor 2 over and above what we need.
8589 { MaybeObject* maybe_cache =
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008590 GetHeap()->AllocateFixedArray(transitions * 2 * step + header);
8591 if (!maybe_cache->To(&new_cache)) return maybe_cache;
Steve Block053d10c2011-06-13 19:13:29 +01008592 }
8593
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008594 for (int i = 0; i < capacity * step; i++) {
8595 new_cache->set(i + header, cache->get(i + header));
8596 }
Steve Block053d10c2011-06-13 19:13:29 +01008597 cache = new_cache;
8598 set_prototype_transitions(cache);
8599 }
8600
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008601 int last = transitions - 1;
8602
8603 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
8604 cache->set(header + last * step + kProtoTransitionMapOffset, map);
8605 SetNumberOfProtoTransitions(transitions);
Steve Block053d10c2011-06-13 19:13:29 +01008606
8607 return cache;
8608}
8609
8610
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008611MaybeObject* JSReceiver::SetPrototype(Object* value,
8612 bool skip_hidden_prototypes) {
8613#ifdef DEBUG
8614 int size = Size();
8615#endif
8616
Steve Block44f0eee2011-05-26 01:26:41 +01008617 Heap* heap = GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +00008618 // Silently ignore the change if value is not a JSObject or null.
8619 // SpiderMonkey behaves this way.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008620 if (!value->IsJSReceiver() && !value->IsNull()) return value;
Andrei Popescu402d9372010-02-26 13:31:12 +00008621
Ben Murdoch8b112d22011-06-08 16:22:53 +01008622 // From 8.6.2 Object Internal Methods
8623 // ...
8624 // In addition, if [[Extensible]] is false the value of the [[Class]] and
8625 // [[Prototype]] internal properties of the object may not be modified.
8626 // ...
8627 // Implementation specific extensions that modify [[Class]], [[Prototype]]
8628 // or [[Extensible]] must not violate the invariants defined in the preceding
8629 // paragraph.
8630 if (!this->map()->is_extensible()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008631 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01008632 Handle<Object> handle(this, heap->isolate());
8633 return heap->isolate()->Throw(
8634 *FACTORY->NewTypeError("non_extensible_proto",
8635 HandleVector<Object>(&handle, 1)));
8636 }
8637
Andrei Popescu402d9372010-02-26 13:31:12 +00008638 // Before we can set the prototype we need to be sure
8639 // prototype cycles are prevented.
8640 // It is sufficient to validate that the receiver is not in the new prototype
8641 // chain.
Steve Block44f0eee2011-05-26 01:26:41 +01008642 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008643 if (JSReceiver::cast(pt) == this) {
Andrei Popescu402d9372010-02-26 13:31:12 +00008644 // Cycle detected.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008645 HandleScope scope(heap->isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01008646 return heap->isolate()->Throw(
8647 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
Andrei Popescu402d9372010-02-26 13:31:12 +00008648 }
8649 }
8650
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008651 JSReceiver* real_receiver = this;
Andrei Popescu402d9372010-02-26 13:31:12 +00008652
8653 if (skip_hidden_prototypes) {
8654 // Find the first object in the chain whose prototype object is not
8655 // hidden and set the new prototype on that object.
8656 Object* current_proto = real_receiver->GetPrototype();
8657 while (current_proto->IsJSObject() &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008658 JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) {
8659 real_receiver = JSReceiver::cast(current_proto);
Andrei Popescu402d9372010-02-26 13:31:12 +00008660 current_proto = current_proto->GetPrototype();
8661 }
8662 }
8663
8664 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +01008665 Map* map = real_receiver->map();
8666
8667 // Nothing to do if prototype is already set.
8668 if (map->prototype() == value) return value;
8669
8670 Object* new_map = map->GetPrototypeTransition(value);
8671 if (new_map == NULL) {
8672 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
8673 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
8674 }
8675
8676 { MaybeObject* maybe_new_cache =
8677 map->PutPrototypeTransition(value, Map::cast(new_map));
8678 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
8679 }
8680
8681 Map::cast(new_map)->set_prototype(value);
John Reck59135872010-11-02 12:39:01 -07008682 }
Steve Block053d10c2011-06-13 19:13:29 +01008683 ASSERT(Map::cast(new_map)->prototype() == value);
Andrei Popescu402d9372010-02-26 13:31:12 +00008684 real_receiver->set_map(Map::cast(new_map));
8685
Steve Block44f0eee2011-05-26 01:26:41 +01008686 heap->ClearInstanceofCache();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008687 ASSERT(size == Size());
Andrei Popescu402d9372010-02-26 13:31:12 +00008688 return value;
8689}
8690
8691
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008692MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
8693 uint32_t first_arg,
8694 uint32_t arg_count,
8695 EnsureElementsMode mode) {
8696 // Elements in |Arguments| are ordered backwards (because they're on the
8697 // stack), but the method that's called here iterates over them in forward
8698 // direction.
8699 return EnsureCanContainElements(
8700 args->arguments() - first_arg - (arg_count - 1),
8701 arg_count, mode);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00008702}
8703
8704
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008705bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01008706 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008707 // Make sure that the top context does not change when doing
8708 // callbacks or interceptor calls.
8709 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008710 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008711 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008712 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00008713 Handle<JSObject> holder_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01008714 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008715 v8::AccessorInfo info(args.end());
8716 if (!interceptor->query()->IsUndefined()) {
8717 v8::IndexedPropertyQuery query =
8718 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01008719 LOG(isolate,
8720 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
Iain Merrick75681382010-08-19 15:07:18 +01008721 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00008722 {
8723 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008724 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008725 result = query(index, info);
8726 }
Iain Merrick75681382010-08-19 15:07:18 +01008727 if (!result.IsEmpty()) {
8728 ASSERT(result->IsInt32());
8729 return true; // absence of property is signaled by empty handle.
8730 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008731 } else if (!interceptor->getter()->IsUndefined()) {
8732 v8::IndexedPropertyGetter getter =
8733 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008734 LOG(isolate,
8735 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
Steve Blocka7e24c12009-10-30 11:49:00 +00008736 v8::Handle<v8::Value> result;
8737 {
8738 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008739 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008740 result = getter(index, info);
8741 }
8742 if (!result.IsEmpty()) return true;
8743 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008744
8745 if (holder_handle->GetElementsAccessor()->HasElement(
8746 *receiver_handle, *holder_handle, index)) {
8747 return true;
8748 }
8749
8750 if (holder_handle->IsStringObjectWithCharacterAt(index)) return true;
8751 Object* pt = holder_handle->GetPrototype();
8752 if (pt->IsJSProxy()) {
8753 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8754 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8755 receiver, index) != ABSENT;
8756 }
8757 if (pt->IsNull()) return false;
8758 return JSObject::cast(pt)->HasElementWithReceiver(*receiver_handle, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00008759}
8760
8761
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008762JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008763 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008764 if (IsAccessCheckNeeded()) {
8765 Heap* heap = GetHeap();
8766 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8767 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8768 return UNDEFINED_ELEMENT;
8769 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008770 }
8771
Steve Block1e0659c2011-05-24 12:43:12 +01008772 if (IsJSGlobalProxy()) {
8773 Object* proto = GetPrototype();
8774 if (proto->IsNull()) return UNDEFINED_ELEMENT;
8775 ASSERT(proto->IsJSGlobalObject());
8776 return JSObject::cast(proto)->HasLocalElement(index);
8777 }
8778
Steve Blocka7e24c12009-10-30 11:49:00 +00008779 // Check for lookup interceptor
8780 if (HasIndexedInterceptor()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008781 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
8782 : UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00008783 }
8784
8785 // Handle [] on String objects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008786 if (this->IsStringObjectWithCharacterAt(index)) {
8787 return STRING_CHARACTER_ELEMENT;
8788 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008789
8790 switch (GetElementsKind()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008791 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00008792 case FAST_ELEMENTS: {
8793 uint32_t length = IsJSArray() ?
8794 static_cast<uint32_t>
8795 (Smi::cast(JSArray::cast(this)->length())->value()) :
8796 static_cast<uint32_t>(FixedArray::cast(elements())->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008797 if ((index < length) &&
8798 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8799 return FAST_ELEMENT;
8800 }
8801 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008802 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008803 case FAST_DOUBLE_ELEMENTS: {
8804 uint32_t length = IsJSArray() ?
8805 static_cast<uint32_t>
8806 (Smi::cast(JSArray::cast(this)->length())->value()) :
8807 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8808 if ((index < length) &&
8809 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
8810 return FAST_ELEMENT;
8811 }
8812 break;
8813 }
Steve Block44f0eee2011-05-26 01:26:41 +01008814 case EXTERNAL_PIXEL_ELEMENTS: {
8815 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008816 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
8817 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008818 }
Steve Block3ce2e202009-11-05 08:53:23 +00008819 case EXTERNAL_BYTE_ELEMENTS:
8820 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8821 case EXTERNAL_SHORT_ELEMENTS:
8822 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8823 case EXTERNAL_INT_ELEMENTS:
8824 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008825 case EXTERNAL_FLOAT_ELEMENTS:
8826 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008827 ExternalArray* array = ExternalArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008828 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
8829 break;
Steve Block3ce2e202009-11-05 08:53:23 +00008830 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008831 case DICTIONARY_ELEMENTS: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008832 if (element_dictionary()->FindEntry(index) !=
Ben Murdochc7cc0282012-03-05 14:35:55 +00008833 SeededNumberDictionary::kNotFound) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008834 return DICTIONARY_ELEMENT;
8835 }
8836 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008837 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008838 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8839 // Aliased parameters and non-aliased elements in a fast backing store
8840 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
8841 // backing store behave as DICTIONARY_ELEMENT.
8842 FixedArray* parameter_map = FixedArray::cast(elements());
8843 uint32_t length = parameter_map->length();
8844 Object* probe =
8845 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
8846 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8847 // If not aliased, check the arguments.
8848 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8849 if (arguments->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00008850 SeededNumberDictionary* dictionary =
8851 SeededNumberDictionary::cast(arguments);
8852 if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008853 return DICTIONARY_ELEMENT;
8854 }
8855 } else {
8856 length = arguments->length();
8857 probe = (index < length) ? arguments->get(index) : NULL;
8858 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8859 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008860 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008861 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008862 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008863
8864 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00008865}
8866
8867
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008868bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008869 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008870 if (IsAccessCheckNeeded()) {
8871 Heap* heap = GetHeap();
8872 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8873 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8874 return false;
8875 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008876 }
8877
8878 // Check for lookup interceptor
8879 if (HasIndexedInterceptor()) {
8880 return HasElementWithInterceptor(receiver, index);
8881 }
8882
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008883 ElementsAccessor* accessor = GetElementsAccessor();
8884 if (accessor->HasElement(receiver, this, index)) {
8885 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00008886 }
8887
8888 // Handle [] on String objects.
8889 if (this->IsStringObjectWithCharacterAt(index)) return true;
8890
8891 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01008892 if (pt->IsNull()) return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008893 if (pt->IsJSProxy()) {
8894 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8895 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8896 receiver, index) != ABSENT;
8897 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008898 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8899}
8900
8901
John Reck59135872010-11-02 12:39:01 -07008902MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01008903 Object* value,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008904 PropertyAttributes attributes,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008905 StrictModeFlag strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008906 bool check_prototype,
8907 SetPropertyMode set_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01008908 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008909 // Make sure that the top context does not change when doing
8910 // callbacks or interceptor calls.
8911 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008912 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008913 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8914 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01008915 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008916 if (!interceptor->setter()->IsUndefined()) {
8917 v8::IndexedPropertySetter setter =
8918 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +01008919 LOG(isolate,
8920 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
8921 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008922 v8::AccessorInfo info(args.end());
8923 v8::Handle<v8::Value> result;
8924 {
8925 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008926 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008927 result = setter(index, v8::Utils::ToLocal(value_handle), info);
8928 }
Steve Block44f0eee2011-05-26 01:26:41 +01008929 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008930 if (!result.IsEmpty()) return *value_handle;
8931 }
John Reck59135872010-11-02 12:39:01 -07008932 MaybeObject* raw_result =
Steve Block9fac8402011-05-12 15:51:54 +01008933 this_handle->SetElementWithoutInterceptor(index,
8934 *value_handle,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008935 attributes,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008936 strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008937 check_prototype,
8938 set_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01008939 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008940 return raw_result;
8941}
8942
8943
John Reck59135872010-11-02 12:39:01 -07008944MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
8945 Object* structure,
8946 uint32_t index,
8947 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01008948 Isolate* isolate = GetIsolate();
Ben Murdoch257744e2011-11-30 15:57:28 +00008949 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01008950
8951 // api style callbacks.
8952 if (structure->IsAccessorInfo()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00008953 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01008954 Object* fun_obj = data->getter();
8955 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Steve Block44f0eee2011-05-26 01:26:41 +01008956 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008957 Handle<JSObject> self(JSObject::cast(receiver));
8958 Handle<JSObject> holder_handle(JSObject::cast(holder));
Steve Block44f0eee2011-05-26 01:26:41 +01008959 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008960 Handle<String> key = isolate->factory()->NumberToString(number);
Steve Block44f0eee2011-05-26 01:26:41 +01008961 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
8962 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01008963 v8::AccessorInfo info(args.end());
8964 v8::Handle<v8::Value> result;
8965 {
8966 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008967 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01008968 result = call_fun(v8::Utils::ToLocal(key), info);
8969 }
Steve Block44f0eee2011-05-26 01:26:41 +01008970 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8971 if (result.IsEmpty()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008972 return *v8::Utils::OpenHandle(*result);
8973 }
8974
8975 // __defineGetter__ callback
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008976 if (structure->IsAccessorPair()) {
8977 Object* getter = AccessorPair::cast(structure)->getter();
8978 if (getter->IsSpecFunction()) {
8979 // TODO(rossberg): nicer would be to cast to some JSCallable here...
8980 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
Leon Clarkef7060e22010-06-03 12:02:55 +01008981 }
8982 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +01008983 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008984 }
8985
8986 UNREACHABLE();
8987 return NULL;
8988}
8989
8990
John Reck59135872010-11-02 12:39:01 -07008991MaybeObject* JSObject::SetElementWithCallback(Object* structure,
8992 uint32_t index,
8993 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008994 JSObject* holder,
8995 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01008996 Isolate* isolate = GetIsolate();
8997 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008998
8999 // We should never get here to initialize a const with the hole
9000 // value since a const declaration would conflict with the setter.
9001 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01009002 Handle<Object> value_handle(value, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01009003
9004 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00009005 // data structure used to store the callbacks. Eventually foreign
Leon Clarkef7060e22010-06-03 12:02:55 +01009006 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00009007 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01009008
9009 if (structure->IsAccessorInfo()) {
9010 // api style callbacks
Ben Murdoch257744e2011-11-30 15:57:28 +00009011 Handle<JSObject> self(this);
9012 Handle<JSObject> holder_handle(JSObject::cast(holder));
9013 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01009014 Object* call_obj = data->setter();
9015 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
9016 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +01009017 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9018 Handle<String> key(isolate->factory()->NumberToString(number));
Ben Murdoch257744e2011-11-30 15:57:28 +00009019 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
9020 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01009021 v8::AccessorInfo info(args.end());
9022 {
9023 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01009024 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01009025 call_fun(v8::Utils::ToLocal(key),
9026 v8::Utils::ToLocal(value_handle),
9027 info);
9028 }
Steve Block44f0eee2011-05-26 01:26:41 +01009029 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01009030 return *value_handle;
9031 }
9032
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009033 if (structure->IsAccessorPair()) {
9034 Handle<Object> setter(AccessorPair::cast(structure)->setter());
9035 if (setter->IsSpecFunction()) {
9036 // TODO(rossberg): nicer would be to cast to some JSCallable here...
9037 return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
Leon Clarkef7060e22010-06-03 12:02:55 +01009038 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009039 if (strict_mode == kNonStrictMode) {
9040 return value;
9041 }
Steve Block44f0eee2011-05-26 01:26:41 +01009042 Handle<Object> holder_handle(holder, isolate);
9043 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Leon Clarkef7060e22010-06-03 12:02:55 +01009044 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01009045 return isolate->Throw(
9046 *isolate->factory()->NewTypeError("no_setter_in_callback",
9047 HandleVector(args, 2)));
Leon Clarkef7060e22010-06-03 12:02:55 +01009048 }
9049 }
9050
9051 UNREACHABLE();
9052 return NULL;
9053}
9054
9055
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009056bool JSObject::HasFastArgumentsElements() {
9057 Heap* heap = GetHeap();
9058 if (!elements()->IsFixedArray()) return false;
9059 FixedArray* elements = FixedArray::cast(this->elements());
9060 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9061 return false;
9062 }
9063 FixedArray* arguments = FixedArray::cast(elements->get(1));
9064 return !arguments->IsDictionary();
9065}
9066
9067
9068bool JSObject::HasDictionaryArgumentsElements() {
9069 Heap* heap = GetHeap();
9070 if (!elements()->IsFixedArray()) return false;
9071 FixedArray* elements = FixedArray::cast(this->elements());
9072 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9073 return false;
9074 }
9075 FixedArray* arguments = FixedArray::cast(elements->get(1));
9076 return arguments->IsDictionary();
9077}
9078
9079
Steve Blocka7e24c12009-10-30 11:49:00 +00009080// Adding n elements in fast case is O(n*n).
9081// Note: revisit design to have dual undefined values to capture absent
9082// elements.
Steve Block9fac8402011-05-12 15:51:54 +01009083MaybeObject* JSObject::SetFastElement(uint32_t index,
9084 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009085 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01009086 bool check_prototype) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009087 ASSERT(HasFastTypeElements() ||
9088 HasFastArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009089
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009090 FixedArray* backing_store = FixedArray::cast(elements());
9091 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
9092 backing_store = FixedArray::cast(backing_store->get(1));
9093 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009094 MaybeObject* maybe = EnsureWritableFastElements();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009095 if (!maybe->To(&backing_store)) return maybe;
John Reck59135872010-11-02 12:39:01 -07009096 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009097 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00009098
Steve Block9fac8402011-05-12 15:51:54 +01009099 if (check_prototype &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009100 (index >= capacity || backing_store->get(index)->IsTheHole())) {
Steve Block1e0659c2011-05-24 12:43:12 +01009101 bool found;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009102 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9103 value,
9104 &found,
9105 strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +01009106 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00009107 }
9108
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009109 uint32_t new_capacity = capacity;
9110 // Check if the length property of this object needs to be updated.
9111 uint32_t array_length = 0;
9112 bool must_update_array_length = false;
9113 if (IsJSArray()) {
9114 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9115 if (index >= array_length) {
9116 must_update_array_length = true;
9117 array_length = index + 1;
9118 }
9119 }
9120 // Check if the capacity of the backing store needs to be increased, or if
9121 // a transition to slow elements is necessary.
9122 if (index >= capacity) {
9123 bool convert_to_slow = true;
9124 if ((index - capacity) < kMaxGap) {
9125 new_capacity = NewElementsCapacity(index + 1);
9126 ASSERT(new_capacity > index);
9127 if (!ShouldConvertToSlowElements(new_capacity)) {
9128 convert_to_slow = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009129 }
9130 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009131 if (convert_to_slow) {
9132 MaybeObject* result = NormalizeElements();
9133 if (result->IsFailure()) return result;
9134 return SetDictionaryElement(index, value, NONE, strict_mode,
9135 check_prototype);
Ben Murdoch592a9fc2012-03-05 11:04:45 +00009136 }
9137 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009138 // Convert to fast double elements if appropriate.
9139 if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) {
9140 MaybeObject* maybe =
9141 SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
9142 if (maybe->IsFailure()) return maybe;
9143 FixedDoubleArray::cast(elements())->set(index, value->Number());
9144 return value;
9145 }
9146 // Change elements kind from SMI_ONLY to generic FAST if necessary.
9147 if (HasFastSmiOnlyElements() && !value->IsSmi()) {
9148 Map* new_map;
9149 { MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
9150 FAST_ELEMENTS);
9151 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9152 }
9153 set_map(new_map);
9154 if (FLAG_trace_elements_transitions) {
9155 PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
9156 FAST_ELEMENTS, elements());
9157 }
9158 }
9159 // Increase backing store capacity if that's been decided previously.
9160 if (new_capacity != capacity) {
9161 FixedArray* new_elements;
9162 SetFastElementsCapacityMode set_capacity_mode =
9163 value->IsSmi() && HasFastSmiOnlyElements()
9164 ? kAllowSmiOnlyElements
9165 : kDontAllowSmiOnlyElements;
9166 { MaybeObject* maybe =
9167 SetFastElementsCapacityAndLength(new_capacity,
9168 array_length,
9169 set_capacity_mode);
9170 if (!maybe->To(&new_elements)) return maybe;
9171 }
9172 new_elements->set(index, value);
9173 return value;
9174 }
9175 // Finally, set the new element and length.
9176 ASSERT(elements()->IsFixedArray());
9177 backing_store->set(index, value);
9178 if (must_update_array_length) {
9179 JSArray::cast(this)->set_length(Smi::FromInt(array_length));
9180 }
9181 return value;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009182}
9183
9184
9185MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
9186 Object* value,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009187 PropertyAttributes attributes,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009188 StrictModeFlag strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009189 bool check_prototype,
9190 SetPropertyMode set_mode) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009191 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9192 Isolate* isolate = GetIsolate();
9193 Heap* heap = isolate->heap();
9194
9195 // Insert element in the dictionary.
9196 FixedArray* elements = FixedArray::cast(this->elements());
9197 bool is_arguments =
9198 (elements->map() == heap->non_strict_arguments_elements_map());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009199 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009200 if (is_arguments) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009201 dictionary = SeededNumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009202 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009203 dictionary = SeededNumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009204 }
9205
9206 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00009207 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009208 Object* element = dictionary->ValueAt(entry);
9209 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009210 if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009211 return SetElementWithCallback(element, index, value, this, strict_mode);
9212 } else {
9213 dictionary->UpdateMaxNumberKey(index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009214 // If a value has not been initialized we allow writing to it even if it
9215 // is read-only (a declared const that has not been initialized). If a
9216 // value is being defined we skip attribute checks completely.
9217 if (set_mode == DEFINE_PROPERTY) {
9218 details = PropertyDetails(attributes, NORMAL, details.index());
9219 dictionary->DetailsAtPut(entry, details);
9220 } else if (details.IsReadOnly() && !element->IsTheHole()) {
9221 if (strict_mode == kNonStrictMode) {
9222 return isolate->heap()->undefined_value();
9223 } else {
9224 Handle<Object> holder(this);
9225 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9226 Handle<Object> args[2] = { number, holder };
9227 Handle<Object> error =
9228 isolate->factory()->NewTypeError("strict_read_only_property",
9229 HandleVector(args, 2));
9230 return isolate->Throw(*error);
9231 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009232 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009233 // Elements of the arguments object in slow mode might be slow aliases.
9234 if (is_arguments && element->IsAliasedArgumentsEntry()) {
9235 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(element);
9236 Context* context = Context::cast(elements->get(0));
9237 int context_index = entry->aliased_context_slot();
9238 ASSERT(!context->get(context_index)->IsTheHole());
9239 context->set(context_index, value);
9240 // For elements that are still writable we keep slow aliasing.
9241 if (!details.IsReadOnly()) value = element;
9242 }
9243 dictionary->ValueAtPut(entry, value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009244 }
9245 } else {
9246 // Index not already used. Look for an accessor in the prototype chain.
9247 if (check_prototype) {
9248 bool found;
9249 MaybeObject* result =
9250 SetElementWithCallbackSetterInPrototypes(
9251 index, value, &found, strict_mode);
9252 if (found) return result;
9253 }
9254 // When we set the is_extensible flag to false we always force the
9255 // element into dictionary mode (and force them to stay there).
9256 if (!map()->is_extensible()) {
9257 if (strict_mode == kNonStrictMode) {
9258 return isolate->heap()->undefined_value();
9259 } else {
9260 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9261 Handle<String> name = isolate->factory()->NumberToString(number);
9262 Handle<Object> args[1] = { name };
9263 Handle<Object> error =
9264 isolate->factory()->NewTypeError("object_not_extensible",
9265 HandleVector(args, 1));
9266 return isolate->Throw(*error);
9267 }
9268 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009269 FixedArrayBase* new_dictionary;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009270 PropertyDetails details = PropertyDetails(attributes, NORMAL);
9271 MaybeObject* maybe = dictionary->AddNumberEntry(index, value, details);
9272 if (!maybe->To(&new_dictionary)) return maybe;
Ben Murdochc7cc0282012-03-05 14:35:55 +00009273 if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009274 if (is_arguments) {
9275 elements->set(1, new_dictionary);
9276 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009277 set_elements(new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009278 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00009279 dictionary = SeededNumberDictionary::cast(new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009280 }
9281 }
9282
9283 // Update the array length if this JSObject is an array.
9284 if (IsJSArray()) {
9285 MaybeObject* result =
9286 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
9287 if (result->IsFailure()) return result;
9288 }
9289
9290 // Attempt to put this object back in fast case.
9291 if (ShouldConvertToFastElements()) {
9292 uint32_t new_length = 0;
9293 if (IsJSArray()) {
9294 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
9295 } else {
9296 new_length = dictionary->max_number_key() + 1;
9297 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009298 SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays
9299 ? kAllowSmiOnlyElements
9300 : kDontAllowSmiOnlyElements;
9301 bool has_smi_only_elements = false;
9302 bool should_convert_to_fast_double_elements =
9303 ShouldConvertToFastDoubleElements(&has_smi_only_elements);
9304 if (has_smi_only_elements) {
9305 set_capacity_mode = kForceSmiOnlyElements;
9306 }
9307 MaybeObject* result = should_convert_to_fast_double_elements
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009308 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009309 : SetFastElementsCapacityAndLength(new_length,
9310 new_length,
9311 set_capacity_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009312 if (result->IsFailure()) return result;
9313#ifdef DEBUG
9314 if (FLAG_trace_normalization) {
9315 PrintF("Object elements are fast case again:\n");
9316 Print();
9317 }
9318#endif
9319 }
9320 return value;
9321}
9322
9323
9324MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
9325 uint32_t index,
9326 Object* value,
9327 StrictModeFlag strict_mode,
9328 bool check_prototype) {
9329 ASSERT(HasFastDoubleElements());
9330
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009331 FixedArrayBase* base_elms = FixedArrayBase::cast(elements());
9332 uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009333
9334 // If storing to an element that isn't in the array, pass the store request
9335 // up the prototype chain before storing in the receiver's elements.
9336 if (check_prototype &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009337 (index >= elms_length ||
9338 FixedDoubleArray::cast(base_elms)->is_the_hole(index))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009339 bool found;
9340 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9341 value,
9342 &found,
9343 strict_mode);
9344 if (found) return result;
9345 }
9346
9347 // If the value object is not a heap number, switch to fast elements and try
9348 // again.
9349 bool value_is_smi = value->IsSmi();
9350 if (!value->IsNumber()) {
9351 Object* obj;
9352 uint32_t length = elms_length;
9353 if (IsJSArray()) {
9354 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9355 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009356 MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
9357 elms_length,
9358 length,
9359 kDontAllowSmiOnlyElements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009360 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009361 return SetFastElement(index,
9362 value,
9363 strict_mode,
9364 check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009365 }
9366
9367 double double_value = value_is_smi
9368 ? static_cast<double>(Smi::cast(value)->value())
9369 : HeapNumber::cast(value)->value();
9370
9371 // Check whether there is extra space in the fixed array.
Steve Blocka7e24c12009-10-30 11:49:00 +00009372 if (index < elms_length) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009373 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009374 elms->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009375 if (IsJSArray()) {
9376 // Update the length of the array if needed.
9377 uint32_t array_length = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009378 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00009379 if (index >= array_length) {
Leon Clarke4515c472010-02-03 11:58:03 +00009380 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00009381 }
9382 }
9383 return value;
9384 }
9385
9386 // Allow gap in fast case.
9387 if ((index - elms_length) < kMaxGap) {
9388 // Try allocating extra space.
9389 int new_capacity = NewElementsCapacity(index+1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009390 if (!ShouldConvertToSlowElements(new_capacity)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009391 ASSERT(static_cast<uint32_t>(new_capacity) > index);
John Reck59135872010-11-02 12:39:01 -07009392 Object* obj;
9393 { MaybeObject* maybe_obj =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009394 SetFastDoubleElementsCapacityAndLength(new_capacity,
9395 index + 1);
John Reck59135872010-11-02 12:39:01 -07009396 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9397 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009398 FixedDoubleArray::cast(elements())->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009399 return value;
9400 }
9401 }
9402
9403 // Otherwise default to slow case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009404 ASSERT(HasFastDoubleElements());
9405 ASSERT(map()->has_fast_double_elements());
9406 ASSERT(elements()->IsFixedDoubleArray());
John Reck59135872010-11-02 12:39:01 -07009407 Object* obj;
9408 { MaybeObject* maybe_obj = NormalizeElements();
9409 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9410 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009411 ASSERT(HasDictionaryElements());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009412 return SetElement(index, value, NONE, strict_mode, check_prototype);
9413}
9414
9415
9416MaybeObject* JSReceiver::SetElement(uint32_t index,
9417 Object* value,
9418 PropertyAttributes attributes,
9419 StrictModeFlag strict_mode,
9420 bool check_proto) {
9421 if (IsJSProxy()) {
9422 return JSProxy::cast(this)->SetElementWithHandler(
9423 index, value, strict_mode);
9424 } else {
9425 return JSObject::cast(this)->SetElement(
9426 index, value, attributes, strict_mode, check_proto);
9427 }
9428}
9429
9430
9431Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
9432 uint32_t index,
9433 Handle<Object> value,
9434 StrictModeFlag strict_mode) {
9435 ASSERT(!object->HasExternalArrayElements());
9436 CALL_HEAP_FUNCTION(
9437 object->GetIsolate(),
9438 object->SetElement(index, *value, NONE, strict_mode, false),
9439 Object);
9440}
9441
9442
9443Handle<Object> JSObject::SetElement(Handle<JSObject> object,
9444 uint32_t index,
9445 Handle<Object> value,
9446 PropertyAttributes attr,
9447 StrictModeFlag strict_mode,
9448 SetPropertyMode set_mode) {
9449 if (object->HasExternalArrayElements()) {
9450 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
9451 bool has_exception;
9452 Handle<Object> number = Execution::ToNumber(value, &has_exception);
9453 if (has_exception) return Handle<Object>();
9454 value = number;
9455 }
9456 }
9457 CALL_HEAP_FUNCTION(
9458 object->GetIsolate(),
9459 object->SetElement(index, *value, attr, strict_mode, true, set_mode),
9460 Object);
Ben Murdochc7cc0282012-03-05 14:35:55 +00009461}
9462
9463
Steve Block9fac8402011-05-12 15:51:54 +01009464MaybeObject* JSObject::SetElement(uint32_t index,
9465 Object* value,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009466 PropertyAttributes attributes,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009467 StrictModeFlag strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009468 bool check_prototype,
9469 SetPropertyMode set_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009470 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009471 if (IsAccessCheckNeeded()) {
9472 Heap* heap = GetHeap();
9473 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009474 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01009475 Handle<Object> value_handle(value);
9476 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
9477 return *value_handle;
9478 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009479 }
9480
9481 if (IsJSGlobalProxy()) {
9482 Object* proto = GetPrototype();
9483 if (proto->IsNull()) return value;
9484 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009485 return JSObject::cast(proto)->SetElement(index,
9486 value,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009487 attributes,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009488 strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009489 check_prototype,
9490 set_mode);
9491 }
9492
9493 // Don't allow element properties to be redefined for external arrays.
9494 if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) {
9495 Isolate* isolate = GetHeap()->isolate();
9496 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9497 Handle<Object> args[] = { Handle<Object>(this), number };
9498 Handle<Object> error = isolate->factory()->NewTypeError(
9499 "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args)));
9500 return isolate->Throw(*error);
9501 }
9502
9503 // Normalize the elements to enable attributes on the property.
9504 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
9505 SeededNumberDictionary* dictionary;
9506 MaybeObject* maybe_object = NormalizeElements();
9507 if (!maybe_object->To(&dictionary)) return maybe_object;
9508 // Make sure that we never go back to fast case.
9509 dictionary->set_requires_slow_elements();
Steve Blocka7e24c12009-10-30 11:49:00 +00009510 }
9511
9512 // Check for lookup interceptor
9513 if (HasIndexedInterceptor()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009514 return SetElementWithInterceptor(index,
9515 value,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009516 attributes,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009517 strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009518 check_prototype,
9519 set_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009520 }
9521
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009522 return SetElementWithoutInterceptor(index,
9523 value,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009524 attributes,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009525 strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009526 check_prototype,
9527 set_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009528}
9529
9530
John Reck59135872010-11-02 12:39:01 -07009531MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01009532 Object* value,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009533 PropertyAttributes attr,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009534 StrictModeFlag strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009535 bool check_prototype,
9536 SetPropertyMode set_mode) {
9537 ASSERT(HasDictionaryElements() ||
9538 HasDictionaryArgumentsElements() ||
9539 (attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
Steve Block44f0eee2011-05-26 01:26:41 +01009540 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00009541 switch (GetElementsKind()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009542 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00009543 case FAST_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009544 return SetFastElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009545 case FAST_DOUBLE_ELEMENTS:
9546 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01009547 case EXTERNAL_PIXEL_ELEMENTS: {
9548 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009549 return pixels->SetValue(index, value);
9550 }
Steve Block3ce2e202009-11-05 08:53:23 +00009551 case EXTERNAL_BYTE_ELEMENTS: {
9552 ExternalByteArray* array = ExternalByteArray::cast(elements());
9553 return array->SetValue(index, value);
9554 }
9555 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9556 ExternalUnsignedByteArray* array =
9557 ExternalUnsignedByteArray::cast(elements());
9558 return array->SetValue(index, value);
9559 }
9560 case EXTERNAL_SHORT_ELEMENTS: {
9561 ExternalShortArray* array = ExternalShortArray::cast(elements());
9562 return array->SetValue(index, value);
9563 }
9564 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9565 ExternalUnsignedShortArray* array =
9566 ExternalUnsignedShortArray::cast(elements());
9567 return array->SetValue(index, value);
9568 }
9569 case EXTERNAL_INT_ELEMENTS: {
9570 ExternalIntArray* array = ExternalIntArray::cast(elements());
9571 return array->SetValue(index, value);
9572 }
9573 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9574 ExternalUnsignedIntArray* array =
9575 ExternalUnsignedIntArray::cast(elements());
9576 return array->SetValue(index, value);
9577 }
9578 case EXTERNAL_FLOAT_ELEMENTS: {
9579 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
9580 return array->SetValue(index, value);
9581 }
Ben Murdoch257744e2011-11-30 15:57:28 +00009582 case EXTERNAL_DOUBLE_ELEMENTS: {
9583 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
9584 return array->SetValue(index, value);
9585 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009586 case DICTIONARY_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009587 return SetDictionaryElement(index, value, attr, strict_mode,
9588 check_prototype, set_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009589 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9590 FixedArray* parameter_map = FixedArray::cast(elements());
9591 uint32_t length = parameter_map->length();
9592 Object* probe =
9593 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
9594 if (probe != NULL && !probe->IsTheHole()) {
9595 Context* context = Context::cast(parameter_map->get(0));
9596 int context_index = Smi::cast(probe)->value();
9597 ASSERT(!context->get(context_index)->IsTheHole());
9598 context->set(context_index, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009599 // Redefining attributes of an aliased element destroys fast aliasing.
9600 if (set_mode == SET_PROPERTY || attr == NONE) return value;
9601 parameter_map->set_the_hole(index + 2);
9602 // For elements that are still writable we re-establish slow aliasing.
9603 if ((attr & READ_ONLY) == 0) {
9604 MaybeObject* maybe_entry =
9605 isolate->heap()->AllocateAliasedArgumentsEntry(context_index);
9606 if (!maybe_entry->ToObject(&value)) return maybe_entry;
Ben Murdoch85b71792012-04-11 18:30:58 +01009607 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01009608 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009609 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9610 if (arguments->IsDictionary()) {
9611 return SetDictionaryElement(index, value, attr, strict_mode,
9612 check_prototype, set_mode);
9613 } else {
9614 return SetFastElement(index, value, strict_mode, check_prototype);
9615 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009616 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009617 }
9618 // All possible cases have been handled above. Add a return to avoid the
9619 // complaints from the compiler.
9620 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01009621 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009622}
9623
9624
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009625Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
9626 ElementsKind to_kind) {
9627 CALL_HEAP_FUNCTION(object->GetIsolate(),
9628 object->TransitionElementsKind(to_kind),
9629 Object);
9630}
9631
9632
9633MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
9634 ElementsKind from_kind = map()->elements_kind();
9635
9636 Isolate* isolate = GetIsolate();
9637 if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9638 (to_kind == FAST_ELEMENTS ||
9639 elements() == isolate->heap()->empty_fixed_array())) {
9640 MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
9641 Map* new_map;
9642 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9643 set_map(new_map);
9644 if (FLAG_trace_elements_transitions) {
9645 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9646 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
9647 }
9648 return this;
9649 }
9650
9651 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9652 uint32_t capacity = static_cast<uint32_t>(elms->length());
9653 uint32_t length = capacity;
9654
9655 if (IsJSArray()) {
9656 Object* raw_length = JSArray::cast(this)->length();
9657 if (raw_length->IsUndefined()) {
9658 // If length is undefined, then JSArray is being initialized and has no
9659 // elements, assume a length of zero.
9660 length = 0;
9661 } else {
9662 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9663 }
9664 }
9665
9666 if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9667 to_kind == FAST_DOUBLE_ELEMENTS) {
9668 MaybeObject* maybe_result =
9669 SetFastDoubleElementsCapacityAndLength(capacity, length);
9670 if (maybe_result->IsFailure()) return maybe_result;
9671 return this;
9672 }
9673
9674 if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
9675 MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
9676 capacity, length, kDontAllowSmiOnlyElements);
9677 if (maybe_result->IsFailure()) return maybe_result;
9678 return this;
9679 }
9680
9681 // This method should never be called for any other case than the ones
9682 // handled above.
9683 UNREACHABLE();
9684 return GetIsolate()->heap()->null_value();
9685}
9686
9687
9688// static
9689bool Map::IsValidElementsTransition(ElementsKind from_kind,
9690 ElementsKind to_kind) {
9691 return
9692 (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9693 (to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) ||
9694 (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS);
9695}
9696
9697
John Reck59135872010-11-02 12:39:01 -07009698MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
9699 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009700 uint32_t old_len = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009701 CHECK(length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +00009702 // Check to see if we need to update the length. For now, we make
9703 // sure that the length stays within 32-bits (unsigned).
9704 if (index >= old_len && index != 0xffffffff) {
John Reck59135872010-11-02 12:39:01 -07009705 Object* len;
9706 { MaybeObject* maybe_len =
Steve Block44f0eee2011-05-26 01:26:41 +01009707 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
John Reck59135872010-11-02 12:39:01 -07009708 if (!maybe_len->ToObject(&len)) return maybe_len;
9709 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009710 set_length(len);
9711 }
9712 return value;
9713}
9714
9715
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009716MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07009717 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01009718 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00009719 // Make sure that the top context does not change when doing
9720 // callbacks or interceptor calls.
9721 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01009722 HandleScope scope(isolate);
9723 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
9724 Handle<Object> this_handle(receiver, isolate);
9725 Handle<JSObject> holder_handle(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009726 if (!interceptor->getter()->IsUndefined()) {
9727 v8::IndexedPropertyGetter getter =
9728 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01009729 LOG(isolate,
9730 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
9731 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00009732 v8::AccessorInfo info(args.end());
9733 v8::Handle<v8::Value> result;
9734 {
9735 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01009736 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009737 result = getter(index, info);
9738 }
Steve Block44f0eee2011-05-26 01:26:41 +01009739 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009740 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
9741 }
9742
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009743 Heap* heap = holder_handle->GetHeap();
9744 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009745 MaybeObject* raw_result = handler->Get(*this_handle,
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009746 *holder_handle,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009747 index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009748 if (raw_result != heap->the_hole_value()) return raw_result;
9749
Steve Block44f0eee2011-05-26 01:26:41 +01009750 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009751
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009752 Object* pt = holder_handle->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01009753 if (pt == heap->null_value()) return heap->undefined_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009754 return pt->GetElementWithReceiver(*this_handle, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00009755}
9756
9757
9758bool JSObject::HasDenseElements() {
9759 int capacity = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009760 int used = 0;
9761 GetElementsCapacityAndUsage(&capacity, &used);
9762 return (capacity == 0) || (used > (capacity / 2));
9763}
9764
9765
9766void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
9767 *capacity = 0;
9768 *used = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00009769
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009770 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
9771 FixedArray* backing_store = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00009772 switch (GetElementsKind()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009773 case NON_STRICT_ARGUMENTS_ELEMENTS:
9774 backing_store_base =
9775 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
9776 backing_store = FixedArray::cast(backing_store_base);
9777 if (backing_store->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009778 SeededNumberDictionary* dictionary =
9779 SeededNumberDictionary::cast(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009780 *capacity = dictionary->Capacity();
9781 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009782 break;
9783 }
9784 // Fall through.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009785 case FAST_SMI_ONLY_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009786 case FAST_ELEMENTS:
9787 backing_store = FixedArray::cast(backing_store_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009788 *capacity = backing_store->length();
9789 for (int i = 0; i < *capacity; ++i) {
9790 if (!backing_store->get(i)->IsTheHole()) ++(*used);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009791 }
9792 break;
9793 case DICTIONARY_ELEMENTS: {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009794 SeededNumberDictionary* dictionary =
9795 SeededNumberDictionary::cast(FixedArray::cast(elements()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009796 *capacity = dictionary->Capacity();
9797 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009798 break;
9799 }
9800 case FAST_DOUBLE_ELEMENTS: {
9801 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009802 *capacity = elms->length();
9803 for (int i = 0; i < *capacity; i++) {
9804 if (!elms->is_the_hole(i)) ++(*used);
Steve Blocka7e24c12009-10-30 11:49:00 +00009805 }
9806 break;
9807 }
Steve Block3ce2e202009-11-05 08:53:23 +00009808 case EXTERNAL_BYTE_ELEMENTS:
9809 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9810 case EXTERNAL_SHORT_ELEMENTS:
9811 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9812 case EXTERNAL_INT_ELEMENTS:
9813 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009814 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009815 case EXTERNAL_DOUBLE_ELEMENTS:
9816 case EXTERNAL_PIXEL_ELEMENTS:
9817 // External arrays are considered 100% used.
9818 ExternalArray* external_array = ExternalArray::cast(elements());
9819 *capacity = external_array->length();
9820 *used = external_array->length();
9821 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00009822 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009823}
9824
9825
9826bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009827 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
9828 kMaxUncheckedFastElementsLength);
9829 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
9830 (new_capacity <= kMaxUncheckedFastElementsLength &&
9831 GetHeap()->InNewSpace(this))) {
9832 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009833 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009834 // If the fast-case backing storage takes up roughly three times as
9835 // much space (in machine words) as a dictionary backing storage
9836 // would, the object should have slow elements.
9837 int old_capacity = 0;
9838 int used_elements = 0;
9839 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdochc7cc0282012-03-05 14:35:55 +00009840 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
9841 SeededNumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009842 return 3 * dictionary_size <= new_capacity;
Steve Blocka7e24c12009-10-30 11:49:00 +00009843}
9844
9845
9846bool JSObject::ShouldConvertToFastElements() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009847 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009848 // If the elements are sparse, we should not go back to fast case.
9849 if (!HasDenseElements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00009850 // An object requiring access checks is never allowed to have fast
9851 // elements. If it had fast elements we would skip security checks.
9852 if (IsAccessCheckNeeded()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009853
9854 FixedArray* elements = FixedArray::cast(this->elements());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009855 SeededNumberDictionary* dictionary = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009856 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009857 dictionary = SeededNumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009858 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00009859 dictionary = SeededNumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009860 }
9861 // If an element has been added at a very high index in the elements
9862 // dictionary, we cannot go back to fast case.
9863 if (dictionary->requires_slow_elements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00009864 // If the dictionary backing storage takes up roughly half as much
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009865 // space (in machine words) as a fast-case backing storage would,
9866 // the object should have fast elements.
9867 uint32_t array_size = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00009868 if (IsJSArray()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009869 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
Steve Blocka7e24c12009-10-30 11:49:00 +00009870 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009871 array_size = dictionary->max_number_key();
Steve Blocka7e24c12009-10-30 11:49:00 +00009872 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009873 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
Ben Murdochc7cc0282012-03-05 14:35:55 +00009874 SeededNumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009875 return 2 * dictionary_size >= array_size;
Steve Blocka7e24c12009-10-30 11:49:00 +00009876}
9877
9878
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009879bool JSObject::ShouldConvertToFastDoubleElements(
9880 bool* has_smi_only_elements) {
9881 *has_smi_only_elements = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009882 if (FLAG_unbox_double_arrays) {
9883 ASSERT(HasDictionaryElements());
Ben Murdochc7cc0282012-03-05 14:35:55 +00009884 SeededNumberDictionary* dictionary =
9885 SeededNumberDictionary::cast(elements());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009886 bool found_double = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009887 for (int i = 0; i < dictionary->Capacity(); i++) {
9888 Object* key = dictionary->KeyAt(i);
9889 if (key->IsNumber()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009890 Object* value = dictionary->ValueAt(i);
9891 if (!value->IsNumber()) return false;
9892 if (!value->IsSmi()) {
9893 found_double = true;
9894 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009895 }
9896 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009897 *has_smi_only_elements = !found_double;
9898 return found_double;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009899 } else {
9900 return false;
9901 }
9902}
9903
9904
Steve Blocka7e24c12009-10-30 11:49:00 +00009905// Certain compilers request function template instantiation when they
9906// see the definition of the other template functions in the
9907// class. This requires us to have the template functions put
9908// together, so even though this function belongs in objects-debug.cc,
9909// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +01009910#ifdef OBJECT_PRINT
Steve Blocka7e24c12009-10-30 11:49:00 +00009911template<typename Shape, typename Key>
Ben Murdochb0fe1622011-05-05 13:52:32 +01009912void Dictionary<Shape, Key>::Print(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009913 int capacity = HashTable<Shape, Key>::Capacity();
9914 for (int i = 0; i < capacity; i++) {
9915 Object* k = HashTable<Shape, Key>::KeyAt(i);
9916 if (HashTable<Shape, Key>::IsKey(k)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01009917 PrintF(out, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00009918 if (k->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01009919 String::cast(k)->StringPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00009920 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01009921 k->ShortPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00009922 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01009923 PrintF(out, ": ");
9924 ValueAt(i)->ShortPrint(out);
9925 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00009926 }
9927 }
9928}
9929#endif
9930
9931
9932template<typename Shape, typename Key>
9933void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
9934 int pos = 0;
9935 int capacity = HashTable<Shape, Key>::Capacity();
Leon Clarke4515c472010-02-03 11:58:03 +00009936 AssertNoAllocation no_gc;
9937 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00009938 for (int i = 0; i < capacity; i++) {
9939 Object* k = Dictionary<Shape, Key>::KeyAt(i);
9940 if (Dictionary<Shape, Key>::IsKey(k)) {
9941 elements->set(pos++, ValueAt(i), mode);
9942 }
9943 }
9944 ASSERT(pos == elements->length());
9945}
9946
9947
9948InterceptorInfo* JSObject::GetNamedInterceptor() {
9949 ASSERT(map()->has_named_interceptor());
9950 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01009951 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00009952 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01009953 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00009954 return InterceptorInfo::cast(result);
9955}
9956
9957
9958InterceptorInfo* JSObject::GetIndexedInterceptor() {
9959 ASSERT(map()->has_indexed_interceptor());
9960 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01009961 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00009962 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01009963 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00009964 return InterceptorInfo::cast(result);
9965}
9966
9967
John Reck59135872010-11-02 12:39:01 -07009968MaybeObject* JSObject::GetPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009969 JSReceiver* receiver,
John Reck59135872010-11-02 12:39:01 -07009970 String* name,
9971 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009972 // Check local property in holder, ignore interceptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009973 LookupResult result(GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +00009974 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009975 if (result.IsProperty()) {
9976 return GetProperty(receiver, &result, name, attributes);
9977 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009978 // Continue searching via the prototype chain.
9979 Object* pt = GetPrototype();
9980 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +01009981 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009982 return pt->GetPropertyWithReceiver(receiver, name, attributes);
9983}
9984
9985
John Reck59135872010-11-02 12:39:01 -07009986MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009987 JSReceiver* receiver,
Steve Blockd0582a62009-12-15 09:54:21 +00009988 String* name,
9989 PropertyAttributes* attributes) {
9990 // Check local property in holder, ignore interceptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009991 LookupResult result(GetIsolate());
Steve Blockd0582a62009-12-15 09:54:21 +00009992 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009993 if (result.IsProperty()) {
9994 return GetProperty(receiver, &result, name, attributes);
9995 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01009996 return GetHeap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00009997}
9998
9999
John Reck59135872010-11-02 12:39:01 -070010000MaybeObject* JSObject::GetPropertyWithInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010001 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +000010002 String* name,
10003 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +010010004 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000010005 InterceptorInfo* interceptor = GetNamedInterceptor();
Steve Block44f0eee2011-05-26 01:26:41 +010010006 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010007 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +000010008 Handle<JSObject> holder_handle(this);
10009 Handle<String> name_handle(name);
10010
10011 if (!interceptor->getter()->IsUndefined()) {
10012 v8::NamedPropertyGetter getter =
10013 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +010010014 LOG(isolate,
10015 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
10016 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +000010017 v8::AccessorInfo info(args.end());
10018 v8::Handle<v8::Value> result;
10019 {
10020 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +010010021 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +000010022 result = getter(v8::Utils::ToLocal(name_handle), info);
10023 }
Steve Block44f0eee2011-05-26 01:26:41 +010010024 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010025 if (!result.IsEmpty()) {
10026 *attributes = NONE;
10027 return *v8::Utils::OpenHandle(*result);
10028 }
10029 }
10030
John Reck59135872010-11-02 12:39:01 -070010031 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +000010032 *receiver_handle,
10033 *name_handle,
10034 attributes);
Steve Block44f0eee2011-05-26 01:26:41 +010010035 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010036 return result;
10037}
10038
10039
10040bool JSObject::HasRealNamedProperty(String* key) {
10041 // Check access rights if needed.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010042 Isolate* isolate = GetIsolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +010010043 if (IsAccessCheckNeeded()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010044 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10045 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010046 return false;
10047 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010048 }
10049
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010050 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010051 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +000010052 return result.IsProperty() && (result.type() != INTERCEPTOR);
Steve Blocka7e24c12009-10-30 11:49:00 +000010053}
10054
10055
10056bool JSObject::HasRealElementProperty(uint32_t index) {
10057 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010058 if (IsAccessCheckNeeded()) {
10059 Heap* heap = GetHeap();
10060 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
10061 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10062 return false;
10063 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010064 }
10065
10066 // Handle [] on String objects.
10067 if (this->IsStringObjectWithCharacterAt(index)) return true;
10068
10069 switch (GetElementsKind()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010070 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +000010071 case FAST_ELEMENTS: {
10072 uint32_t length = IsJSArray() ?
10073 static_cast<uint32_t>(
10074 Smi::cast(JSArray::cast(this)->length())->value()) :
10075 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10076 return (index < length) &&
10077 !FixedArray::cast(elements())->get(index)->IsTheHole();
10078 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010079 case FAST_DOUBLE_ELEMENTS: {
10080 uint32_t length = IsJSArray() ?
10081 static_cast<uint32_t>(
10082 Smi::cast(JSArray::cast(this)->length())->value()) :
10083 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
10084 return (index < length) &&
10085 !FixedDoubleArray::cast(elements())->is_the_hole(index);
10086 break;
10087 }
Steve Block44f0eee2011-05-26 01:26:41 +010010088 case EXTERNAL_PIXEL_ELEMENTS: {
10089 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +000010090 return index < static_cast<uint32_t>(pixels->length());
10091 }
Steve Block3ce2e202009-11-05 08:53:23 +000010092 case EXTERNAL_BYTE_ELEMENTS:
10093 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10094 case EXTERNAL_SHORT_ELEMENTS:
10095 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10096 case EXTERNAL_INT_ELEMENTS:
10097 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +000010098 case EXTERNAL_FLOAT_ELEMENTS:
10099 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +000010100 ExternalArray* array = ExternalArray::cast(elements());
10101 return index < static_cast<uint32_t>(array->length());
10102 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010103 case DICTIONARY_ELEMENTS: {
10104 return element_dictionary()->FindEntry(index)
Ben Murdochc7cc0282012-03-05 14:35:55 +000010105 != SeededNumberDictionary::kNotFound;
Steve Blocka7e24c12009-10-30 11:49:00 +000010106 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010107 case NON_STRICT_ARGUMENTS_ELEMENTS:
10108 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +000010109 break;
10110 }
10111 // All possibilities have been handled above already.
10112 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +010010113 return GetHeap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010114}
10115
10116
10117bool JSObject::HasRealNamedCallbackProperty(String* key) {
10118 // Check access rights if needed.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010119 Isolate* isolate = GetIsolate();
Ben Murdoch8b112d22011-06-08 16:22:53 +010010120 if (IsAccessCheckNeeded()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010121 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10122 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010123 return false;
10124 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010125 }
10126
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010127 LookupResult result(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010128 LocalLookupRealNamedProperty(key, &result);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010129 return result.IsFound() && (result.type() == CALLBACKS);
Steve Blocka7e24c12009-10-30 11:49:00 +000010130}
10131
10132
10133int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010134 return HasFastProperties() ?
10135 map()->NumberOfDescribedProperties(filter) :
10136 property_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000010137}
10138
10139
10140void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
10141 Object* temp = get(i);
10142 set(i, get(j));
10143 set(j, temp);
10144 if (this != numbers) {
10145 temp = numbers->get(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010146 numbers->set(i, Smi::cast(numbers->get(j)));
10147 numbers->set(j, Smi::cast(temp));
Steve Blocka7e24c12009-10-30 11:49:00 +000010148 }
10149}
10150
10151
10152static void InsertionSortPairs(FixedArray* content,
10153 FixedArray* numbers,
10154 int len) {
10155 for (int i = 1; i < len; i++) {
10156 int j = i;
10157 while (j > 0 &&
10158 (NumberToUint32(numbers->get(j - 1)) >
10159 NumberToUint32(numbers->get(j)))) {
10160 content->SwapPairs(numbers, j - 1, j);
10161 j--;
10162 }
10163 }
10164}
10165
10166
10167void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
10168 // In-place heap sort.
10169 ASSERT(content->length() == numbers->length());
10170
10171 // Bottom-up max-heap construction.
10172 for (int i = 1; i < len; ++i) {
10173 int child_index = i;
10174 while (child_index > 0) {
10175 int parent_index = ((child_index + 1) >> 1) - 1;
10176 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10177 uint32_t child_value = NumberToUint32(numbers->get(child_index));
10178 if (parent_value < child_value) {
10179 content->SwapPairs(numbers, parent_index, child_index);
10180 } else {
10181 break;
10182 }
10183 child_index = parent_index;
10184 }
10185 }
10186
10187 // Extract elements and create sorted array.
10188 for (int i = len - 1; i > 0; --i) {
10189 // Put max element at the back of the array.
10190 content->SwapPairs(numbers, 0, i);
10191 // Sift down the new top element.
10192 int parent_index = 0;
10193 while (true) {
10194 int child_index = ((parent_index + 1) << 1) - 1;
10195 if (child_index >= i) break;
10196 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
10197 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
10198 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10199 if (child_index + 1 >= i || child1_value > child2_value) {
10200 if (parent_value > child1_value) break;
10201 content->SwapPairs(numbers, parent_index, child_index);
10202 parent_index = child_index;
10203 } else {
10204 if (parent_value > child2_value) break;
10205 content->SwapPairs(numbers, parent_index, child_index + 1);
10206 parent_index = child_index + 1;
10207 }
10208 }
10209 }
10210}
10211
10212
10213// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
10214void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
10215 ASSERT(this->length() == numbers->length());
10216 // For small arrays, simply use insertion sort.
10217 if (len <= 10) {
10218 InsertionSortPairs(this, numbers, len);
10219 return;
10220 }
10221 // Check the range of indices.
10222 uint32_t min_index = NumberToUint32(numbers->get(0));
10223 uint32_t max_index = min_index;
10224 uint32_t i;
10225 for (i = 1; i < len; i++) {
10226 if (NumberToUint32(numbers->get(i)) < min_index) {
10227 min_index = NumberToUint32(numbers->get(i));
10228 } else if (NumberToUint32(numbers->get(i)) > max_index) {
10229 max_index = NumberToUint32(numbers->get(i));
10230 }
10231 }
10232 if (max_index - min_index + 1 == len) {
10233 // Indices form a contiguous range, unless there are duplicates.
10234 // Do an in-place linear time sort assuming distinct numbers, but
10235 // avoid hanging in case they are not.
10236 for (i = 0; i < len; i++) {
10237 uint32_t p;
10238 uint32_t j = 0;
10239 // While the current element at i is not at its correct position p,
10240 // swap the elements at these two positions.
10241 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
10242 j++ < len) {
10243 SwapPairs(numbers, i, p);
10244 }
10245 }
10246 } else {
10247 HeapSortPairs(this, numbers, len);
10248 return;
10249 }
10250}
10251
10252
10253// Fill in the names of local properties into the supplied storage. The main
10254// purpose of this function is to provide reflection information for the object
10255// mirrors.
10256void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010257 ASSERT(storage->length() >= (NumberOfLocalProperties() - index));
Steve Blocka7e24c12009-10-30 11:49:00 +000010258 if (HasFastProperties()) {
10259 DescriptorArray* descs = map()->instance_descriptors();
10260 for (int i = 0; i < descs->number_of_descriptors(); i++) {
10261 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
10262 }
10263 ASSERT(storage->length() >= index);
10264 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010265 property_dictionary()->CopyKeysTo(storage,
10266 index,
10267 StringDictionary::UNSORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000010268 }
10269}
10270
10271
10272int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
10273 return GetLocalElementKeys(NULL, filter);
10274}
10275
10276
10277int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +000010278 // Fast case for objects with no elements.
10279 if (!IsJSValue() && HasFastElements()) {
10280 uint32_t length = IsJSArray() ?
10281 static_cast<uint32_t>(
10282 Smi::cast(JSArray::cast(this)->length())->value()) :
10283 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10284 if (length == 0) return 0;
10285 }
10286 // Compute the number of enumerable elements.
Steve Blocka7e24c12009-10-30 11:49:00 +000010287 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
10288}
10289
10290
10291int JSObject::GetLocalElementKeys(FixedArray* storage,
10292 PropertyAttributes filter) {
10293 int counter = 0;
10294 switch (GetElementsKind()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010295 case FAST_SMI_ONLY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +000010296 case FAST_ELEMENTS: {
10297 int length = IsJSArray() ?
10298 Smi::cast(JSArray::cast(this)->length())->value() :
10299 FixedArray::cast(elements())->length();
10300 for (int i = 0; i < length; i++) {
10301 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
10302 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000010303 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010304 }
10305 counter++;
10306 }
10307 }
10308 ASSERT(!storage || storage->length() >= counter);
10309 break;
10310 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010311 case FAST_DOUBLE_ELEMENTS: {
10312 int length = IsJSArray() ?
10313 Smi::cast(JSArray::cast(this)->length())->value() :
10314 FixedDoubleArray::cast(elements())->length();
10315 for (int i = 0; i < length; i++) {
10316 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
10317 if (storage != NULL) {
10318 storage->set(counter, Smi::FromInt(i));
10319 }
10320 counter++;
10321 }
10322 }
10323 ASSERT(!storage || storage->length() >= counter);
10324 break;
10325 }
Steve Block44f0eee2011-05-26 01:26:41 +010010326 case EXTERNAL_PIXEL_ELEMENTS: {
10327 int length = ExternalPixelArray::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000010328 while (counter < length) {
10329 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000010330 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +000010331 }
10332 counter++;
10333 }
10334 ASSERT(!storage || storage->length() >= counter);
10335 break;
10336 }
Steve Block3ce2e202009-11-05 08:53:23 +000010337 case EXTERNAL_BYTE_ELEMENTS:
10338 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10339 case EXTERNAL_SHORT_ELEMENTS:
10340 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10341 case EXTERNAL_INT_ELEMENTS:
10342 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +000010343 case EXTERNAL_FLOAT_ELEMENTS:
10344 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +000010345 int length = ExternalArray::cast(elements())->length();
10346 while (counter < length) {
10347 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000010348 storage->set(counter, Smi::FromInt(counter));
Steve Block3ce2e202009-11-05 08:53:23 +000010349 }
10350 counter++;
10351 }
10352 ASSERT(!storage || storage->length() >= counter);
10353 break;
10354 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010355 case DICTIONARY_ELEMENTS: {
10356 if (storage != NULL) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010357 element_dictionary()->CopyKeysTo(storage,
10358 filter,
Ben Murdochc7cc0282012-03-05 14:35:55 +000010359 SeededNumberDictionary::SORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000010360 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010361 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000010362 break;
10363 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010364 case NON_STRICT_ARGUMENTS_ELEMENTS: {
10365 FixedArray* parameter_map = FixedArray::cast(elements());
10366 int mapped_length = parameter_map->length() - 2;
10367 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
10368 if (arguments->IsDictionary()) {
10369 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
10370 // will insert in storage starting at index 0.
Ben Murdochc7cc0282012-03-05 14:35:55 +000010371 SeededNumberDictionary* dictionary =
10372 SeededNumberDictionary::cast(arguments);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010373 if (storage != NULL) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010374 dictionary->CopyKeysTo(
10375 storage, filter, SeededNumberDictionary::UNSORTED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010376 }
10377 counter += dictionary->NumberOfElementsFilterAttributes(filter);
10378 for (int i = 0; i < mapped_length; ++i) {
10379 if (!parameter_map->get(i + 2)->IsTheHole()) {
10380 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10381 ++counter;
10382 }
10383 }
10384 if (storage != NULL) storage->SortPairs(storage, counter);
10385
10386 } else {
10387 int backing_length = arguments->length();
10388 int i = 0;
10389 for (; i < mapped_length; ++i) {
10390 if (!parameter_map->get(i + 2)->IsTheHole()) {
10391 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10392 ++counter;
10393 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
10394 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10395 ++counter;
10396 }
10397 }
10398 for (; i < backing_length; ++i) {
10399 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10400 ++counter;
10401 }
10402 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010403 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010404 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010405 }
10406
10407 if (this->IsJSValue()) {
10408 Object* val = JSValue::cast(this)->value();
10409 if (val->IsString()) {
10410 String* str = String::cast(val);
10411 if (storage) {
10412 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000010413 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010414 }
10415 }
10416 counter += str->length();
10417 }
10418 }
10419 ASSERT(!storage || storage->length() == counter);
10420 return counter;
10421}
10422
10423
10424int JSObject::GetEnumElementKeys(FixedArray* storage) {
10425 return GetLocalElementKeys(storage,
10426 static_cast<PropertyAttributes>(DONT_ENUM));
10427}
10428
10429
Steve Blocka7e24c12009-10-30 11:49:00 +000010430// StringKey simply carries a string object as key.
10431class StringKey : public HashTableKey {
10432 public:
10433 explicit StringKey(String* string) :
10434 string_(string),
10435 hash_(HashForObject(string)) { }
10436
10437 bool IsMatch(Object* string) {
10438 // We know that all entries in a hash table had their hash keys created.
10439 // Use that knowledge to have fast failure.
10440 if (hash_ != HashForObject(string)) {
10441 return false;
10442 }
10443 return string_->Equals(String::cast(string));
10444 }
10445
10446 uint32_t Hash() { return hash_; }
10447
10448 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
10449
10450 Object* AsObject() { return string_; }
10451
10452 String* string_;
10453 uint32_t hash_;
10454};
10455
10456
10457// StringSharedKeys are used as keys in the eval cache.
10458class StringSharedKey : public HashTableKey {
10459 public:
Steve Block1e0659c2011-05-24 12:43:12 +010010460 StringSharedKey(String* source,
10461 SharedFunctionInfo* shared,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010462 LanguageMode language_mode,
10463 int scope_position)
Steve Block1e0659c2011-05-24 12:43:12 +010010464 : source_(source),
10465 shared_(shared),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010466 language_mode_(language_mode),
10467 scope_position_(scope_position) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000010468
10469 bool IsMatch(Object* other) {
10470 if (!other->IsFixedArray()) return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010471 FixedArray* other_array = FixedArray::cast(other);
10472 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
Steve Blocka7e24c12009-10-30 11:49:00 +000010473 if (shared != shared_) return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010474 int language_unchecked = Smi::cast(other_array->get(2))->value();
10475 ASSERT(language_unchecked == CLASSIC_MODE ||
10476 language_unchecked == STRICT_MODE ||
10477 language_unchecked == EXTENDED_MODE);
10478 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10479 if (language_mode != language_mode_) return false;
10480 int scope_position = Smi::cast(other_array->get(3))->value();
10481 if (scope_position != scope_position_) return false;
10482 String* source = String::cast(other_array->get(1));
Steve Blocka7e24c12009-10-30 11:49:00 +000010483 return source->Equals(source_);
10484 }
10485
10486 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +010010487 SharedFunctionInfo* shared,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010488 LanguageMode language_mode,
10489 int scope_position) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010490 uint32_t hash = source->Hash();
10491 if (shared->HasSourceCode()) {
10492 // Instead of using the SharedFunctionInfo pointer in the hash
10493 // code computation, we use a combination of the hash of the
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010494 // script source code and the start position of the calling scope.
10495 // We do this to ensure that the cache entries can survive garbage
Steve Blocka7e24c12009-10-30 11:49:00 +000010496 // collection.
10497 Script* script = Script::cast(shared->script());
10498 hash ^= String::cast(script->source())->Hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010499 if (language_mode == STRICT_MODE) hash ^= 0x8000;
10500 if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
10501 hash += scope_position;
Steve Blocka7e24c12009-10-30 11:49:00 +000010502 }
10503 return hash;
10504 }
10505
10506 uint32_t Hash() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010507 return StringSharedHashHelper(
10508 source_, shared_, language_mode_, scope_position_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010509 }
10510
10511 uint32_t HashForObject(Object* obj) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010512 FixedArray* other_array = FixedArray::cast(obj);
10513 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10514 String* source = String::cast(other_array->get(1));
10515 int language_unchecked = Smi::cast(other_array->get(2))->value();
10516 ASSERT(language_unchecked == CLASSIC_MODE ||
10517 language_unchecked == STRICT_MODE ||
10518 language_unchecked == EXTENDED_MODE);
10519 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10520 int scope_position = Smi::cast(other_array->get(3))->value();
10521 return StringSharedHashHelper(
10522 source, shared, language_mode, scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000010523 }
10524
John Reck59135872010-11-02 12:39:01 -070010525 MUST_USE_RESULT MaybeObject* AsObject() {
10526 Object* obj;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010527 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(4);
John Reck59135872010-11-02 12:39:01 -070010528 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10529 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010530 FixedArray* other_array = FixedArray::cast(obj);
10531 other_array->set(0, shared_);
10532 other_array->set(1, source_);
10533 other_array->set(2, Smi::FromInt(language_mode_));
10534 other_array->set(3, Smi::FromInt(scope_position_));
10535 return other_array;
Steve Blocka7e24c12009-10-30 11:49:00 +000010536 }
10537
10538 private:
10539 String* source_;
10540 SharedFunctionInfo* shared_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010541 LanguageMode language_mode_;
10542 int scope_position_;
Steve Blocka7e24c12009-10-30 11:49:00 +000010543};
10544
10545
10546// RegExpKey carries the source and flags of a regular expression as key.
10547class RegExpKey : public HashTableKey {
10548 public:
10549 RegExpKey(String* string, JSRegExp::Flags flags)
10550 : string_(string),
10551 flags_(Smi::FromInt(flags.value())) { }
10552
Steve Block3ce2e202009-11-05 08:53:23 +000010553 // Rather than storing the key in the hash table, a pointer to the
10554 // stored value is stored where the key should be. IsMatch then
10555 // compares the search key to the found object, rather than comparing
10556 // a key to a key.
Steve Blocka7e24c12009-10-30 11:49:00 +000010557 bool IsMatch(Object* obj) {
10558 FixedArray* val = FixedArray::cast(obj);
10559 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
10560 && (flags_ == val->get(JSRegExp::kFlagsIndex));
10561 }
10562
10563 uint32_t Hash() { return RegExpHash(string_, flags_); }
10564
10565 Object* AsObject() {
10566 // Plain hash maps, which is where regexp keys are used, don't
10567 // use this function.
10568 UNREACHABLE();
10569 return NULL;
10570 }
10571
10572 uint32_t HashForObject(Object* obj) {
10573 FixedArray* val = FixedArray::cast(obj);
10574 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
10575 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
10576 }
10577
10578 static uint32_t RegExpHash(String* string, Smi* flags) {
10579 return string->Hash() + flags->value();
10580 }
10581
10582 String* string_;
10583 Smi* flags_;
10584};
10585
10586// Utf8SymbolKey carries a vector of chars as key.
10587class Utf8SymbolKey : public HashTableKey {
10588 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +000010589 explicit Utf8SymbolKey(Vector<const char> string, uint32_t seed)
10590 : string_(string), hash_field_(0), seed_(seed) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000010591
10592 bool IsMatch(Object* string) {
10593 return String::cast(string)->IsEqualTo(string_);
10594 }
10595
10596 uint32_t Hash() {
Steve Blockd0582a62009-12-15 09:54:21 +000010597 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +000010598 unibrow::Utf8InputBuffer<> buffer(string_.start(),
10599 static_cast<unsigned>(string_.length()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010600 chars_ = buffer.Utf16Length();
Ben Murdochc7cc0282012-03-05 14:35:55 +000010601 hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
Steve Blockd0582a62009-12-15 09:54:21 +000010602 uint32_t result = hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +000010603 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10604 return result;
10605 }
10606
10607 uint32_t HashForObject(Object* other) {
10608 return String::cast(other)->Hash();
10609 }
10610
John Reck59135872010-11-02 12:39:01 -070010611 MaybeObject* AsObject() {
Steve Blockd0582a62009-12-15 09:54:21 +000010612 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +010010613 return Isolate::Current()->heap()->AllocateSymbol(
10614 string_, chars_, hash_field_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010615 }
10616
10617 Vector<const char> string_;
Steve Blockd0582a62009-12-15 09:54:21 +000010618 uint32_t hash_field_;
Steve Blocka7e24c12009-10-30 11:49:00 +000010619 int chars_; // Caches the number of characters when computing the hash code.
Ben Murdochc7cc0282012-03-05 14:35:55 +000010620 uint32_t seed_;
Steve Blocka7e24c12009-10-30 11:49:00 +000010621};
10622
10623
Steve Block9fac8402011-05-12 15:51:54 +010010624template <typename Char>
10625class SequentialSymbolKey : public HashTableKey {
10626 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +000010627 explicit SequentialSymbolKey(Vector<const Char> string, uint32_t seed)
10628 : string_(string), hash_field_(0), seed_(seed) { }
Steve Block9fac8402011-05-12 15:51:54 +010010629
10630 uint32_t Hash() {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010631 StringHasher hasher(string_.length(), seed_);
Steve Block9fac8402011-05-12 15:51:54 +010010632
10633 // Very long strings have a trivial hash that doesn't inspect the
10634 // string contents.
10635 if (hasher.has_trivial_hash()) {
10636 hash_field_ = hasher.GetHashField();
10637 } else {
10638 int i = 0;
10639 // Do the iterative array index computation as long as there is a
10640 // chance this is an array index.
10641 while (i < string_.length() && hasher.is_array_index()) {
10642 hasher.AddCharacter(static_cast<uc32>(string_[i]));
10643 i++;
10644 }
10645
10646 // Process the remaining characters without updating the array
10647 // index.
10648 while (i < string_.length()) {
10649 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
10650 i++;
10651 }
10652 hash_field_ = hasher.GetHashField();
10653 }
10654
10655 uint32_t result = hash_field_ >> String::kHashShift;
10656 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10657 return result;
10658 }
10659
10660
10661 uint32_t HashForObject(Object* other) {
10662 return String::cast(other)->Hash();
10663 }
10664
10665 Vector<const Char> string_;
10666 uint32_t hash_field_;
Ben Murdochc7cc0282012-03-05 14:35:55 +000010667 uint32_t seed_;
Steve Block9fac8402011-05-12 15:51:54 +010010668};
10669
10670
10671
10672class AsciiSymbolKey : public SequentialSymbolKey<char> {
10673 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +000010674 AsciiSymbolKey(Vector<const char> str, uint32_t seed)
10675 : SequentialSymbolKey<char>(str, seed) { }
Steve Block9fac8402011-05-12 15:51:54 +010010676
10677 bool IsMatch(Object* string) {
10678 return String::cast(string)->IsAsciiEqualTo(string_);
10679 }
10680
10681 MaybeObject* AsObject() {
10682 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +010010683 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +010010684 }
10685};
10686
10687
Ben Murdoch257744e2011-11-30 15:57:28 +000010688class SubStringAsciiSymbolKey : public HashTableKey {
10689 public:
10690 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
10691 int from,
Ben Murdochc7cc0282012-03-05 14:35:55 +000010692 int length,
10693 uint32_t seed)
10694 : string_(string), from_(from), length_(length), seed_(seed) { }
Ben Murdoch257744e2011-11-30 15:57:28 +000010695
10696 uint32_t Hash() {
10697 ASSERT(length_ >= 0);
10698 ASSERT(from_ + length_ <= string_->length());
Ben Murdochc7cc0282012-03-05 14:35:55 +000010699 StringHasher hasher(length_, string_->GetHeap()->HashSeed());
Ben Murdoch257744e2011-11-30 15:57:28 +000010700
10701 // Very long strings have a trivial hash that doesn't inspect the
10702 // string contents.
10703 if (hasher.has_trivial_hash()) {
10704 hash_field_ = hasher.GetHashField();
10705 } else {
10706 int i = 0;
10707 // Do the iterative array index computation as long as there is a
10708 // chance this is an array index.
10709 while (i < length_ && hasher.is_array_index()) {
10710 hasher.AddCharacter(static_cast<uc32>(
10711 string_->SeqAsciiStringGet(i + from_)));
10712 i++;
10713 }
10714
10715 // Process the remaining characters without updating the array
10716 // index.
10717 while (i < length_) {
10718 hasher.AddCharacterNoIndex(static_cast<uc32>(
10719 string_->SeqAsciiStringGet(i + from_)));
10720 i++;
10721 }
10722 hash_field_ = hasher.GetHashField();
10723 }
10724
10725 uint32_t result = hash_field_ >> String::kHashShift;
10726 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10727 return result;
10728 }
10729
10730
10731 uint32_t HashForObject(Object* other) {
10732 return String::cast(other)->Hash();
10733 }
10734
10735 bool IsMatch(Object* string) {
10736 Vector<const char> chars(string_->GetChars() + from_, length_);
10737 return String::cast(string)->IsAsciiEqualTo(chars);
10738 }
10739
10740 MaybeObject* AsObject() {
10741 if (hash_field_ == 0) Hash();
10742 Vector<const char> chars(string_->GetChars() + from_, length_);
10743 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
10744 }
10745
10746 private:
10747 Handle<SeqAsciiString> string_;
10748 int from_;
10749 int length_;
10750 uint32_t hash_field_;
Ben Murdochc7cc0282012-03-05 14:35:55 +000010751 uint32_t seed_;
Ben Murdoch257744e2011-11-30 15:57:28 +000010752};
10753
10754
Steve Block9fac8402011-05-12 15:51:54 +010010755class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
10756 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +000010757 explicit TwoByteSymbolKey(Vector<const uc16> str, uint32_t seed)
10758 : SequentialSymbolKey<uc16>(str, seed) { }
Steve Block9fac8402011-05-12 15:51:54 +010010759
10760 bool IsMatch(Object* string) {
10761 return String::cast(string)->IsTwoByteEqualTo(string_);
10762 }
10763
10764 MaybeObject* AsObject() {
10765 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +010010766 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +010010767 }
10768};
10769
10770
Steve Blocka7e24c12009-10-30 11:49:00 +000010771// SymbolKey carries a string/symbol object as key.
10772class SymbolKey : public HashTableKey {
10773 public:
Steve Block44f0eee2011-05-26 01:26:41 +010010774 explicit SymbolKey(String* string)
10775 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000010776
10777 bool IsMatch(Object* string) {
10778 return String::cast(string)->Equals(string_);
10779 }
10780
10781 uint32_t Hash() { return string_->Hash(); }
10782
10783 uint32_t HashForObject(Object* other) {
10784 return String::cast(other)->Hash();
10785 }
10786
John Reck59135872010-11-02 12:39:01 -070010787 MaybeObject* AsObject() {
Leon Clarkef7060e22010-06-03 12:02:55 +010010788 // Attempt to flatten the string, so that symbols will most often
10789 // be flat strings.
10790 string_ = string_->TryFlattenGetString();
Steve Block44f0eee2011-05-26 01:26:41 +010010791 Heap* heap = string_->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010792 // Transform string to symbol if possible.
Steve Block44f0eee2011-05-26 01:26:41 +010010793 Map* map = heap->SymbolMapForString(string_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010794 if (map != NULL) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010795 string_->set_map_no_write_barrier(map);
Steve Blocka7e24c12009-10-30 11:49:00 +000010796 ASSERT(string_->IsSymbol());
10797 return string_;
10798 }
10799 // Otherwise allocate a new symbol.
10800 StringInputBuffer buffer(string_);
Steve Block44f0eee2011-05-26 01:26:41 +010010801 return heap->AllocateInternalSymbol(&buffer,
Steve Blocka7e24c12009-10-30 11:49:00 +000010802 string_->length(),
Steve Blockd0582a62009-12-15 09:54:21 +000010803 string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +000010804 }
10805
10806 static uint32_t StringHash(Object* obj) {
10807 return String::cast(obj)->Hash();
10808 }
10809
10810 String* string_;
10811};
10812
10813
10814template<typename Shape, typename Key>
10815void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
10816 IteratePointers(v, 0, kElementsStartOffset);
10817}
10818
10819
10820template<typename Shape, typename Key>
10821void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
10822 IteratePointers(v,
10823 kElementsStartOffset,
10824 kHeaderSize + length() * kPointerSize);
10825}
10826
10827
10828template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010829MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
10830 PretenureFlag pretenure) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010831 int capacity = ComputeCapacity(at_least_space_for);
10832 if (capacity > HashTable::kMaxCapacity) {
Leon Clarkee46be812010-01-19 14:06:41 +000010833 return Failure::OutOfMemoryException();
10834 }
10835
John Reck59135872010-11-02 12:39:01 -070010836 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +010010837 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
10838 AllocateHashTable(EntryToIndex(capacity), pretenure);
John Reck59135872010-11-02 12:39:01 -070010839 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000010840 }
John Reck59135872010-11-02 12:39:01 -070010841 HashTable::cast(obj)->SetNumberOfElements(0);
10842 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
10843 HashTable::cast(obj)->SetCapacity(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000010844 return obj;
10845}
10846
10847
Leon Clarkee46be812010-01-19 14:06:41 +000010848// Find entry for key otherwise return kNotFound.
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010849int StringDictionary::FindEntry(String* key) {
10850 if (!key->IsSymbol()) {
10851 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
10852 }
10853
10854 // Optimized for symbol key. Knowledge of the key type allows:
10855 // 1. Move the check if the key is a symbol out of the loop.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010856 // 2. Avoid comparing hash codes in symbol to symbol comparison.
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010857 // 3. Detect a case when a dictionary key is not a symbol but the key is.
10858 // In case of positive result the dictionary key may be replaced by
10859 // the symbol with minimal performance penalty. It gives a chance to
10860 // perform further lookups in code stubs (and significant performance boost
10861 // a certain style of code).
10862
10863 // EnsureCapacity will guarantee the hash table is never full.
10864 uint32_t capacity = Capacity();
10865 uint32_t entry = FirstProbe(key->Hash(), capacity);
10866 uint32_t count = 1;
10867
10868 while (true) {
10869 int index = EntryToIndex(entry);
10870 Object* element = get(index);
10871 if (element->IsUndefined()) break; // Empty entry.
10872 if (key == element) return entry;
10873 if (!element->IsSymbol() &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010874 !element->IsTheHole() &&
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010875 String::cast(element)->Equals(key)) {
10876 // Replace a non-symbol key by the equivalent symbol for faster further
10877 // lookups.
10878 set(index, key);
10879 return entry;
10880 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010881 ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key));
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010882 entry = NextProbe(entry, count++, capacity);
10883 }
10884 return kNotFound;
10885}
10886
10887
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010888bool StringDictionary::ContainsTransition(int entry) {
10889 switch (DetailsAt(entry).type()) {
10890 case MAP_TRANSITION:
10891 case CONSTANT_TRANSITION:
10892 case ELEMENTS_TRANSITION:
10893 return true;
10894 case CALLBACKS: {
10895 Object* value = ValueAt(entry);
10896 if (!value->IsAccessorPair()) return false;
10897 AccessorPair* accessors = AccessorPair::cast(value);
10898 return accessors->getter()->IsMap() || accessors->setter()->IsMap();
10899 }
10900 case NORMAL:
10901 case FIELD:
10902 case CONSTANT_FUNCTION:
10903 case HANDLER:
10904 case INTERCEPTOR:
10905 case NULL_DESCRIPTOR:
10906 return false;
10907 }
10908 UNREACHABLE(); // Keep the compiler happy.
10909 return false;
10910}
10911
10912
Steve Blocka7e24c12009-10-30 11:49:00 +000010913template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010914MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
10915 ASSERT(NumberOfElements() < new_table->Capacity());
10916
10917 AssertNoAllocation no_gc;
10918 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
10919
10920 // Copy prefix to new array.
10921 for (int i = kPrefixStartIndex;
10922 i < kPrefixStartIndex + Shape::kPrefixSize;
10923 i++) {
10924 new_table->set(i, get(i), mode);
10925 }
10926
10927 // Rehash the elements.
10928 int capacity = Capacity();
10929 for (int i = 0; i < capacity; i++) {
10930 uint32_t from_index = EntryToIndex(i);
10931 Object* k = get(from_index);
10932 if (IsKey(k)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000010933 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010934 uint32_t insertion_index =
10935 EntryToIndex(new_table->FindInsertionEntry(hash));
10936 for (int j = 0; j < Shape::kEntrySize; j++) {
10937 new_table->set(insertion_index + j, get(from_index + j), mode);
10938 }
10939 }
10940 }
10941 new_table->SetNumberOfElements(NumberOfElements());
10942 new_table->SetNumberOfDeletedElements(0);
10943 return new_table;
10944}
10945
10946
10947template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010948MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010949 int capacity = Capacity();
10950 int nof = NumberOfElements() + n;
Leon Clarkee46be812010-01-19 14:06:41 +000010951 int nod = NumberOfDeletedElements();
10952 // Return if:
10953 // 50% is still free after adding n elements and
10954 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +010010955 if (nod <= (capacity - nof) >> 1) {
10956 int needed_free = nof >> 1;
10957 if (nof + needed_free <= capacity) return this;
10958 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010959
Steve Block6ded16b2010-05-10 14:33:55 +010010960 const int kMinCapacityForPretenure = 256;
10961 bool pretenure =
Ben Murdoch8b112d22011-06-08 16:22:53 +010010962 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
John Reck59135872010-11-02 12:39:01 -070010963 Object* obj;
10964 { MaybeObject* maybe_obj =
10965 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
10966 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10967 }
Leon Clarke4515c472010-02-03 11:58:03 +000010968
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010969 return Rehash(HashTable::cast(obj), key);
10970}
Steve Blocka7e24c12009-10-30 11:49:00 +000010971
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010972
10973template<typename Shape, typename Key>
10974MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
10975 int capacity = Capacity();
10976 int nof = NumberOfElements();
10977
10978 // Shrink to fit the number of elements if only a quarter of the
10979 // capacity is filled with elements.
10980 if (nof > (capacity >> 2)) return this;
10981 // Allocate a new dictionary with room for at least the current
10982 // number of elements. The allocation method will make sure that
10983 // there is extra room in the dictionary for additions. Don't go
10984 // lower than room for 16 elements.
10985 int at_least_room_for = nof;
10986 if (at_least_room_for < 16) return this;
10987
10988 const int kMinCapacityForPretenure = 256;
10989 bool pretenure =
10990 (at_least_room_for > kMinCapacityForPretenure) &&
10991 !GetHeap()->InNewSpace(this);
10992 Object* obj;
10993 { MaybeObject* maybe_obj =
10994 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
10995 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000010996 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010997
10998 return Rehash(HashTable::cast(obj), key);
Steve Blocka7e24c12009-10-30 11:49:00 +000010999}
11000
11001
11002template<typename Shape, typename Key>
11003uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
11004 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +000011005 uint32_t entry = FirstProbe(hash, capacity);
11006 uint32_t count = 1;
11007 // EnsureCapacity will guarantee the hash table is never full.
11008 while (true) {
11009 Object* element = KeyAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011010 if (element->IsUndefined() || element->IsTheHole()) break;
Leon Clarkee46be812010-01-19 14:06:41 +000011011 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000011012 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011013 return entry;
11014}
11015
11016// Force instantiation of template instances class.
11017// Please note this list is compiler dependent.
11018
11019template class HashTable<SymbolTableShape, HashTableKey*>;
11020
11021template class HashTable<CompilationCacheShape, HashTableKey*>;
11022
11023template class HashTable<MapCacheShape, HashTableKey*>;
11024
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011025template class HashTable<ObjectHashTableShape<1>, Object*>;
11026
11027template class HashTable<ObjectHashTableShape<2>, Object*>;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011028
Steve Blocka7e24c12009-10-30 11:49:00 +000011029template class Dictionary<StringDictionaryShape, String*>;
11030
Ben Murdochc7cc0282012-03-05 14:35:55 +000011031template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
Steve Blocka7e24c12009-10-30 11:49:00 +000011032
Ben Murdochc7cc0282012-03-05 14:35:55 +000011033template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
11034
11035template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11036 Allocate(int at_least_space_for);
11037
11038template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11039 Allocate(int at_least_space_for);
Steve Blocka7e24c12009-10-30 11:49:00 +000011040
John Reck59135872010-11-02 12:39:01 -070011041template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +000011042 int);
11043
Ben Murdochc7cc0282012-03-05 14:35:55 +000011044template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
Steve Blocka7e24c12009-10-30 11:49:00 +000011045 uint32_t, Object*);
11046
Ben Murdochc7cc0282012-03-05 14:35:55 +000011047template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11048 AtPut(uint32_t, Object*);
11049
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011050template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11051 SlowReverseLookup(Object* value);
11052
Ben Murdochc7cc0282012-03-05 14:35:55 +000011053template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11054 SlowReverseLookup(Object* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000011055
11056template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
11057 Object*);
11058
Ben Murdochc7cc0282012-03-05 14:35:55 +000011059template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011060 FixedArray*,
11061 PropertyAttributes,
Ben Murdochc7cc0282012-03-05 14:35:55 +000011062 Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000011063
11064template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
11065 int, JSObject::DeleteMode);
11066
Ben Murdochc7cc0282012-03-05 14:35:55 +000011067template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11068 DeleteProperty(int, JSObject::DeleteMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000011069
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011070template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
11071 String*);
11072
Ben Murdochc7cc0282012-03-05 14:35:55 +000011073template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011074 uint32_t);
11075
Steve Blocka7e24c12009-10-30 11:49:00 +000011076template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011077 FixedArray*,
11078 int,
11079 Dictionary<StringDictionaryShape, String*>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000011080
11081template int
11082Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
11083 PropertyAttributes);
11084
John Reck59135872010-11-02 12:39:01 -070011085template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000011086 String*, Object*, PropertyDetails);
11087
John Reck59135872010-11-02 12:39:01 -070011088template MaybeObject*
Steve Blocka7e24c12009-10-30 11:49:00 +000011089Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
11090
11091template int
Ben Murdochc7cc0282012-03-05 14:35:55 +000011092Dictionary<SeededNumberDictionaryShape, uint32_t>::
11093 NumberOfElementsFilterAttributes(PropertyAttributes);
Steve Blocka7e24c12009-10-30 11:49:00 +000011094
Ben Murdochc7cc0282012-03-05 14:35:55 +000011095template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000011096 uint32_t, Object*, PropertyDetails);
11097
Ben Murdochc7cc0282012-03-05 14:35:55 +000011098template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
11099 uint32_t, Object*, PropertyDetails);
11100
11101template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11102 EnsureCapacity(int, uint32_t);
11103
11104template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
John Reck59135872010-11-02 12:39:01 -070011105 EnsureCapacity(int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000011106
John Reck59135872010-11-02 12:39:01 -070011107template MaybeObject* Dictionary<StringDictionaryShape, String*>::
11108 EnsureCapacity(int, String*);
Steve Blocka7e24c12009-10-30 11:49:00 +000011109
Ben Murdochc7cc0282012-03-05 14:35:55 +000011110template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11111 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
11112
11113template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11114 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000011115
John Reck59135872010-11-02 12:39:01 -070011116template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +000011117 String*, Object*, PropertyDetails, uint32_t);
11118
11119template
Ben Murdochc7cc0282012-03-05 14:35:55 +000011120int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000011121
11122template
11123int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
11124
Leon Clarkee46be812010-01-19 14:06:41 +000011125template
Ben Murdochc7cc0282012-03-05 14:35:55 +000011126int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
Leon Clarkee46be812010-01-19 14:06:41 +000011127
11128
Steve Blocka7e24c12009-10-30 11:49:00 +000011129// Collates undefined and unexisting elements below limit from position
11130// zero of the elements. The object stays in Dictionary mode.
John Reck59135872010-11-02 12:39:01 -070011131MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011132 ASSERT(HasDictionaryElements());
11133 // Must stay in dictionary mode, either because of requires_slow_elements,
11134 // or because we are not going to sort (and therefore compact) all of the
11135 // elements.
Ben Murdochc7cc0282012-03-05 14:35:55 +000011136 SeededNumberDictionary* dict = element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +000011137 HeapNumber* result_double = NULL;
11138 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11139 // Allocate space for result before we start mutating the object.
John Reck59135872010-11-02 12:39:01 -070011140 Object* new_double;
Ben Murdoch8b112d22011-06-08 16:22:53 +010011141 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070011142 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11143 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011144 result_double = HeapNumber::cast(new_double);
11145 }
11146
John Reck59135872010-11-02 12:39:01 -070011147 Object* obj;
11148 { MaybeObject* maybe_obj =
Ben Murdochc7cc0282012-03-05 14:35:55 +000011149 SeededNumberDictionary::Allocate(dict->NumberOfElements());
John Reck59135872010-11-02 12:39:01 -070011150 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11151 }
Ben Murdochc7cc0282012-03-05 14:35:55 +000011152 SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +000011153
11154 AssertNoAllocation no_alloc;
11155
11156 uint32_t pos = 0;
11157 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010011158 int capacity = dict->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000011159 for (int i = 0; i < capacity; i++) {
11160 Object* k = dict->KeyAt(i);
11161 if (dict->IsKey(k)) {
11162 ASSERT(k->IsNumber());
11163 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
11164 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
11165 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
11166 Object* value = dict->ValueAt(i);
11167 PropertyDetails details = dict->DetailsAt(i);
11168 if (details.type() == CALLBACKS) {
11169 // Bail out and do the sorting of undefineds and array holes in JS.
11170 return Smi::FromInt(-1);
11171 }
11172 uint32_t key = NumberToUint32(k);
John Reck59135872010-11-02 12:39:01 -070011173 // In the following we assert that adding the entry to the new dictionary
11174 // does not cause GC. This is the case because we made sure to allocate
11175 // the dictionary big enough above, so it need not grow.
Steve Blocka7e24c12009-10-30 11:49:00 +000011176 if (key < limit) {
11177 if (value->IsUndefined()) {
11178 undefs++;
11179 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010011180 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11181 // Adding an entry with the key beyond smi-range requires
11182 // allocation. Bailout.
11183 return Smi::FromInt(-1);
11184 }
John Reck59135872010-11-02 12:39:01 -070011185 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000011186 pos++;
11187 }
11188 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010011189 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
11190 // Adding an entry with the key beyond smi-range requires
11191 // allocation. Bailout.
11192 return Smi::FromInt(-1);
11193 }
John Reck59135872010-11-02 12:39:01 -070011194 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000011195 }
11196 }
11197 }
11198
11199 uint32_t result = pos;
11200 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011201 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000011202 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010011203 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11204 // Adding an entry with the key beyond smi-range requires
11205 // allocation. Bailout.
11206 return Smi::FromInt(-1);
11207 }
Steve Block44f0eee2011-05-26 01:26:41 +010011208 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
John Reck59135872010-11-02 12:39:01 -070011209 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000011210 pos++;
11211 undefs--;
11212 }
11213
11214 set_elements(new_dict);
11215
11216 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11217 return Smi::FromInt(static_cast<int>(result));
11218 }
11219
11220 ASSERT_NE(NULL, result_double);
11221 result_double->set_value(static_cast<double>(result));
11222 return result_double;
11223}
11224
11225
11226// Collects all defined (non-hole) and non-undefined (array) elements at
11227// the start of the elements array.
11228// If the object is in dictionary mode, it is converted to fast elements
11229// mode.
John Reck59135872010-11-02 12:39:01 -070011230MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011231 Heap* heap = GetHeap();
11232
Steve Blocka7e24c12009-10-30 11:49:00 +000011233 if (HasDictionaryElements()) {
11234 // Convert to fast elements containing only the existing properties.
11235 // Ordering is irrelevant, since we are going to sort anyway.
Ben Murdochc7cc0282012-03-05 14:35:55 +000011236 SeededNumberDictionary* dict = element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +000011237 if (IsJSArray() || dict->requires_slow_elements() ||
11238 dict->max_number_key() >= limit) {
11239 return PrepareSlowElementsForSort(limit);
11240 }
11241 // Convert to fast elements.
11242
John Reck59135872010-11-02 12:39:01 -070011243 Object* obj;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011244 { MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
11245 FAST_ELEMENTS);
John Reck59135872010-11-02 12:39:01 -070011246 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11247 }
Steve Block8defd9f2010-07-08 12:39:36 +010011248 Map* new_map = Map::cast(obj);
11249
Steve Block44f0eee2011-05-26 01:26:41 +010011250 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
John Reck59135872010-11-02 12:39:01 -070011251 Object* new_array;
11252 { MaybeObject* maybe_new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010011253 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
John Reck59135872010-11-02 12:39:01 -070011254 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
11255 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011256 FixedArray* fast_elements = FixedArray::cast(new_array);
11257 dict->CopyValuesTo(fast_elements);
Steve Block8defd9f2010-07-08 12:39:36 +010011258
11259 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +000011260 set_elements(fast_elements);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011261 } else if (HasExternalArrayElements()) {
11262 // External arrays cannot have holes or undefined elements.
11263 return Smi::FromInt(ExternalArray::cast(elements())->length());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011264 } else if (!HasFastDoubleElements()) {
John Reck59135872010-11-02 12:39:01 -070011265 Object* obj;
11266 { MaybeObject* maybe_obj = EnsureWritableFastElements();
11267 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11268 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011269 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011270 ASSERT(HasFastTypeElements() || HasFastDoubleElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000011271
11272 // Collect holes at the end, undefined before that and the rest at the
11273 // start, and return the number of non-hole, non-undefined values.
11274
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011275 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
11276 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000011277 if (limit > elements_length) {
11278 limit = elements_length ;
11279 }
11280 if (limit == 0) {
11281 return Smi::FromInt(0);
11282 }
11283
11284 HeapNumber* result_double = NULL;
11285 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11286 // Pessimistically allocate space for return value before
11287 // we start mutating the array.
John Reck59135872010-11-02 12:39:01 -070011288 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +010011289 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070011290 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11291 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011292 result_double = HeapNumber::cast(new_double);
11293 }
11294
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011295 uint32_t result = 0;
11296 if (elements_base->map() == heap->fixed_double_array_map()) {
11297 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
11298 // Split elements into defined and the_hole, in that order.
11299 unsigned int holes = limit;
11300 // Assume most arrays contain no holes and undefined values, so minimize the
11301 // number of stores of non-undefined, non-the-hole values.
11302 for (unsigned int i = 0; i < holes; i++) {
11303 if (elements->is_the_hole(i)) {
11304 holes--;
11305 } else {
11306 continue;
11307 }
11308 // Position i needs to be filled.
11309 while (holes > i) {
11310 if (elements->is_the_hole(holes)) {
11311 holes--;
11312 } else {
11313 elements->set(i, elements->get_scalar(holes));
11314 break;
11315 }
11316 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011317 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011318 result = holes;
11319 while (holes < limit) {
11320 elements->set_the_hole(holes);
11321 holes++;
11322 }
11323 } else {
11324 FixedArray* elements = FixedArray::cast(elements_base);
11325 AssertNoAllocation no_alloc;
11326
11327 // Split elements into defined, undefined and the_hole, in that order. Only
11328 // count locations for undefined and the hole, and fill them afterwards.
11329 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
11330 unsigned int undefs = limit;
11331 unsigned int holes = limit;
11332 // Assume most arrays contain no holes and undefined values, so minimize the
11333 // number of stores of non-undefined, non-the-hole values.
11334 for (unsigned int i = 0; i < undefs; i++) {
11335 Object* current = elements->get(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000011336 if (current->IsTheHole()) {
11337 holes--;
11338 undefs--;
11339 } else if (current->IsUndefined()) {
11340 undefs--;
11341 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011342 continue;
11343 }
11344 // Position i needs to be filled.
11345 while (undefs > i) {
11346 current = elements->get(undefs);
11347 if (current->IsTheHole()) {
11348 holes--;
11349 undefs--;
11350 } else if (current->IsUndefined()) {
11351 undefs--;
11352 } else {
11353 elements->set(i, current, write_barrier);
11354 break;
11355 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011356 }
11357 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011358 result = undefs;
11359 while (undefs < holes) {
11360 elements->set_undefined(undefs);
11361 undefs++;
11362 }
11363 while (holes < limit) {
11364 elements->set_the_hole(holes);
11365 holes++;
11366 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011367 }
11368
11369 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11370 return Smi::FromInt(static_cast<int>(result));
11371 }
11372 ASSERT_NE(NULL, result_double);
11373 result_double->set_value(static_cast<double>(result));
11374 return result_double;
11375}
11376
11377
Steve Block44f0eee2011-05-26 01:26:41 +010011378Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011379 uint8_t clamped_value = 0;
11380 if (index < static_cast<uint32_t>(length())) {
11381 if (value->IsSmi()) {
11382 int int_value = Smi::cast(value)->value();
11383 if (int_value < 0) {
11384 clamped_value = 0;
11385 } else if (int_value > 255) {
11386 clamped_value = 255;
11387 } else {
11388 clamped_value = static_cast<uint8_t>(int_value);
11389 }
11390 } else if (value->IsHeapNumber()) {
11391 double double_value = HeapNumber::cast(value)->value();
11392 if (!(double_value > 0)) {
11393 // NaN and less than zero clamp to zero.
11394 clamped_value = 0;
11395 } else if (double_value > 255) {
11396 // Greater than 255 clamp to 255.
11397 clamped_value = 255;
11398 } else {
11399 // Other doubles are rounded to the nearest integer.
11400 clamped_value = static_cast<uint8_t>(double_value + 0.5);
11401 }
11402 } else {
11403 // Clamp undefined to zero (default). All other types have been
11404 // converted to a number type further up in the call chain.
11405 ASSERT(value->IsUndefined());
11406 }
11407 set(index, clamped_value);
11408 }
11409 return Smi::FromInt(clamped_value);
11410}
11411
11412
Steve Block3ce2e202009-11-05 08:53:23 +000011413template<typename ExternalArrayClass, typename ValueType>
Steve Block44f0eee2011-05-26 01:26:41 +010011414static MaybeObject* ExternalArrayIntSetter(Heap* heap,
11415 ExternalArrayClass* receiver,
John Reck59135872010-11-02 12:39:01 -070011416 uint32_t index,
11417 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011418 ValueType cast_value = 0;
11419 if (index < static_cast<uint32_t>(receiver->length())) {
11420 if (value->IsSmi()) {
11421 int int_value = Smi::cast(value)->value();
11422 cast_value = static_cast<ValueType>(int_value);
11423 } else if (value->IsHeapNumber()) {
11424 double double_value = HeapNumber::cast(value)->value();
11425 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
11426 } else {
11427 // Clamp undefined to zero (default). All other types have been
11428 // converted to a number type further up in the call chain.
11429 ASSERT(value->IsUndefined());
11430 }
11431 receiver->set(index, cast_value);
11432 }
Steve Block44f0eee2011-05-26 01:26:41 +010011433 return heap->NumberFromInt32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000011434}
11435
11436
John Reck59135872010-11-02 12:39:01 -070011437MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011438 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011439 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011440}
11441
11442
John Reck59135872010-11-02 12:39:01 -070011443MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
11444 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011445 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011446 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011447}
11448
11449
John Reck59135872010-11-02 12:39:01 -070011450MaybeObject* ExternalShortArray::SetValue(uint32_t index,
11451 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011452 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011453 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011454}
11455
11456
John Reck59135872010-11-02 12:39:01 -070011457MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
11458 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011459 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011460 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011461}
11462
11463
John Reck59135872010-11-02 12:39:01 -070011464MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011465 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
Steve Block44f0eee2011-05-26 01:26:41 +010011466 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000011467}
11468
11469
John Reck59135872010-11-02 12:39:01 -070011470MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000011471 uint32_t cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010011472 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000011473 if (index < static_cast<uint32_t>(length())) {
11474 if (value->IsSmi()) {
11475 int int_value = Smi::cast(value)->value();
11476 cast_value = static_cast<uint32_t>(int_value);
11477 } else if (value->IsHeapNumber()) {
11478 double double_value = HeapNumber::cast(value)->value();
11479 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
11480 } else {
11481 // Clamp undefined to zero (default). All other types have been
11482 // converted to a number type further up in the call chain.
11483 ASSERT(value->IsUndefined());
11484 }
11485 set(index, cast_value);
11486 }
Steve Block44f0eee2011-05-26 01:26:41 +010011487 return heap->NumberFromUint32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000011488}
11489
11490
John Reck59135872010-11-02 12:39:01 -070011491MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011492 float cast_value = static_cast<float>(OS::nan_value());
Steve Block44f0eee2011-05-26 01:26:41 +010011493 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000011494 if (index < static_cast<uint32_t>(length())) {
11495 if (value->IsSmi()) {
11496 int int_value = Smi::cast(value)->value();
11497 cast_value = static_cast<float>(int_value);
11498 } else if (value->IsHeapNumber()) {
11499 double double_value = HeapNumber::cast(value)->value();
11500 cast_value = static_cast<float>(double_value);
11501 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011502 // Clamp undefined to NaN (default). All other types have been
Steve Block3ce2e202009-11-05 08:53:23 +000011503 // converted to a number type further up in the call chain.
11504 ASSERT(value->IsUndefined());
11505 }
11506 set(index, cast_value);
11507 }
Steve Block44f0eee2011-05-26 01:26:41 +010011508 return heap->AllocateHeapNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000011509}
11510
11511
Ben Murdoch257744e2011-11-30 15:57:28 +000011512MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011513 double double_value = OS::nan_value();
Ben Murdoch257744e2011-11-30 15:57:28 +000011514 Heap* heap = GetHeap();
11515 if (index < static_cast<uint32_t>(length())) {
11516 if (value->IsSmi()) {
11517 int int_value = Smi::cast(value)->value();
11518 double_value = static_cast<double>(int_value);
11519 } else if (value->IsHeapNumber()) {
11520 double_value = HeapNumber::cast(value)->value();
11521 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011522 // Clamp undefined to NaN (default). All other types have been
Ben Murdoch257744e2011-11-30 15:57:28 +000011523 // converted to a number type further up in the call chain.
11524 ASSERT(value->IsUndefined());
11525 }
11526 set(index, double_value);
11527 }
11528 return heap->AllocateHeapNumber(double_value);
11529}
11530
11531
Ben Murdochb0fe1622011-05-05 13:52:32 +010011532JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011533 ASSERT(!HasFastProperties());
11534 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +010011535 return JSGlobalPropertyCell::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000011536}
11537
11538
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011539Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
11540 Handle<GlobalObject> global,
11541 Handle<String> name) {
11542 Isolate* isolate = global->GetIsolate();
11543 CALL_HEAP_FUNCTION(isolate,
11544 global->EnsurePropertyCell(*name),
11545 JSGlobalPropertyCell);
11546}
11547
11548
John Reck59135872010-11-02 12:39:01 -070011549MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011550 ASSERT(!HasFastProperties());
11551 int entry = property_dictionary()->FindEntry(name);
11552 if (entry == StringDictionary::kNotFound) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011553 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -070011554 Object* cell;
11555 { MaybeObject* maybe_cell =
Steve Block44f0eee2011-05-26 01:26:41 +010011556 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
John Reck59135872010-11-02 12:39:01 -070011557 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
11558 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011559 PropertyDetails details(NONE, NORMAL);
11560 details = details.AsDeleted();
John Reck59135872010-11-02 12:39:01 -070011561 Object* dictionary;
11562 { MaybeObject* maybe_dictionary =
11563 property_dictionary()->Add(name, cell, details);
11564 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
11565 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011566 set_properties(StringDictionary::cast(dictionary));
11567 return cell;
11568 } else {
11569 Object* value = property_dictionary()->ValueAt(entry);
11570 ASSERT(value->IsJSGlobalPropertyCell());
11571 return value;
11572 }
11573}
11574
11575
John Reck59135872010-11-02 12:39:01 -070011576MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011577 SymbolKey key(string);
11578 return LookupKey(&key, s);
11579}
11580
11581
Steve Blockd0582a62009-12-15 09:54:21 +000011582// This class is used for looking up two character strings in the symbol table.
11583// If we don't have a hit we don't want to waste much time so we unroll the
11584// string hash calculation loop here for speed. Doesn't work if the two
11585// characters form a decimal integer, since such strings have a different hash
11586// algorithm.
11587class TwoCharHashTableKey : public HashTableKey {
11588 public:
Ben Murdochc7cc0282012-03-05 14:35:55 +000011589 TwoCharHashTableKey(uint32_t c1, uint32_t c2, uint32_t seed)
Steve Blockd0582a62009-12-15 09:54:21 +000011590 : c1_(c1), c2_(c2) {
11591 // Char 1.
Ben Murdochc7cc0282012-03-05 14:35:55 +000011592 uint32_t hash = seed;
11593 hash += c1;
11594 hash += hash << 10;
Steve Blockd0582a62009-12-15 09:54:21 +000011595 hash ^= hash >> 6;
11596 // Char 2.
11597 hash += c2;
11598 hash += hash << 10;
11599 hash ^= hash >> 6;
11600 // GetHash.
11601 hash += hash << 3;
11602 hash ^= hash >> 11;
11603 hash += hash << 15;
Ben Murdochc7cc0282012-03-05 14:35:55 +000011604 if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash;
Steve Blockd0582a62009-12-15 09:54:21 +000011605#ifdef DEBUG
Ben Murdochc7cc0282012-03-05 14:35:55 +000011606 StringHasher hasher(2, seed);
Steve Blockd0582a62009-12-15 09:54:21 +000011607 hasher.AddCharacter(c1);
11608 hasher.AddCharacter(c2);
11609 // If this assert fails then we failed to reproduce the two-character
11610 // version of the string hashing algorithm above. One reason could be
11611 // that we were passed two digits as characters, since the hash
11612 // algorithm is different in that case.
11613 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
11614#endif
11615 hash_ = hash;
11616 }
11617
11618 bool IsMatch(Object* o) {
11619 if (!o->IsString()) return false;
11620 String* other = String::cast(o);
11621 if (other->length() != 2) return false;
11622 if (other->Get(0) != c1_) return false;
11623 return other->Get(1) == c2_;
11624 }
11625
11626 uint32_t Hash() { return hash_; }
11627 uint32_t HashForObject(Object* key) {
11628 if (!key->IsString()) return 0;
11629 return String::cast(key)->Hash();
11630 }
11631
11632 Object* AsObject() {
11633 // The TwoCharHashTableKey is only used for looking in the symbol
11634 // table, not for adding to it.
11635 UNREACHABLE();
11636 return NULL;
11637 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011638
Steve Blockd0582a62009-12-15 09:54:21 +000011639 private:
11640 uint32_t c1_;
11641 uint32_t c2_;
11642 uint32_t hash_;
11643};
11644
11645
Steve Blocka7e24c12009-10-30 11:49:00 +000011646bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
11647 SymbolKey key(string);
11648 int entry = FindEntry(&key);
11649 if (entry == kNotFound) {
11650 return false;
11651 } else {
11652 String* result = String::cast(KeyAt(entry));
11653 ASSERT(StringShape(result).IsSymbol());
11654 *symbol = result;
11655 return true;
11656 }
11657}
11658
11659
Steve Blockd0582a62009-12-15 09:54:21 +000011660bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
11661 uint32_t c2,
11662 String** symbol) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000011663 TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
Steve Blockd0582a62009-12-15 09:54:21 +000011664 int entry = FindEntry(&key);
11665 if (entry == kNotFound) {
11666 return false;
11667 } else {
11668 String* result = String::cast(KeyAt(entry));
11669 ASSERT(StringShape(result).IsSymbol());
11670 *symbol = result;
11671 return true;
11672 }
11673}
11674
11675
Ben Murdochc7cc0282012-03-05 14:35:55 +000011676MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str,
11677 Object** s) {
11678 Utf8SymbolKey key(str, GetHeap()->HashSeed());
Steve Blocka7e24c12009-10-30 11:49:00 +000011679 return LookupKey(&key, s);
11680}
11681
11682
Steve Block9fac8402011-05-12 15:51:54 +010011683MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
11684 Object** s) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000011685 AsciiSymbolKey key(str, GetHeap()->HashSeed());
Steve Block9fac8402011-05-12 15:51:54 +010011686 return LookupKey(&key, s);
11687}
11688
11689
Ben Murdoch257744e2011-11-30 15:57:28 +000011690MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
11691 int from,
11692 int length,
11693 Object** s) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000011694 SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
Ben Murdoch257744e2011-11-30 15:57:28 +000011695 return LookupKey(&key, s);
11696}
11697
11698
Steve Block9fac8402011-05-12 15:51:54 +010011699MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
11700 Object** s) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000011701 TwoByteSymbolKey key(str, GetHeap()->HashSeed());
Steve Block9fac8402011-05-12 15:51:54 +010011702 return LookupKey(&key, s);
11703}
11704
John Reck59135872010-11-02 12:39:01 -070011705MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011706 int entry = FindEntry(key);
11707
11708 // Symbol already in table.
11709 if (entry != kNotFound) {
11710 *s = KeyAt(entry);
11711 return this;
11712 }
11713
11714 // Adding new symbol. Grow table if needed.
John Reck59135872010-11-02 12:39:01 -070011715 Object* obj;
11716 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11717 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11718 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011719
11720 // Create symbol object.
John Reck59135872010-11-02 12:39:01 -070011721 Object* symbol;
11722 { MaybeObject* maybe_symbol = key->AsObject();
11723 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
11724 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011725
11726 // If the symbol table grew as part of EnsureCapacity, obj is not
11727 // the current symbol table and therefore we cannot use
11728 // SymbolTable::cast here.
11729 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
11730
11731 // Add the new symbol and return it along with the symbol table.
11732 entry = table->FindInsertionEntry(key->Hash());
11733 table->set(EntryToIndex(entry), symbol);
11734 table->ElementAdded();
11735 *s = symbol;
11736 return table;
11737}
11738
11739
11740Object* CompilationCacheTable::Lookup(String* src) {
11741 StringKey key(src);
11742 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011743 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011744 return get(EntryToIndex(entry) + 1);
11745}
11746
11747
Steve Block1e0659c2011-05-24 12:43:12 +010011748Object* CompilationCacheTable::LookupEval(String* src,
11749 Context* context,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011750 LanguageMode language_mode,
11751 int scope_position) {
11752 StringSharedKey key(src,
11753 context->closure()->shared(),
11754 language_mode,
11755 scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000011756 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +010011757 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011758 return get(EntryToIndex(entry) + 1);
11759}
11760
11761
11762Object* CompilationCacheTable::LookupRegExp(String* src,
11763 JSRegExp::Flags flags) {
11764 RegExpKey key(src, flags);
11765 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011766 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011767 return get(EntryToIndex(entry) + 1);
11768}
11769
11770
John Reck59135872010-11-02 12:39:01 -070011771MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011772 StringKey key(src);
John Reck59135872010-11-02 12:39:01 -070011773 Object* obj;
11774 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11775 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11776 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011777
11778 CompilationCacheTable* cache =
11779 reinterpret_cast<CompilationCacheTable*>(obj);
11780 int entry = cache->FindInsertionEntry(key.Hash());
11781 cache->set(EntryToIndex(entry), src);
11782 cache->set(EntryToIndex(entry) + 1, value);
11783 cache->ElementAdded();
11784 return cache;
11785}
11786
11787
John Reck59135872010-11-02 12:39:01 -070011788MaybeObject* CompilationCacheTable::PutEval(String* src,
11789 Context* context,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011790 SharedFunctionInfo* value,
11791 int scope_position) {
Steve Block1e0659c2011-05-24 12:43:12 +010011792 StringSharedKey key(src,
11793 context->closure()->shared(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011794 value->language_mode(),
11795 scope_position);
John Reck59135872010-11-02 12:39:01 -070011796 Object* obj;
11797 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11798 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11799 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011800
11801 CompilationCacheTable* cache =
11802 reinterpret_cast<CompilationCacheTable*>(obj);
11803 int entry = cache->FindInsertionEntry(key.Hash());
11804
John Reck59135872010-11-02 12:39:01 -070011805 Object* k;
11806 { MaybeObject* maybe_k = key.AsObject();
11807 if (!maybe_k->ToObject(&k)) return maybe_k;
11808 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011809
11810 cache->set(EntryToIndex(entry), k);
11811 cache->set(EntryToIndex(entry) + 1, value);
11812 cache->ElementAdded();
11813 return cache;
11814}
11815
11816
John Reck59135872010-11-02 12:39:01 -070011817MaybeObject* CompilationCacheTable::PutRegExp(String* src,
11818 JSRegExp::Flags flags,
11819 FixedArray* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011820 RegExpKey key(src, flags);
John Reck59135872010-11-02 12:39:01 -070011821 Object* obj;
11822 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11823 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11824 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011825
11826 CompilationCacheTable* cache =
11827 reinterpret_cast<CompilationCacheTable*>(obj);
11828 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000011829 // We store the value in the key slot, and compare the search key
11830 // to the stored value with a custon IsMatch function during lookups.
Steve Blocka7e24c12009-10-30 11:49:00 +000011831 cache->set(EntryToIndex(entry), value);
11832 cache->set(EntryToIndex(entry) + 1, value);
11833 cache->ElementAdded();
11834 return cache;
11835}
11836
11837
Ben Murdochb0fe1622011-05-05 13:52:32 +010011838void CompilationCacheTable::Remove(Object* value) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011839 Object* the_hole_value = GetHeap()->the_hole_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010011840 for (int entry = 0, size = Capacity(); entry < size; entry++) {
11841 int entry_index = EntryToIndex(entry);
11842 int value_index = entry_index + 1;
11843 if (get(value_index) == value) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011844 NoWriteBarrierSet(this, entry_index, the_hole_value);
11845 NoWriteBarrierSet(this, value_index, the_hole_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011846 ElementRemoved();
11847 }
11848 }
11849 return;
11850}
11851
11852
Steve Blocka7e24c12009-10-30 11:49:00 +000011853// SymbolsKey used for HashTable where key is array of symbols.
11854class SymbolsKey : public HashTableKey {
11855 public:
11856 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
11857
11858 bool IsMatch(Object* symbols) {
11859 FixedArray* o = FixedArray::cast(symbols);
11860 int len = symbols_->length();
11861 if (o->length() != len) return false;
11862 for (int i = 0; i < len; i++) {
11863 if (o->get(i) != symbols_->get(i)) return false;
11864 }
11865 return true;
11866 }
11867
11868 uint32_t Hash() { return HashForObject(symbols_); }
11869
11870 uint32_t HashForObject(Object* obj) {
11871 FixedArray* symbols = FixedArray::cast(obj);
11872 int len = symbols->length();
11873 uint32_t hash = 0;
11874 for (int i = 0; i < len; i++) {
11875 hash ^= String::cast(symbols->get(i))->Hash();
11876 }
11877 return hash;
11878 }
11879
11880 Object* AsObject() { return symbols_; }
11881
11882 private:
11883 FixedArray* symbols_;
11884};
11885
11886
11887Object* MapCache::Lookup(FixedArray* array) {
11888 SymbolsKey key(array);
11889 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011890 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011891 return get(EntryToIndex(entry) + 1);
11892}
11893
11894
John Reck59135872010-11-02 12:39:01 -070011895MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011896 SymbolsKey key(array);
John Reck59135872010-11-02 12:39:01 -070011897 Object* obj;
11898 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11899 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11900 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011901
11902 MapCache* cache = reinterpret_cast<MapCache*>(obj);
11903 int entry = cache->FindInsertionEntry(key.Hash());
11904 cache->set(EntryToIndex(entry), array);
11905 cache->set(EntryToIndex(entry) + 1, value);
11906 cache->ElementAdded();
11907 return cache;
11908}
11909
11910
11911template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011912MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
11913 Object* obj;
11914 { MaybeObject* maybe_obj =
11915 HashTable<Shape, Key>::Allocate(at_least_space_for);
11916 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000011917 }
John Reck59135872010-11-02 12:39:01 -070011918 // Initialize the next enumeration index.
11919 Dictionary<Shape, Key>::cast(obj)->
11920 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
Steve Blocka7e24c12009-10-30 11:49:00 +000011921 return obj;
11922}
11923
11924
11925template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011926MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Steve Block44f0eee2011-05-26 01:26:41 +010011927 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000011928 int length = HashTable<Shape, Key>::NumberOfElements();
11929
11930 // Allocate and initialize iteration order array.
John Reck59135872010-11-02 12:39:01 -070011931 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +010011932 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070011933 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11934 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011935 FixedArray* iteration_order = FixedArray::cast(obj);
11936 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000011937 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000011938 }
11939
11940 // Allocate array with enumeration order.
Steve Block44f0eee2011-05-26 01:26:41 +010011941 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070011942 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11943 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011944 FixedArray* enumeration_order = FixedArray::cast(obj);
11945
11946 // Fill the enumeration order array with property details.
11947 int capacity = HashTable<Shape, Key>::Capacity();
11948 int pos = 0;
11949 for (int i = 0; i < capacity; i++) {
11950 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
Leon Clarke4515c472010-02-03 11:58:03 +000011951 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011952 }
11953 }
11954
11955 // Sort the arrays wrt. enumeration order.
11956 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
11957
11958 // Overwrite the enumeration_order with the enumeration indices.
11959 for (int i = 0; i < length; i++) {
11960 int index = Smi::cast(iteration_order->get(i))->value();
11961 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +000011962 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +000011963 }
11964
11965 // Update the dictionary with new indices.
11966 capacity = HashTable<Shape, Key>::Capacity();
11967 pos = 0;
11968 for (int i = 0; i < capacity; i++) {
11969 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
11970 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
11971 PropertyDetails details = DetailsAt(i);
11972 PropertyDetails new_details =
11973 PropertyDetails(details.attributes(), details.type(), enum_index);
11974 DetailsAtPut(i, new_details);
11975 }
11976 }
11977
11978 // Set the next enumeration index.
11979 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
11980 return this;
11981}
11982
11983template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011984MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011985 // Check whether there are enough enumeration indices to add n elements.
11986 if (Shape::kIsEnumerable &&
11987 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
11988 // If not, we generate new indices for the properties.
John Reck59135872010-11-02 12:39:01 -070011989 Object* result;
11990 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
11991 if (!maybe_result->ToObject(&result)) return maybe_result;
11992 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011993 }
11994 return HashTable<Shape, Key>::EnsureCapacity(n, key);
11995}
11996
11997
Steve Blocka7e24c12009-10-30 11:49:00 +000011998template<typename Shape, typename Key>
11999Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012000 JSReceiver::DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +010012001 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000012002 PropertyDetails details = DetailsAt(entry);
12003 // Ignore attributes if forcing a deletion.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012004 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
Steve Block44f0eee2011-05-26 01:26:41 +010012005 return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012006 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012007 SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012008 HashTable<Shape, Key>::ElementRemoved();
Steve Block44f0eee2011-05-26 01:26:41 +010012009 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012010}
12011
12012
12013template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012014MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
12015 return HashTable<Shape, Key>::Shrink(key);
12016}
12017
12018
12019template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070012020MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012021 int entry = this->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000012022
12023 // If the entry is present set the value;
12024 if (entry != Dictionary<Shape, Key>::kNotFound) {
12025 ValueAtPut(entry, value);
12026 return this;
12027 }
12028
12029 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070012030 Object* obj;
12031 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12032 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12033 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012034
John Reck59135872010-11-02 12:39:01 -070012035 Object* k;
12036 { MaybeObject* maybe_k = Shape::AsObject(key);
12037 if (!maybe_k->ToObject(&k)) return maybe_k;
12038 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012039 PropertyDetails details = PropertyDetails(NONE, NORMAL);
Ben Murdochc7cc0282012-03-05 14:35:55 +000012040
12041 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12042 Dictionary<Shape, Key>::Hash(key));
Steve Blocka7e24c12009-10-30 11:49:00 +000012043}
12044
12045
12046template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070012047MaybeObject* Dictionary<Shape, Key>::Add(Key key,
12048 Object* value,
12049 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012050 // Valdate key is absent.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012051 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000012052 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070012053 Object* obj;
12054 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12055 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12056 }
Ben Murdochc7cc0282012-03-05 14:35:55 +000012057
12058 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12059 Dictionary<Shape, Key>::Hash(key));
Steve Blocka7e24c12009-10-30 11:49:00 +000012060}
12061
12062
12063// Add a key, value pair to the dictionary.
12064template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070012065MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
12066 Object* value,
12067 PropertyDetails details,
12068 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012069 // Compute the key object.
John Reck59135872010-11-02 12:39:01 -070012070 Object* k;
12071 { MaybeObject* maybe_k = Shape::AsObject(key);
12072 if (!maybe_k->ToObject(&k)) return maybe_k;
12073 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012074
12075 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
12076 // Insert element at empty or deleted entry
12077 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
12078 // Assign an enumeration index to the property and update
12079 // SetNextEnumerationIndex.
12080 int index = NextEnumerationIndex();
12081 details = PropertyDetails(details.attributes(), details.type(), index);
12082 SetNextEnumerationIndex(index + 1);
12083 }
12084 SetEntry(entry, k, value, details);
12085 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
12086 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
12087 HashTable<Shape, Key>::ElementAdded();
12088 return this;
12089}
12090
12091
Ben Murdochc7cc0282012-03-05 14:35:55 +000012092void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012093 // If the dictionary requires slow elements an element has already
12094 // been added at a high index.
12095 if (requires_slow_elements()) return;
12096 // Check if this index is high enough that we should require slow
12097 // elements.
12098 if (key > kRequiresSlowElementsLimit) {
12099 set_requires_slow_elements();
12100 return;
12101 }
12102 // Update max key value.
12103 Object* max_index_object = get(kMaxNumberKeyIndex);
12104 if (!max_index_object->IsSmi() || max_number_key() < key) {
12105 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000012106 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000012107 }
12108}
12109
12110
Ben Murdochc7cc0282012-03-05 14:35:55 +000012111MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
12112 Object* value,
12113 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012114 UpdateMaxNumberKey(key);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010012115 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +000012116 return Add(key, value, details);
12117}
12118
12119
Ben Murdochc7cc0282012-03-05 14:35:55 +000012120MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
12121 Object* value) {
12122 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
12123 return Add(key, value, PropertyDetails(NONE, NORMAL));
12124}
12125
12126
12127MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012128 UpdateMaxNumberKey(key);
12129 return AtPut(key, value);
12130}
12131
12132
Ben Murdochc7cc0282012-03-05 14:35:55 +000012133MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
12134 Object* value) {
12135 return AtPut(key, value);
12136}
12137
12138
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012139Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
12140 Handle<SeededNumberDictionary> dictionary,
12141 uint32_t index,
12142 Handle<Object> value,
12143 PropertyDetails details) {
12144 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12145 dictionary->Set(index, *value, details),
12146 SeededNumberDictionary);
12147}
12148
12149
12150Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
12151 Handle<UnseededNumberDictionary> dictionary,
12152 uint32_t index,
12153 Handle<Object> value) {
12154 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12155 dictionary->Set(index, *value),
12156 UnseededNumberDictionary);
12157}
12158
12159
Ben Murdochc7cc0282012-03-05 14:35:55 +000012160MaybeObject* SeededNumberDictionary::Set(uint32_t key,
12161 Object* value,
12162 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012163 int entry = FindEntry(key);
12164 if (entry == kNotFound) return AddNumberEntry(key, value, details);
12165 // Preserve enumeration index.
12166 details = PropertyDetails(details.attributes(),
12167 details.type(),
12168 DetailsAt(entry).index());
Ben Murdochc7cc0282012-03-05 14:35:55 +000012169 MaybeObject* maybe_object_key = SeededNumberDictionaryShape::AsObject(key);
John Reck59135872010-11-02 12:39:01 -070012170 Object* object_key;
12171 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
Ben Murdochf87a2032010-10-22 12:50:53 +010012172 SetEntry(entry, object_key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000012173 return this;
12174}
12175
12176
Ben Murdochc7cc0282012-03-05 14:35:55 +000012177MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
12178 Object* value) {
12179 int entry = FindEntry(key);
12180 if (entry == kNotFound) return AddNumberEntry(key, value);
12181 MaybeObject* maybe_object_key = UnseededNumberDictionaryShape::AsObject(key);
12182 Object* object_key;
12183 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
12184 SetEntry(entry, object_key, value);
12185 return this;
12186}
12187
12188
Steve Blocka7e24c12009-10-30 11:49:00 +000012189
12190template<typename Shape, typename Key>
12191int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
12192 PropertyAttributes filter) {
12193 int capacity = HashTable<Shape, Key>::Capacity();
12194 int result = 0;
12195 for (int i = 0; i < capacity; i++) {
12196 Object* k = HashTable<Shape, Key>::KeyAt(i);
12197 if (HashTable<Shape, Key>::IsKey(k)) {
12198 PropertyDetails details = DetailsAt(i);
12199 if (details.IsDeleted()) continue;
12200 PropertyAttributes attr = details.attributes();
12201 if ((attr & filter) == 0) result++;
12202 }
12203 }
12204 return result;
12205}
12206
12207
12208template<typename Shape, typename Key>
12209int Dictionary<Shape, Key>::NumberOfEnumElements() {
12210 return NumberOfElementsFilterAttributes(
12211 static_cast<PropertyAttributes>(DONT_ENUM));
12212}
12213
12214
12215template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012216void Dictionary<Shape, Key>::CopyKeysTo(
12217 FixedArray* storage,
12218 PropertyAttributes filter,
12219 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012220 ASSERT(storage->length() >= NumberOfEnumElements());
12221 int capacity = HashTable<Shape, Key>::Capacity();
12222 int index = 0;
12223 for (int i = 0; i < capacity; i++) {
12224 Object* k = HashTable<Shape, Key>::KeyAt(i);
12225 if (HashTable<Shape, Key>::IsKey(k)) {
12226 PropertyDetails details = DetailsAt(i);
12227 if (details.IsDeleted()) continue;
12228 PropertyAttributes attr = details.attributes();
12229 if ((attr & filter) == 0) storage->set(index++, k);
12230 }
12231 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012232 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12233 storage->SortPairs(storage, index);
12234 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012235 ASSERT(storage->length() >= index);
12236}
12237
12238
12239void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
12240 FixedArray* sort_array) {
12241 ASSERT(storage->length() >= NumberOfEnumElements());
12242 int capacity = Capacity();
12243 int index = 0;
12244 for (int i = 0; i < capacity; i++) {
12245 Object* k = KeyAt(i);
12246 if (IsKey(k)) {
12247 PropertyDetails details = DetailsAt(i);
12248 if (details.IsDeleted() || details.IsDontEnum()) continue;
12249 storage->set(index, k);
Leon Clarke4515c472010-02-03 11:58:03 +000012250 sort_array->set(index, Smi::FromInt(details.index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000012251 index++;
12252 }
12253 }
12254 storage->SortPairs(sort_array, sort_array->length());
12255 ASSERT(storage->length() >= index);
12256}
12257
12258
12259template<typename Shape, typename Key>
Ben Murdoch6d7cb002011-08-04 19:25:22 +010012260void Dictionary<Shape, Key>::CopyKeysTo(
Ben Murdoch257744e2011-11-30 15:57:28 +000012261 FixedArray* storage,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012262 int index,
12263 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012264 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
12265 static_cast<PropertyAttributes>(NONE)));
12266 int capacity = HashTable<Shape, Key>::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000012267 for (int i = 0; i < capacity; i++) {
12268 Object* k = HashTable<Shape, Key>::KeyAt(i);
12269 if (HashTable<Shape, Key>::IsKey(k)) {
12270 PropertyDetails details = DetailsAt(i);
12271 if (details.IsDeleted()) continue;
12272 storage->set(index++, k);
12273 }
12274 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012275 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12276 storage->SortPairs(storage, index);
12277 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012278 ASSERT(storage->length() >= index);
12279}
12280
12281
12282// Backwards lookup (slow).
12283template<typename Shape, typename Key>
12284Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
12285 int capacity = HashTable<Shape, Key>::Capacity();
12286 for (int i = 0; i < capacity; i++) {
12287 Object* k = HashTable<Shape, Key>::KeyAt(i);
12288 if (Dictionary<Shape, Key>::IsKey(k)) {
12289 Object* e = ValueAt(i);
12290 if (e->IsJSGlobalPropertyCell()) {
12291 e = JSGlobalPropertyCell::cast(e)->value();
12292 }
12293 if (e == value) return k;
12294 }
12295 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010012296 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010012297 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012298}
12299
12300
John Reck59135872010-11-02 12:39:01 -070012301MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Steve Blocka7e24c12009-10-30 11:49:00 +000012302 JSObject* obj, int unused_property_fields) {
12303 // Make sure we preserve dictionary representation if there are too many
12304 // descriptors.
12305 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
12306
12307 // Figure out if it is necessary to generate new enumeration indices.
12308 int max_enumeration_index =
12309 NextEnumerationIndex() +
12310 (DescriptorArray::kMaxNumberOfDescriptors -
12311 NumberOfElements());
12312 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
John Reck59135872010-11-02 12:39:01 -070012313 Object* result;
12314 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12315 if (!maybe_result->ToObject(&result)) return maybe_result;
12316 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012317 }
12318
12319 int instance_descriptor_length = 0;
12320 int number_of_fields = 0;
12321
Ben Murdoch8b112d22011-06-08 16:22:53 +010012322 Heap* heap = GetHeap();
12323
Steve Blocka7e24c12009-10-30 11:49:00 +000012324 // Compute the length of the instance descriptor.
12325 int capacity = Capacity();
12326 for (int i = 0; i < capacity; i++) {
12327 Object* k = KeyAt(i);
12328 if (IsKey(k)) {
12329 Object* value = ValueAt(i);
12330 PropertyType type = DetailsAt(i).type();
12331 ASSERT(type != FIELD);
12332 instance_descriptor_length++;
Leon Clarkee46be812010-01-19 14:06:41 +000012333 if (type == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +010012334 (!value->IsJSFunction() || heap->InNewSpace(value))) {
Leon Clarkee46be812010-01-19 14:06:41 +000012335 number_of_fields += 1;
12336 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012337 }
12338 }
12339
12340 // Allocate the instance descriptor.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012341 DescriptorArray* descriptors;
12342 { MaybeObject* maybe_descriptors =
John Reck59135872010-11-02 12:39:01 -070012343 DescriptorArray::Allocate(instance_descriptor_length);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012344 if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) {
12345 return maybe_descriptors;
John Reck59135872010-11-02 12:39:01 -070012346 }
12347 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012348
12349 DescriptorArray::WhitenessWitness witness(descriptors);
Steve Blocka7e24c12009-10-30 11:49:00 +000012350
12351 int inobject_props = obj->map()->inobject_properties();
12352 int number_of_allocated_fields =
12353 number_of_fields + unused_property_fields - inobject_props;
Ben Murdochf87a2032010-10-22 12:50:53 +010012354 if (number_of_allocated_fields < 0) {
12355 // There is enough inobject space for all fields (including unused).
12356 number_of_allocated_fields = 0;
12357 unused_property_fields = inobject_props - number_of_fields;
12358 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012359
12360 // Allocate the fixed array for the fields.
John Reck59135872010-11-02 12:39:01 -070012361 Object* fields;
12362 { MaybeObject* maybe_fields =
Steve Block44f0eee2011-05-26 01:26:41 +010012363 heap->AllocateFixedArray(number_of_allocated_fields);
John Reck59135872010-11-02 12:39:01 -070012364 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
12365 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012366
12367 // Fill in the instance descriptor and the fields.
12368 int next_descriptor = 0;
12369 int current_offset = 0;
12370 for (int i = 0; i < capacity; i++) {
12371 Object* k = KeyAt(i);
12372 if (IsKey(k)) {
12373 Object* value = ValueAt(i);
12374 // Ensure the key is a symbol before writing into the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070012375 Object* key;
Steve Block44f0eee2011-05-26 01:26:41 +010012376 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
John Reck59135872010-11-02 12:39:01 -070012377 if (!maybe_key->ToObject(&key)) return maybe_key;
12378 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012379 PropertyDetails details = DetailsAt(i);
12380 PropertyType type = details.type();
12381
Steve Block44f0eee2011-05-26 01:26:41 +010012382 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012383 ConstantFunctionDescriptor d(String::cast(key),
12384 JSFunction::cast(value),
12385 details.attributes(),
12386 details.index());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012387 descriptors->Set(next_descriptor++, &d, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012388 } else if (type == NORMAL) {
12389 if (current_offset < inobject_props) {
12390 obj->InObjectPropertyAtPut(current_offset,
12391 value,
12392 UPDATE_WRITE_BARRIER);
12393 } else {
12394 int offset = current_offset - inobject_props;
12395 FixedArray::cast(fields)->set(offset, value);
12396 }
12397 FieldDescriptor d(String::cast(key),
12398 current_offset++,
12399 details.attributes(),
12400 details.index());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012401 descriptors->Set(next_descriptor++, &d, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012402 } else if (type == CALLBACKS) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012403 if (value->IsAccessorPair()) {
12404 MaybeObject* maybe_copy =
12405 AccessorPair::cast(value)->CopyWithoutTransitions();
12406 if (!maybe_copy->To(&value)) return maybe_copy;
12407 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012408 CallbacksDescriptor d(String::cast(key),
12409 value,
12410 details.attributes(),
12411 details.index());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012412 descriptors->Set(next_descriptor++, &d, witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012413 } else {
12414 UNREACHABLE();
12415 }
12416 }
12417 }
12418 ASSERT(current_offset == number_of_fields);
12419
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012420 descriptors->Sort(witness);
Steve Blocka7e24c12009-10-30 11:49:00 +000012421 // Allocate new map.
John Reck59135872010-11-02 12:39:01 -070012422 Object* new_map;
12423 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
12424 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
12425 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012426
12427 // Transform the object.
12428 obj->set_map(Map::cast(new_map));
12429 obj->map()->set_instance_descriptors(descriptors);
12430 obj->map()->set_unused_property_fields(unused_property_fields);
12431
12432 obj->set_properties(FixedArray::cast(fields));
12433 ASSERT(obj->IsJSObject());
12434
12435 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
12436 // Check that it really works.
12437 ASSERT(obj->HasFastProperties());
12438
12439 return obj;
12440}
12441
12442
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012443bool ObjectHashSet::Contains(Object* key) {
12444 ASSERT(IsKey(key));
12445
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012446 // If the object does not have an identity hash, it was never used as a key.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012447 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12448 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
12449 }
12450 return (FindEntry(key) != kNotFound);
12451}
12452
12453
12454MaybeObject* ObjectHashSet::Add(Object* key) {
12455 ASSERT(IsKey(key));
12456
12457 // Make sure the key object has an identity hash code.
12458 int hash;
12459 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12460 if (maybe_hash->IsFailure()) return maybe_hash;
12461 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12462 }
12463 int entry = FindEntry(key);
12464
12465 // Check whether key is already present.
12466 if (entry != kNotFound) return this;
12467
12468 // Check whether the hash set should be extended and add entry.
12469 Object* obj;
12470 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12471 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12472 }
12473 ObjectHashSet* table = ObjectHashSet::cast(obj);
12474 entry = table->FindInsertionEntry(hash);
12475 table->set(EntryToIndex(entry), key);
12476 table->ElementAdded();
12477 return table;
12478}
12479
12480
12481MaybeObject* ObjectHashSet::Remove(Object* key) {
12482 ASSERT(IsKey(key));
12483
12484 // If the object does not have an identity hash, it was never used as a key.
12485 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12486 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
12487 }
12488 int entry = FindEntry(key);
12489
12490 // Check whether key is actually present.
12491 if (entry == kNotFound) return this;
12492
12493 // Remove entry and try to shrink this hash set.
12494 set_the_hole(EntryToIndex(entry));
12495 ElementRemoved();
12496 return Shrink(key);
12497}
12498
12499
12500Object* ObjectHashTable::Lookup(Object* key) {
12501 ASSERT(IsKey(key));
12502
12503 // If the object does not have an identity hash, it was never used as a key.
12504 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12505 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
12506 return GetHeap()->undefined_value();
12507 }
12508 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012509 int entry = FindEntry(key);
12510 if (entry == kNotFound) return GetHeap()->undefined_value();
12511 return get(EntryToIndex(entry) + 1);
12512}
12513
12514
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012515MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
12516 ASSERT(IsKey(key));
12517
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012518 // Make sure the key object has an identity hash code.
12519 int hash;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012520 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012521 if (maybe_hash->IsFailure()) return maybe_hash;
12522 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12523 }
12524 int entry = FindEntry(key);
12525
12526 // Check whether to perform removal operation.
12527 if (value->IsUndefined()) {
12528 if (entry == kNotFound) return this;
12529 RemoveEntry(entry);
12530 return Shrink(key);
12531 }
12532
12533 // Key is already in table, just overwrite value.
12534 if (entry != kNotFound) {
12535 set(EntryToIndex(entry) + 1, value);
12536 return this;
12537 }
12538
12539 // Check whether the hash table should be extended.
12540 Object* obj;
12541 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12542 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12543 }
12544 ObjectHashTable* table = ObjectHashTable::cast(obj);
12545 table->AddEntry(table->FindInsertionEntry(hash), key, value);
12546 return table;
12547}
12548
12549
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012550void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012551 set(EntryToIndex(entry), key);
12552 set(EntryToIndex(entry) + 1, value);
12553 ElementAdded();
12554}
12555
12556
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012557void ObjectHashTable::RemoveEntry(int entry) {
12558 set_the_hole(EntryToIndex(entry));
12559 set_the_hole(EntryToIndex(entry) + 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012560 ElementRemoved();
12561}
12562
12563
Steve Blocka7e24c12009-10-30 11:49:00 +000012564#ifdef ENABLE_DEBUGGER_SUPPORT
12565// Check if there is a break point at this code position.
12566bool DebugInfo::HasBreakPoint(int code_position) {
12567 // Get the break point info object for this code position.
12568 Object* break_point_info = GetBreakPointInfo(code_position);
12569
12570 // If there is no break point info object or no break points in the break
12571 // point info object there is no break point at this code position.
12572 if (break_point_info->IsUndefined()) return false;
12573 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
12574}
12575
12576
12577// Get the break point info object for this code position.
12578Object* DebugInfo::GetBreakPointInfo(int code_position) {
12579 // Find the index of the break point info object for this code position.
12580 int index = GetBreakPointInfoIndex(code_position);
12581
12582 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010012583 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012584 return BreakPointInfo::cast(break_points()->get(index));
12585}
12586
12587
12588// Clear a break point at the specified code position.
12589void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
12590 int code_position,
12591 Handle<Object> break_point_object) {
12592 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12593 if (break_point_info->IsUndefined()) return;
12594 BreakPointInfo::ClearBreakPoint(
12595 Handle<BreakPointInfo>::cast(break_point_info),
12596 break_point_object);
12597}
12598
12599
12600void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
12601 int code_position,
12602 int source_position,
12603 int statement_position,
12604 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010012605 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000012606 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12607 if (!break_point_info->IsUndefined()) {
12608 BreakPointInfo::SetBreakPoint(
12609 Handle<BreakPointInfo>::cast(break_point_info),
12610 break_point_object);
12611 return;
12612 }
12613
12614 // Adding a new break point for a code position which did not have any
12615 // break points before. Try to find a free slot.
12616 int index = kNoBreakPointInfo;
12617 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12618 if (debug_info->break_points()->get(i)->IsUndefined()) {
12619 index = i;
12620 break;
12621 }
12622 }
12623 if (index == kNoBreakPointInfo) {
12624 // No free slot - extend break point info array.
12625 Handle<FixedArray> old_break_points =
12626 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000012627 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010012628 isolate->factory()->NewFixedArray(
12629 old_break_points->length() +
12630 Debug::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010012631
12632 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000012633 for (int i = 0; i < old_break_points->length(); i++) {
12634 new_break_points->set(i, old_break_points->get(i));
12635 }
12636 index = old_break_points->length();
12637 }
12638 ASSERT(index != kNoBreakPointInfo);
12639
12640 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010012641 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
12642 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000012643 new_break_point_info->set_code_position(Smi::FromInt(code_position));
12644 new_break_point_info->set_source_position(Smi::FromInt(source_position));
12645 new_break_point_info->
12646 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010012647 new_break_point_info->set_break_point_objects(
12648 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012649 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
12650 debug_info->break_points()->set(index, *new_break_point_info);
12651}
12652
12653
12654// Get the break point objects for a code position.
12655Object* DebugInfo::GetBreakPointObjects(int code_position) {
12656 Object* break_point_info = GetBreakPointInfo(code_position);
12657 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010012658 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012659 }
12660 return BreakPointInfo::cast(break_point_info)->break_point_objects();
12661}
12662
12663
12664// Get the total number of break points.
12665int DebugInfo::GetBreakPointCount() {
12666 if (break_points()->IsUndefined()) return 0;
12667 int count = 0;
12668 for (int i = 0; i < break_points()->length(); i++) {
12669 if (!break_points()->get(i)->IsUndefined()) {
12670 BreakPointInfo* break_point_info =
12671 BreakPointInfo::cast(break_points()->get(i));
12672 count += break_point_info->GetBreakPointCount();
12673 }
12674 }
12675 return count;
12676}
12677
12678
12679Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
12680 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010012681 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010012682 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012683 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12684 if (!debug_info->break_points()->get(i)->IsUndefined()) {
12685 Handle<BreakPointInfo> break_point_info =
12686 Handle<BreakPointInfo>(BreakPointInfo::cast(
12687 debug_info->break_points()->get(i)));
12688 if (BreakPointInfo::HasBreakPointObject(break_point_info,
12689 break_point_object)) {
12690 return *break_point_info;
12691 }
12692 }
12693 }
Steve Block44f0eee2011-05-26 01:26:41 +010012694 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012695}
12696
12697
12698// Find the index of the break point info object for the specified code
12699// position.
12700int DebugInfo::GetBreakPointInfoIndex(int code_position) {
12701 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
12702 for (int i = 0; i < break_points()->length(); i++) {
12703 if (!break_points()->get(i)->IsUndefined()) {
12704 BreakPointInfo* break_point_info =
12705 BreakPointInfo::cast(break_points()->get(i));
12706 if (break_point_info->code_position()->value() == code_position) {
12707 return i;
12708 }
12709 }
12710 }
12711 return kNoBreakPointInfo;
12712}
12713
12714
12715// Remove the specified break point object.
12716void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
12717 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010012718 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000012719 // If there are no break points just ignore.
12720 if (break_point_info->break_point_objects()->IsUndefined()) return;
12721 // If there is a single break point clear it if it is the same.
12722 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12723 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010012724 break_point_info->set_break_point_objects(
12725 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000012726 }
12727 return;
12728 }
12729 // If there are multiple break points shrink the array
12730 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
12731 Handle<FixedArray> old_array =
12732 Handle<FixedArray>(
12733 FixedArray::cast(break_point_info->break_point_objects()));
12734 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010012735 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000012736 int found_count = 0;
12737 for (int i = 0; i < old_array->length(); i++) {
12738 if (old_array->get(i) == *break_point_object) {
12739 ASSERT(found_count == 0);
12740 found_count++;
12741 } else {
12742 new_array->set(i - found_count, old_array->get(i));
12743 }
12744 }
12745 // If the break point was found in the list change it.
12746 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
12747}
12748
12749
12750// Add the specified break point object.
12751void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
12752 Handle<Object> break_point_object) {
12753 // If there was no break point objects before just set it.
12754 if (break_point_info->break_point_objects()->IsUndefined()) {
12755 break_point_info->set_break_point_objects(*break_point_object);
12756 return;
12757 }
12758 // If the break point object is the same as before just ignore.
12759 if (break_point_info->break_point_objects() == *break_point_object) return;
12760 // If there was one break point object before replace with array.
12761 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Steve Block44f0eee2011-05-26 01:26:41 +010012762 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000012763 array->set(0, break_point_info->break_point_objects());
12764 array->set(1, *break_point_object);
12765 break_point_info->set_break_point_objects(*array);
12766 return;
12767 }
12768 // If there was more than one break point before extend array.
12769 Handle<FixedArray> old_array =
12770 Handle<FixedArray>(
12771 FixedArray::cast(break_point_info->break_point_objects()));
12772 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010012773 FACTORY->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000012774 for (int i = 0; i < old_array->length(); i++) {
12775 // If the break point was there before just ignore.
12776 if (old_array->get(i) == *break_point_object) return;
12777 new_array->set(i, old_array->get(i));
12778 }
12779 // Add the new break point.
12780 new_array->set(old_array->length(), *break_point_object);
12781 break_point_info->set_break_point_objects(*new_array);
12782}
12783
12784
12785bool BreakPointInfo::HasBreakPointObject(
12786 Handle<BreakPointInfo> break_point_info,
12787 Handle<Object> break_point_object) {
12788 // No break point.
12789 if (break_point_info->break_point_objects()->IsUndefined()) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012790 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000012791 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12792 return break_point_info->break_point_objects() == *break_point_object;
12793 }
12794 // Multiple break points.
12795 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
12796 for (int i = 0; i < array->length(); i++) {
12797 if (array->get(i) == *break_point_object) {
12798 return true;
12799 }
12800 }
12801 return false;
12802}
12803
12804
12805// Get the number of break points.
12806int BreakPointInfo::GetBreakPointCount() {
12807 // No break point.
12808 if (break_point_objects()->IsUndefined()) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012809 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000012810 if (!break_point_objects()->IsFixedArray()) return 1;
12811 // Multiple break points.
12812 return FixedArray::cast(break_point_objects())->length();
12813}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012814#endif // ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +000012815
12816
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012817MaybeObject* JSDate::GetField(Object* object, Smi* index) {
12818 return JSDate::cast(object)->DoGetField(
12819 static_cast<FieldIndex>(index->value()));
12820}
12821
12822
12823Object* JSDate::DoGetField(FieldIndex index) {
12824 ASSERT(index != kDateValue);
12825
12826 DateCache* date_cache = GetIsolate()->date_cache();
12827
12828 if (index < kFirstUncachedField) {
12829 Object* stamp = cache_stamp();
12830 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
12831 // Since the stamp is not NaN, the value is also not NaN.
12832 int64_t local_time_ms =
12833 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
12834 SetLocalFields(local_time_ms, date_cache);
12835 }
12836 switch (index) {
12837 case kYear: return year();
12838 case kMonth: return month();
12839 case kDay: return day();
12840 case kWeekday: return weekday();
12841 case kHour: return hour();
12842 case kMinute: return min();
12843 case kSecond: return sec();
12844 default: UNREACHABLE();
12845 }
12846 }
12847
12848 if (index >= kFirstUTCField) {
12849 return GetUTCField(index, value()->Number(), date_cache);
12850 }
12851
12852 double time = value()->Number();
12853 if (isnan(time)) return GetIsolate()->heap()->nan_value();
12854
12855 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
12856 int days = DateCache::DaysFromTime(local_time_ms);
12857
12858 if (index == kDays) return Smi::FromInt(days);
12859
12860 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
12861 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
12862 ASSERT(index == kTimeInDay);
12863 return Smi::FromInt(time_in_day_ms);
12864}
12865
12866
12867Object* JSDate::GetUTCField(FieldIndex index,
12868 double value,
12869 DateCache* date_cache) {
12870 ASSERT(index >= kFirstUTCField);
12871
12872 if (isnan(value)) return GetIsolate()->heap()->nan_value();
12873
12874 int64_t time_ms = static_cast<int64_t>(value);
12875
12876 if (index == kTimezoneOffset) {
12877 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
12878 }
12879
12880 int days = DateCache::DaysFromTime(time_ms);
12881
12882 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
12883
12884 if (index <= kDayUTC) {
12885 int year, month, day;
12886 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
12887 if (index == kYearUTC) return Smi::FromInt(year);
12888 if (index == kMonthUTC) return Smi::FromInt(month);
12889 ASSERT(index == kDayUTC);
12890 return Smi::FromInt(day);
12891 }
12892
12893 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
12894 switch (index) {
12895 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
12896 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
12897 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
12898 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
12899 case kDaysUTC: return Smi::FromInt(days);
12900 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
12901 default: UNREACHABLE();
12902 }
12903
12904 UNREACHABLE();
12905 return NULL;
12906}
12907
12908
12909void JSDate::SetValue(Object* value, bool is_value_nan) {
12910 set_value(value);
12911 if (is_value_nan) {
12912 HeapNumber* nan = GetIsolate()->heap()->nan_value();
12913 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
12914 set_year(nan, SKIP_WRITE_BARRIER);
12915 set_month(nan, SKIP_WRITE_BARRIER);
12916 set_day(nan, SKIP_WRITE_BARRIER);
12917 set_hour(nan, SKIP_WRITE_BARRIER);
12918 set_min(nan, SKIP_WRITE_BARRIER);
12919 set_sec(nan, SKIP_WRITE_BARRIER);
12920 set_weekday(nan, SKIP_WRITE_BARRIER);
12921 } else {
12922 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
12923 }
12924}
12925
12926
12927void JSDate::SetLocalFields(int64_t local_time_ms, DateCache* date_cache) {
12928 int days = DateCache::DaysFromTime(local_time_ms);
12929 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
12930 int year, month, day;
12931 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
12932 int weekday = date_cache->Weekday(days);
12933 int hour = time_in_day_ms / (60 * 60 * 1000);
12934 int min = (time_in_day_ms / (60 * 1000)) % 60;
12935 int sec = (time_in_day_ms / 1000) % 60;
12936 set_cache_stamp(date_cache->stamp());
12937 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
12938 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
12939 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
12940 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
12941 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
12942 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
12943 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
12944}
12945
Steve Blocka7e24c12009-10-30 11:49:00 +000012946} } // namespace v8::internal