OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 21 matching lines...) Expand all Loading... |
32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
33 #include "codegen.h" | 33 #include "codegen.h" |
34 #include "debug.h" | 34 #include "debug.h" |
35 #include "deoptimizer.h" | 35 #include "deoptimizer.h" |
36 #include "elements.h" | 36 #include "elements.h" |
37 #include "execution.h" | 37 #include "execution.h" |
38 #include "full-codegen.h" | 38 #include "full-codegen.h" |
39 #include "hydrogen.h" | 39 #include "hydrogen.h" |
40 #include "objects-inl.h" | 40 #include "objects-inl.h" |
41 #include "objects-visiting.h" | 41 #include "objects-visiting.h" |
| 42 #include "objects-visiting-inl.h" |
42 #include "macro-assembler.h" | 43 #include "macro-assembler.h" |
| 44 #include "mark-compact.h" |
43 #include "safepoint-table.h" | 45 #include "safepoint-table.h" |
44 #include "string-stream.h" | 46 #include "string-stream.h" |
45 #include "utils.h" | 47 #include "utils.h" |
46 #include "vm-state-inl.h" | 48 #include "vm-state-inl.h" |
47 | 49 |
48 #ifdef ENABLE_DISASSEMBLER | 50 #ifdef ENABLE_DISASSEMBLER |
49 #include "disasm.h" | 51 #include "disasm.h" |
50 #include "disassembler.h" | 52 #include "disassembler.h" |
51 #endif | 53 #endif |
52 | 54 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 } | 127 } |
126 if (heap_object->IsHeapNumber()) { | 128 if (heap_object->IsHeapNumber()) { |
127 return HeapNumber::cast(this)->HeapNumberToBoolean(); | 129 return HeapNumber::cast(this)->HeapNumberToBoolean(); |
128 } | 130 } |
129 return heap_object->GetHeap()->true_value(); | 131 return heap_object->GetHeap()->true_value(); |
130 } | 132 } |
131 | 133 |
132 | 134 |
133 void Object::Lookup(String* name, LookupResult* result) { | 135 void Object::Lookup(String* name, LookupResult* result) { |
134 Object* holder = NULL; | 136 Object* holder = NULL; |
135 if (IsSmi()) { | 137 if (IsJSReceiver()) { |
| 138 holder = this; |
| 139 } else { |
136 Context* global_context = Isolate::Current()->context()->global_context(); | 140 Context* global_context = Isolate::Current()->context()->global_context(); |
137 holder = global_context->number_function()->instance_prototype(); | 141 if (IsNumber()) { |
138 } else { | 142 holder = global_context->number_function()->instance_prototype(); |
139 HeapObject* heap_object = HeapObject::cast(this); | 143 } else if (IsString()) { |
140 if (heap_object->IsJSObject()) { | |
141 return JSObject::cast(this)->Lookup(name, result); | |
142 } else if (heap_object->IsJSProxy()) { | |
143 return result->HandlerResult(); | |
144 } | |
145 Context* global_context = Isolate::Current()->context()->global_context(); | |
146 if (heap_object->IsString()) { | |
147 holder = global_context->string_function()->instance_prototype(); | 144 holder = global_context->string_function()->instance_prototype(); |
148 } else if (heap_object->IsHeapNumber()) { | 145 } else if (IsBoolean()) { |
149 holder = global_context->number_function()->instance_prototype(); | |
150 } else if (heap_object->IsBoolean()) { | |
151 holder = global_context->boolean_function()->instance_prototype(); | 146 holder = global_context->boolean_function()->instance_prototype(); |
152 } | 147 } |
153 } | 148 } |
154 ASSERT(holder != NULL); // Cannot handle null or undefined. | 149 ASSERT(holder != NULL); // Cannot handle null or undefined. |
155 JSObject::cast(holder)->Lookup(name, result); | 150 JSReceiver::cast(holder)->Lookup(name, result); |
156 } | 151 } |
157 | 152 |
158 | 153 |
159 MaybeObject* Object::GetPropertyWithReceiver(Object* receiver, | 154 MaybeObject* Object::GetPropertyWithReceiver(Object* receiver, |
160 String* name, | 155 String* name, |
161 PropertyAttributes* attributes) { | 156 PropertyAttributes* attributes) { |
162 LookupResult result; | 157 LookupResult result; |
163 Lookup(name, &result); | 158 Lookup(name, &result); |
164 MaybeObject* value = GetProperty(receiver, &result, name, attributes); | 159 MaybeObject* value = GetProperty(receiver, &result, name, attributes); |
165 ASSERT(*attributes <= ABSENT); | 160 ASSERT(*attributes <= ABSENT); |
166 return value; | 161 return value; |
167 } | 162 } |
168 | 163 |
169 | 164 |
170 MaybeObject* Object::GetPropertyWithCallback(Object* receiver, | 165 MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver, |
171 Object* structure, | 166 Object* structure, |
172 String* name, | 167 String* name) { |
173 Object* holder) { | |
174 Isolate* isolate = name->GetIsolate(); | 168 Isolate* isolate = name->GetIsolate(); |
175 // To accommodate both the old and the new api we switch on the | 169 // To accommodate both the old and the new api we switch on the |
176 // data structure used to store the callbacks. Eventually foreign | 170 // data structure used to store the callbacks. Eventually foreign |
177 // callbacks should be phased out. | 171 // callbacks should be phased out. |
178 if (structure->IsForeign()) { | 172 if (structure->IsForeign()) { |
179 AccessorDescriptor* callback = | 173 AccessorDescriptor* callback = |
180 reinterpret_cast<AccessorDescriptor*>( | 174 reinterpret_cast<AccessorDescriptor*>( |
181 Foreign::cast(structure)->address()); | 175 Foreign::cast(structure)->address()); |
182 MaybeObject* value = (callback->getter)(receiver, callback->data); | 176 MaybeObject* value = (callback->getter)(receiver, callback->data); |
183 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 177 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
184 return value; | 178 return value; |
185 } | 179 } |
186 | 180 |
187 // api style callbacks. | 181 // api style callbacks. |
188 if (structure->IsAccessorInfo()) { | 182 if (structure->IsAccessorInfo()) { |
189 AccessorInfo* data = AccessorInfo::cast(structure); | 183 AccessorInfo* data = AccessorInfo::cast(structure); |
190 Object* fun_obj = data->getter(); | 184 Object* fun_obj = data->getter(); |
191 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); | 185 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); |
192 HandleScope scope(isolate); | 186 HandleScope scope(isolate); |
193 JSObject* self = JSObject::cast(receiver); | 187 JSObject* self = JSObject::cast(receiver); |
194 JSObject* holder_handle = JSObject::cast(holder); | |
195 Handle<String> key(name); | 188 Handle<String> key(name); |
196 LOG(isolate, ApiNamedPropertyAccess("load", self, name)); | 189 LOG(isolate, ApiNamedPropertyAccess("load", self, name)); |
197 CustomArguments args(isolate, data->data(), self, holder_handle); | 190 CustomArguments args(isolate, data->data(), self, this); |
198 v8::AccessorInfo info(args.end()); | 191 v8::AccessorInfo info(args.end()); |
199 v8::Handle<v8::Value> result; | 192 v8::Handle<v8::Value> result; |
200 { | 193 { |
201 // Leaving JavaScript. | 194 // Leaving JavaScript. |
202 VMState state(isolate, EXTERNAL); | 195 VMState state(isolate, EXTERNAL); |
203 result = call_fun(v8::Utils::ToLocal(key), info); | 196 result = call_fun(v8::Utils::ToLocal(key), info); |
204 } | 197 } |
205 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 198 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
206 if (result.IsEmpty()) { | 199 if (result.IsEmpty()) { |
207 return isolate->heap()->undefined_value(); | 200 return isolate->heap()->undefined_value(); |
208 } | 201 } |
209 return *v8::Utils::OpenHandle(*result); | 202 return *v8::Utils::OpenHandle(*result); |
210 } | 203 } |
211 | 204 |
212 // __defineGetter__ callback | 205 // __defineGetter__ callback |
213 if (structure->IsFixedArray()) { | 206 if (structure->IsFixedArray()) { |
214 Object* getter = FixedArray::cast(structure)->get(kGetterIndex); | 207 Object* getter = FixedArray::cast(structure)->get(kGetterIndex); |
215 if (getter->IsJSFunction()) { | 208 if (getter->IsSpecFunction()) { |
216 return Object::GetPropertyWithDefinedGetter(receiver, | 209 // TODO(rossberg): nicer would be to cast to some JSCallable here... |
217 JSFunction::cast(getter)); | 210 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter)); |
218 } | 211 } |
219 // Getter is not a function. | 212 // Getter is not a function. |
220 return isolate->heap()->undefined_value(); | 213 return isolate->heap()->undefined_value(); |
221 } | 214 } |
222 | 215 |
223 UNREACHABLE(); | 216 UNREACHABLE(); |
224 return NULL; | 217 return NULL; |
225 } | 218 } |
226 | 219 |
227 | 220 |
228 MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw, | 221 MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw, |
229 String* name_raw, | 222 String* name_raw) { |
230 Object* handler_raw) { | 223 Isolate* isolate = GetIsolate(); |
231 Isolate* isolate = name_raw->GetIsolate(); | |
232 HandleScope scope(isolate); | 224 HandleScope scope(isolate); |
233 Handle<Object> receiver(receiver_raw); | 225 Handle<Object> receiver(receiver_raw); |
234 Handle<Object> name(name_raw); | 226 Handle<Object> name(name_raw); |
235 Handle<Object> handler(handler_raw); | |
236 | 227 |
237 // Extract trap function. | 228 Handle<Object> args[] = { receiver, name }; |
238 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("get"); | 229 Handle<Object> result = CallTrap( |
239 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name)); | 230 "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args); |
240 if (isolate->has_pending_exception()) return Failure::Exception(); | 231 if (isolate->has_pending_exception()) return Failure::Exception(); |
241 if (trap->IsUndefined()) { | |
242 // Get the derived `get' property. | |
243 trap = isolate->derived_get_trap(); | |
244 } | |
245 | |
246 // Call trap function. | |
247 Object** args[] = { receiver.location(), name.location() }; | |
248 bool has_exception; | |
249 Handle<Object> result = | |
250 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception); | |
251 if (has_exception) return Failure::Exception(); | |
252 | 232 |
253 return *result; | 233 return *result; |
254 } | 234 } |
255 | 235 |
256 | 236 |
| 237 MaybeObject* JSProxy::GetElementWithHandler(Object* receiver, |
| 238 uint32_t index) { |
| 239 String* name; |
| 240 MaybeObject* maybe = GetHeap()->Uint32ToString(index); |
| 241 if (!maybe->To<String>(&name)) return maybe; |
| 242 return GetPropertyWithHandler(receiver, name); |
| 243 } |
| 244 |
| 245 |
| 246 MaybeObject* JSProxy::SetElementWithHandler(uint32_t index, |
| 247 Object* value, |
| 248 StrictModeFlag strict_mode) { |
| 249 String* name; |
| 250 MaybeObject* maybe = GetHeap()->Uint32ToString(index); |
| 251 if (!maybe->To<String>(&name)) return maybe; |
| 252 return SetPropertyWithHandler(name, value, NONE, strict_mode); |
| 253 } |
| 254 |
| 255 |
| 256 bool JSProxy::HasElementWithHandler(uint32_t index) { |
| 257 String* name; |
| 258 MaybeObject* maybe = GetHeap()->Uint32ToString(index); |
| 259 if (!maybe->To<String>(&name)) return maybe; |
| 260 return HasPropertyWithHandler(name); |
| 261 } |
| 262 |
| 263 |
257 MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver, | 264 MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver, |
258 JSFunction* getter) { | 265 JSReceiver* getter) { |
259 HandleScope scope; | 266 HandleScope scope; |
260 Handle<JSFunction> fun(JSFunction::cast(getter)); | 267 Handle<JSReceiver> fun(getter); |
261 Handle<Object> self(receiver); | 268 Handle<Object> self(receiver); |
262 #ifdef ENABLE_DEBUGGER_SUPPORT | 269 #ifdef ENABLE_DEBUGGER_SUPPORT |
263 Debug* debug = fun->GetHeap()->isolate()->debug(); | 270 Debug* debug = fun->GetHeap()->isolate()->debug(); |
264 // Handle stepping into a getter if step into is active. | 271 // Handle stepping into a getter if step into is active. |
265 if (debug->StepInActive()) { | 272 // TODO(rossberg): should this apply to getters that are function proxies? |
266 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false); | 273 if (debug->StepInActive() && fun->IsJSFunction()) { |
| 274 debug->HandleStepIn( |
| 275 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false); |
267 } | 276 } |
268 #endif | 277 #endif |
| 278 |
269 bool has_pending_exception; | 279 bool has_pending_exception; |
270 Handle<Object> result = | 280 Handle<Object> result = |
271 Execution::Call(fun, self, 0, NULL, &has_pending_exception); | 281 Execution::Call(fun, self, 0, NULL, &has_pending_exception); |
272 // Check for pending exception and return the result. | 282 // Check for pending exception and return the result. |
273 if (has_pending_exception) return Failure::Exception(); | 283 if (has_pending_exception) return Failure::Exception(); |
274 return *result; | 284 return *result; |
275 } | 285 } |
276 | 286 |
277 | 287 |
278 // Only deal with CALLBACKS and INTERCEPTOR | 288 // Only deal with CALLBACKS and INTERCEPTOR |
279 MaybeObject* JSObject::GetPropertyWithFailedAccessCheck( | 289 MaybeObject* JSObject::GetPropertyWithFailedAccessCheck( |
280 Object* receiver, | 290 Object* receiver, |
281 LookupResult* result, | 291 LookupResult* result, |
282 String* name, | 292 String* name, |
283 PropertyAttributes* attributes) { | 293 PropertyAttributes* attributes) { |
284 if (result->IsProperty()) { | 294 if (result->IsProperty()) { |
285 switch (result->type()) { | 295 switch (result->type()) { |
286 case CALLBACKS: { | 296 case CALLBACKS: { |
287 // Only allow API accessors. | 297 // Only allow API accessors. |
288 Object* obj = result->GetCallbackObject(); | 298 Object* obj = result->GetCallbackObject(); |
289 if (obj->IsAccessorInfo()) { | 299 if (obj->IsAccessorInfo()) { |
290 AccessorInfo* info = AccessorInfo::cast(obj); | 300 AccessorInfo* info = AccessorInfo::cast(obj); |
291 if (info->all_can_read()) { | 301 if (info->all_can_read()) { |
292 *attributes = result->GetAttributes(); | 302 *attributes = result->GetAttributes(); |
293 return GetPropertyWithCallback(receiver, | 303 return result->holder()->GetPropertyWithCallback( |
294 result->GetCallbackObject(), | 304 receiver, result->GetCallbackObject(), name); |
295 name, | |
296 result->holder()); | |
297 } | 305 } |
298 } | 306 } |
299 break; | 307 break; |
300 } | 308 } |
301 case NORMAL: | 309 case NORMAL: |
302 case FIELD: | 310 case FIELD: |
303 case CONSTANT_FUNCTION: { | 311 case CONSTANT_FUNCTION: { |
304 // Search ALL_CAN_READ accessors in prototype chain. | 312 // Search ALL_CAN_READ accessors in prototype chain. |
305 LookupResult r; | 313 LookupResult r; |
306 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r); | 314 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r); |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 // from the DontDelete cell without checking if it contains | 487 // from the DontDelete cell without checking if it contains |
480 // the hole value. | 488 // the hole value. |
481 Object* new_map; | 489 Object* new_map; |
482 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); | 490 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); |
483 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 491 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
484 } | 492 } |
485 set_map(Map::cast(new_map)); | 493 set_map(Map::cast(new_map)); |
486 } | 494 } |
487 JSGlobalPropertyCell* cell = | 495 JSGlobalPropertyCell* cell = |
488 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry)); | 496 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry)); |
489 cell->set_value(cell->heap()->the_hole_value()); | 497 cell->set_value(cell->GetHeap()->the_hole_value()); |
490 dictionary->DetailsAtPut(entry, details.AsDeleted()); | 498 dictionary->DetailsAtPut(entry, details.AsDeleted()); |
491 } else { | 499 } else { |
492 Object* deleted = dictionary->DeleteProperty(entry, mode); | 500 Object* deleted = dictionary->DeleteProperty(entry, mode); |
493 if (deleted == GetHeap()->true_value()) { | 501 if (deleted == GetHeap()->true_value()) { |
494 FixedArray* new_properties = NULL; | 502 FixedArray* new_properties = NULL; |
495 MaybeObject* maybe_properties = dictionary->Shrink(name); | 503 MaybeObject* maybe_properties = dictionary->Shrink(name); |
496 if (!maybe_properties->To(&new_properties)) { | 504 if (!maybe_properties->To(&new_properties)) { |
497 return maybe_properties; | 505 return maybe_properties; |
498 } | 506 } |
499 set_properties(new_properties); | 507 set_properties(new_properties); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
559 if (current == last) break; | 567 if (current == last) break; |
560 } | 568 } |
561 } | 569 } |
562 | 570 |
563 if (!result->IsProperty()) { | 571 if (!result->IsProperty()) { |
564 *attributes = ABSENT; | 572 *attributes = ABSENT; |
565 return heap->undefined_value(); | 573 return heap->undefined_value(); |
566 } | 574 } |
567 *attributes = result->GetAttributes(); | 575 *attributes = result->GetAttributes(); |
568 Object* value; | 576 Object* value; |
569 JSObject* holder = result->holder(); | |
570 switch (result->type()) { | 577 switch (result->type()) { |
571 case NORMAL: | 578 case NORMAL: |
572 value = holder->GetNormalizedProperty(result); | 579 value = result->holder()->GetNormalizedProperty(result); |
573 ASSERT(!value->IsTheHole() || result->IsReadOnly()); | 580 ASSERT(!value->IsTheHole() || result->IsReadOnly()); |
574 return value->IsTheHole() ? heap->undefined_value() : value; | 581 return value->IsTheHole() ? heap->undefined_value() : value; |
575 case FIELD: | 582 case FIELD: |
576 value = holder->FastPropertyAt(result->GetFieldIndex()); | 583 value = result->holder()->FastPropertyAt(result->GetFieldIndex()); |
577 ASSERT(!value->IsTheHole() || result->IsReadOnly()); | 584 ASSERT(!value->IsTheHole() || result->IsReadOnly()); |
578 return value->IsTheHole() ? heap->undefined_value() : value; | 585 return value->IsTheHole() ? heap->undefined_value() : value; |
579 case CONSTANT_FUNCTION: | 586 case CONSTANT_FUNCTION: |
580 return result->GetConstantFunction(); | 587 return result->GetConstantFunction(); |
581 case CALLBACKS: | 588 case CALLBACKS: |
582 return GetPropertyWithCallback(receiver, | 589 return result->holder()->GetPropertyWithCallback( |
583 result->GetCallbackObject(), | 590 receiver, result->GetCallbackObject(), name); |
584 name, | 591 case HANDLER: |
585 holder); | 592 return result->proxy()->GetPropertyWithHandler(receiver, name); |
586 case HANDLER: { | |
587 JSProxy* proxy = JSProxy::cast(this); | |
588 return GetPropertyWithHandler(receiver, name, proxy->handler()); | |
589 } | |
590 case INTERCEPTOR: { | 593 case INTERCEPTOR: { |
591 JSObject* recvr = JSObject::cast(receiver); | 594 JSObject* recvr = JSObject::cast(receiver); |
592 return holder->GetPropertyWithInterceptor(recvr, name, attributes); | 595 return result->holder()->GetPropertyWithInterceptor( |
| 596 recvr, name, attributes); |
593 } | 597 } |
594 case MAP_TRANSITION: | 598 case MAP_TRANSITION: |
595 case ELEMENTS_TRANSITION: | 599 case ELEMENTS_TRANSITION: |
596 case CONSTANT_TRANSITION: | 600 case CONSTANT_TRANSITION: |
597 case NULL_DESCRIPTOR: | 601 case NULL_DESCRIPTOR: |
598 break; | 602 break; |
599 } | 603 } |
600 UNREACHABLE(); | 604 UNREACHABLE(); |
601 return NULL; | 605 return NULL; |
602 } | 606 } |
603 | 607 |
604 | 608 |
605 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { | 609 MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { |
606 Heap* heap = IsSmi() | 610 Heap* heap = IsSmi() |
607 ? Isolate::Current()->heap() | 611 ? Isolate::Current()->heap() |
608 : HeapObject::cast(this)->GetHeap(); | 612 : HeapObject::cast(this)->GetHeap(); |
609 Object* holder = this; | 613 Object* holder = this; |
610 | 614 |
611 // Iterate up the prototype chain until an element is found or the null | 615 // Iterate up the prototype chain until an element is found or the null |
612 // prototype is encountered. | 616 // prototype is encountered. |
613 for (holder = this; | 617 for (holder = this; |
614 holder != heap->null_value(); | 618 holder != heap->null_value(); |
615 holder = holder->GetPrototype()) { | 619 holder = holder->GetPrototype()) { |
616 if (holder->IsSmi()) { | 620 if (!holder->IsJSObject()) { |
617 Context* global_context = Isolate::Current()->context()->global_context(); | 621 Isolate* isolate = heap->isolate(); |
618 holder = global_context->number_function()->instance_prototype(); | 622 Context* global_context = isolate->context()->global_context(); |
619 } else { | 623 if (holder->IsNumber()) { |
620 HeapObject* heap_object = HeapObject::cast(holder); | 624 holder = global_context->number_function()->instance_prototype(); |
621 if (!heap_object->IsJSObject()) { | 625 } else if (holder->IsString()) { |
622 Isolate* isolate = heap->isolate(); | 626 holder = global_context->string_function()->instance_prototype(); |
623 Context* global_context = isolate->context()->global_context(); | 627 } else if (holder->IsBoolean()) { |
624 if (heap_object->IsString()) { | 628 holder = global_context->boolean_function()->instance_prototype(); |
625 holder = global_context->string_function()->instance_prototype(); | 629 } else if (holder->IsJSProxy()) { |
626 } else if (heap_object->IsHeapNumber()) { | 630 return JSProxy::cast(holder)->GetElementWithHandler(receiver, index); |
627 holder = global_context->number_function()->instance_prototype(); | 631 } else { |
628 } else if (heap_object->IsBoolean()) { | 632 // Undefined and null have no indexed properties. |
629 holder = global_context->boolean_function()->instance_prototype(); | 633 ASSERT(holder->IsUndefined() || holder->IsNull()); |
630 } else if (heap_object->IsJSProxy()) { | 634 return heap->undefined_value(); |
631 // TODO(rossberg): do something | |
632 return heap->undefined_value(); // For now... | |
633 } else { | |
634 // Undefined and null have no indexed properties. | |
635 ASSERT(heap_object->IsUndefined() || heap_object->IsNull()); | |
636 return heap->undefined_value(); | |
637 } | |
638 } | 635 } |
639 } | 636 } |
640 | 637 |
641 // Inline the case for JSObjects. Doing so significantly improves the | 638 // Inline the case for JSObjects. Doing so significantly improves the |
642 // performance of fetching elements where checking the prototype chain is | 639 // performance of fetching elements where checking the prototype chain is |
643 // necessary. | 640 // necessary. |
644 JSObject* js_object = JSObject::cast(holder); | 641 JSObject* js_object = JSObject::cast(holder); |
645 | 642 |
646 // Check access rights if needed. | 643 // Check access rights if needed. |
647 if (js_object->IsAccessCheckNeeded()) { | 644 if (js_object->IsAccessCheckNeeded()) { |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 self->Hash(); // Force regeneration of the hash value. | 867 self->Hash(); // Force regeneration of the hash value. |
871 // Now morph this external string into a external symbol. | 868 // Now morph this external string into a external symbol. |
872 this->set_map(is_ascii ? | 869 this->set_map(is_ascii ? |
873 heap->external_symbol_with_ascii_data_map() : | 870 heap->external_symbol_with_ascii_data_map() : |
874 heap->external_symbol_map()); | 871 heap->external_symbol_map()); |
875 } | 872 } |
876 | 873 |
877 // Fill the remainder of the string with dead wood. | 874 // Fill the remainder of the string with dead wood. |
878 int new_size = this->Size(); // Byte size of the external String object. | 875 int new_size = this->Size(); // Byte size of the external String object. |
879 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size); | 876 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size); |
| 877 if (Marking::IsBlack(Marking::MarkBitFrom(this))) { |
| 878 MemoryChunk::IncrementLiveBytes(this->address(), new_size - size); |
| 879 } |
880 return true; | 880 return true; |
881 } | 881 } |
882 | 882 |
883 | 883 |
884 bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) { | 884 bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) { |
885 #ifdef DEBUG | 885 #ifdef DEBUG |
886 if (FLAG_enable_slow_asserts) { | 886 if (FLAG_enable_slow_asserts) { |
887 // Assert that the resource and the string are equivalent. | 887 // Assert that the resource and the string are equivalent. |
888 ASSERT(static_cast<size_t>(this->length()) == resource->length()); | 888 ASSERT(static_cast<size_t>(this->length()) == resource->length()); |
889 ScopedVector<char> smart_chars(this->length()); | 889 ScopedVector<char> smart_chars(this->length()); |
(...skipping 26 matching lines...) Expand all Loading... |
916 // was a symbol to start with. | 916 // was a symbol to start with. |
917 if (is_symbol) { | 917 if (is_symbol) { |
918 self->Hash(); // Force regeneration of the hash value. | 918 self->Hash(); // Force regeneration of the hash value. |
919 // Now morph this external string into a external symbol. | 919 // Now morph this external string into a external symbol. |
920 this->set_map(heap->external_ascii_symbol_map()); | 920 this->set_map(heap->external_ascii_symbol_map()); |
921 } | 921 } |
922 | 922 |
923 // Fill the remainder of the string with dead wood. | 923 // Fill the remainder of the string with dead wood. |
924 int new_size = this->Size(); // Byte size of the external String object. | 924 int new_size = this->Size(); // Byte size of the external String object. |
925 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size); | 925 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size); |
| 926 if (Marking::IsBlack(Marking::MarkBitFrom(this))) { |
| 927 MemoryChunk::IncrementLiveBytes(this->address(), new_size - size); |
| 928 } |
| 929 |
926 return true; | 930 return true; |
927 } | 931 } |
928 | 932 |
929 | 933 |
930 void String::StringShortPrint(StringStream* accumulator) { | 934 void String::StringShortPrint(StringStream* accumulator) { |
931 int len = length(); | 935 int len = length(); |
932 if (len > kMaxShortPrintLength) { | 936 if (len > kMaxShortPrintLength) { |
933 accumulator->Add("<Very long string[%u]>", len); | 937 accumulator->Add("<Very long string[%u]>", len); |
934 return; | 938 return; |
935 } | 939 } |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
991 | 995 |
992 | 996 |
993 void JSObject::JSObjectShortPrint(StringStream* accumulator) { | 997 void JSObject::JSObjectShortPrint(StringStream* accumulator) { |
994 switch (map()->instance_type()) { | 998 switch (map()->instance_type()) { |
995 case JS_ARRAY_TYPE: { | 999 case JS_ARRAY_TYPE: { |
996 double length = JSArray::cast(this)->length()->Number(); | 1000 double length = JSArray::cast(this)->length()->Number(); |
997 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length)); | 1001 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length)); |
998 break; | 1002 break; |
999 } | 1003 } |
1000 case JS_WEAK_MAP_TYPE: { | 1004 case JS_WEAK_MAP_TYPE: { |
1001 int elements = JSWeakMap::cast(this)->table()->NumberOfElements(); | 1005 accumulator->Add("<JS WeakMap>"); |
1002 accumulator->Add("<JS WeakMap[%d]>", elements); | |
1003 break; | 1006 break; |
1004 } | 1007 } |
1005 case JS_REGEXP_TYPE: { | 1008 case JS_REGEXP_TYPE: { |
1006 accumulator->Add("<JS RegExp>"); | 1009 accumulator->Add("<JS RegExp>"); |
1007 break; | 1010 break; |
1008 } | 1011 } |
1009 case JS_FUNCTION_TYPE: { | 1012 case JS_FUNCTION_TYPE: { |
1010 Object* fun_name = JSFunction::cast(this)->shared()->name(); | 1013 Object* fun_name = JSFunction::cast(this)->shared()->name(); |
1011 bool printed = false; | 1014 bool printed = false; |
1012 if (fun_name->IsString()) { | 1015 if (fun_name->IsString()) { |
1013 String* str = String::cast(fun_name); | 1016 String* str = String::cast(fun_name); |
1014 if (str->length() > 0) { | 1017 if (str->length() > 0) { |
1015 accumulator->Add("<JS Function "); | 1018 accumulator->Add("<JS Function "); |
1016 accumulator->Put(str); | 1019 accumulator->Put(str); |
1017 accumulator->Put('>'); | 1020 accumulator->Put('>'); |
1018 printed = true; | 1021 printed = true; |
1019 } | 1022 } |
1020 } | 1023 } |
1021 if (!printed) { | 1024 if (!printed) { |
1022 accumulator->Add("<JS Function>"); | 1025 accumulator->Add("<JS Function>"); |
1023 } | 1026 } |
1024 break; | 1027 break; |
1025 } | 1028 } |
1026 // All other JSObjects are rather similar to each other (JSObject, | 1029 // All other JSObjects are rather similar to each other (JSObject, |
1027 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue). | 1030 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue). |
1028 default: { | 1031 default: { |
1029 Map* map_of_this = map(); | 1032 Map* map_of_this = map(); |
1030 Heap* heap = map_of_this->heap(); | 1033 Heap* heap = GetHeap(); |
1031 Object* constructor = map_of_this->constructor(); | 1034 Object* constructor = map_of_this->constructor(); |
1032 bool printed = false; | 1035 bool printed = false; |
1033 if (constructor->IsHeapObject() && | 1036 if (constructor->IsHeapObject() && |
1034 !heap->Contains(HeapObject::cast(constructor))) { | 1037 !heap->Contains(HeapObject::cast(constructor))) { |
1035 accumulator->Add("!!!INVALID CONSTRUCTOR!!!"); | 1038 accumulator->Add("!!!INVALID CONSTRUCTOR!!!"); |
1036 } else { | 1039 } else { |
1037 bool global_object = IsJSGlobalProxy(); | 1040 bool global_object = IsJSGlobalProxy(); |
1038 if (constructor->IsJSFunction()) { | 1041 if (constructor->IsJSFunction()) { |
1039 if (!heap->Contains(JSFunction::cast(constructor)->shared())) { | 1042 if (!heap->Contains(JSFunction::cast(constructor)->shared())) { |
1040 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!"); | 1043 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!"); |
1041 } else { | 1044 } else { |
1042 Object* constructor_name = | 1045 Object* constructor_name = |
1043 JSFunction::cast(constructor)->shared()->name(); | 1046 JSFunction::cast(constructor)->shared()->name(); |
1044 if (constructor_name->IsString()) { | 1047 if (constructor_name->IsString()) { |
1045 String* str = String::cast(constructor_name); | 1048 String* str = String::cast(constructor_name); |
1046 if (str->length() > 0) { | 1049 if (str->length() > 0) { |
1047 bool vowel = AnWord(str); | 1050 bool vowel = AnWord(str); |
1048 accumulator->Add("<%sa%s ", | 1051 accumulator->Add("<%sa%s ", |
1049 global_object ? "Global Object: " : "", | 1052 global_object ? "Global Object: " : "", |
1050 vowel ? "n" : ""); | 1053 vowel ? "n" : ""); |
1051 accumulator->Put(str); | 1054 accumulator->Put(str); |
1052 accumulator->Put('>'); | |
1053 printed = true; | 1055 printed = true; |
1054 } | 1056 } |
1055 } | 1057 } |
1056 } | 1058 } |
1057 } | 1059 } |
1058 if (!printed) { | 1060 if (!printed) { |
1059 accumulator->Add("<JS %sObject", global_object ? "Global " : ""); | 1061 accumulator->Add("<JS %sObject", global_object ? "Global " : ""); |
1060 } | 1062 } |
1061 } | 1063 } |
1062 if (IsJSValue()) { | 1064 if (IsJSValue()) { |
1063 accumulator->Add(" value = "); | 1065 accumulator->Add(" value = "); |
1064 JSValue::cast(this)->value()->ShortPrint(accumulator); | 1066 JSValue::cast(this)->value()->ShortPrint(accumulator); |
1065 } | 1067 } |
1066 accumulator->Put('>'); | 1068 accumulator->Put('>'); |
1067 break; | 1069 break; |
1068 } | 1070 } |
1069 } | 1071 } |
1070 } | 1072 } |
1071 | 1073 |
1072 | 1074 |
1073 void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { | 1075 void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { |
1074 // if (!HEAP->InNewSpace(this)) PrintF("*", this); | |
1075 Heap* heap = GetHeap(); | 1076 Heap* heap = GetHeap(); |
1076 if (!heap->Contains(this)) { | 1077 if (!heap->Contains(this)) { |
1077 accumulator->Add("!!!INVALID POINTER!!!"); | 1078 accumulator->Add("!!!INVALID POINTER!!!"); |
1078 return; | 1079 return; |
1079 } | 1080 } |
1080 if (!heap->Contains(map())) { | 1081 if (!heap->Contains(map())) { |
1081 accumulator->Add("!!!INVALID MAP!!!"); | 1082 accumulator->Add("!!!INVALID MAP!!!"); |
1082 return; | 1083 return; |
1083 } | 1084 } |
1084 | 1085 |
(...skipping 10 matching lines...) Expand all Loading... |
1095 switch (map()->instance_type()) { | 1096 switch (map()->instance_type()) { |
1096 case MAP_TYPE: | 1097 case MAP_TYPE: |
1097 accumulator->Add("<Map>"); | 1098 accumulator->Add("<Map>"); |
1098 break; | 1099 break; |
1099 case FIXED_ARRAY_TYPE: | 1100 case FIXED_ARRAY_TYPE: |
1100 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length()); | 1101 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length()); |
1101 break; | 1102 break; |
1102 case BYTE_ARRAY_TYPE: | 1103 case BYTE_ARRAY_TYPE: |
1103 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length()); | 1104 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length()); |
1104 break; | 1105 break; |
| 1106 case FREE_SPACE_TYPE: |
| 1107 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size()); |
| 1108 break; |
1105 case EXTERNAL_PIXEL_ARRAY_TYPE: | 1109 case EXTERNAL_PIXEL_ARRAY_TYPE: |
1106 accumulator->Add("<ExternalPixelArray[%u]>", | 1110 accumulator->Add("<ExternalPixelArray[%u]>", |
1107 ExternalPixelArray::cast(this)->length()); | 1111 ExternalPixelArray::cast(this)->length()); |
1108 break; | 1112 break; |
1109 case EXTERNAL_BYTE_ARRAY_TYPE: | 1113 case EXTERNAL_BYTE_ARRAY_TYPE: |
1110 accumulator->Add("<ExternalByteArray[%u]>", | 1114 accumulator->Add("<ExternalByteArray[%u]>", |
1111 ExternalByteArray::cast(this)->length()); | 1115 ExternalByteArray::cast(this)->length()); |
1112 break; | 1116 break; |
1113 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: | 1117 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: |
1114 accumulator->Add("<ExternalUnsignedByteArray[%u]>", | 1118 accumulator->Add("<ExternalUnsignedByteArray[%u]>", |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1270 break; | 1274 break; |
1271 case CODE_TYPE: | 1275 case CODE_TYPE: |
1272 reinterpret_cast<Code*>(this)->CodeIterateBody(v); | 1276 reinterpret_cast<Code*>(this)->CodeIterateBody(v); |
1273 break; | 1277 break; |
1274 case JS_GLOBAL_PROPERTY_CELL_TYPE: | 1278 case JS_GLOBAL_PROPERTY_CELL_TYPE: |
1275 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v); | 1279 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v); |
1276 break; | 1280 break; |
1277 case HEAP_NUMBER_TYPE: | 1281 case HEAP_NUMBER_TYPE: |
1278 case FILLER_TYPE: | 1282 case FILLER_TYPE: |
1279 case BYTE_ARRAY_TYPE: | 1283 case BYTE_ARRAY_TYPE: |
| 1284 case FREE_SPACE_TYPE: |
1280 case EXTERNAL_PIXEL_ARRAY_TYPE: | 1285 case EXTERNAL_PIXEL_ARRAY_TYPE: |
1281 case EXTERNAL_BYTE_ARRAY_TYPE: | 1286 case EXTERNAL_BYTE_ARRAY_TYPE: |
1282 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: | 1287 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: |
1283 case EXTERNAL_SHORT_ARRAY_TYPE: | 1288 case EXTERNAL_SHORT_ARRAY_TYPE: |
1284 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: | 1289 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: |
1285 case EXTERNAL_INT_ARRAY_TYPE: | 1290 case EXTERNAL_INT_ARRAY_TYPE: |
1286 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: | 1291 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: |
1287 case EXTERNAL_FLOAT_ARRAY_TYPE: | 1292 case EXTERNAL_FLOAT_ARRAY_TYPE: |
1288 case EXTERNAL_DOUBLE_ARRAY_TYPE: | 1293 case EXTERNAL_DOUBLE_ARRAY_TYPE: |
1289 break; | 1294 break; |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1526 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 1531 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
1527 } | 1532 } |
1528 | 1533 |
1529 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors); | 1534 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors); |
1530 Map::cast(new_map)->set_instance_descriptors(descriptors); | 1535 Map::cast(new_map)->set_instance_descriptors(descriptors); |
1531 Map* old_map = map(); | 1536 Map* old_map = map(); |
1532 set_map(Map::cast(new_map)); | 1537 set_map(Map::cast(new_map)); |
1533 | 1538 |
1534 // If the old map is the global object map (from new Object()), | 1539 // If the old map is the global object map (from new Object()), |
1535 // then transitions are not added to it, so we are done. | 1540 // then transitions are not added to it, so we are done. |
1536 Heap* heap = old_map->heap(); | 1541 Heap* heap = GetHeap(); |
1537 if (old_map == heap->isolate()->context()->global_context()-> | 1542 if (old_map == heap->isolate()->context()->global_context()-> |
1538 object_function()->map()) { | 1543 object_function()->map()) { |
1539 return function; | 1544 return function; |
1540 } | 1545 } |
1541 | 1546 |
1542 // Do not add CONSTANT_TRANSITIONS to global objects | 1547 // Do not add CONSTANT_TRANSITIONS to global objects |
1543 if (IsGlobalObject()) { | 1548 if (IsGlobalObject()) { |
1544 return function; | 1549 return function; |
1545 } | 1550 } |
1546 | 1551 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1602 return value; | 1607 return value; |
1603 } | 1608 } |
1604 | 1609 |
1605 | 1610 |
1606 MaybeObject* JSObject::AddProperty(String* name, | 1611 MaybeObject* JSObject::AddProperty(String* name, |
1607 Object* value, | 1612 Object* value, |
1608 PropertyAttributes attributes, | 1613 PropertyAttributes attributes, |
1609 StrictModeFlag strict_mode) { | 1614 StrictModeFlag strict_mode) { |
1610 ASSERT(!IsJSGlobalProxy()); | 1615 ASSERT(!IsJSGlobalProxy()); |
1611 Map* map_of_this = map(); | 1616 Map* map_of_this = map(); |
1612 Heap* heap = map_of_this->heap(); | 1617 Heap* heap = GetHeap(); |
1613 if (!map_of_this->is_extensible()) { | 1618 if (!map_of_this->is_extensible()) { |
1614 if (strict_mode == kNonStrictMode) { | 1619 if (strict_mode == kNonStrictMode) { |
1615 return heap->undefined_value(); | 1620 return heap->undefined_value(); |
1616 } else { | 1621 } else { |
1617 Handle<Object> args[1] = {Handle<String>(name)}; | 1622 Handle<Object> args[1] = {Handle<String>(name)}; |
1618 return heap->isolate()->Throw( | 1623 return heap->isolate()->Throw( |
1619 *FACTORY->NewTypeError("object_not_extensible", | 1624 *FACTORY->NewTypeError("object_not_extensible", |
1620 HandleVector(args, 1))); | 1625 HandleVector(args, 1))); |
1621 } | 1626 } |
1622 } | 1627 } |
(...skipping 28 matching lines...) Expand all Loading... |
1651 PropertyAttributes attributes, | 1656 PropertyAttributes attributes, |
1652 StrictModeFlag strict_mode) { | 1657 StrictModeFlag strict_mode) { |
1653 // Check local property, ignore interceptor. | 1658 // Check local property, ignore interceptor. |
1654 LookupResult result; | 1659 LookupResult result; |
1655 LocalLookupRealNamedProperty(name, &result); | 1660 LocalLookupRealNamedProperty(name, &result); |
1656 if (result.IsFound()) { | 1661 if (result.IsFound()) { |
1657 // An existing property, a map transition or a null descriptor was | 1662 // An existing property, a map transition or a null descriptor was |
1658 // found. Use set property to handle all these cases. | 1663 // found. Use set property to handle all these cases. |
1659 return SetProperty(&result, name, value, attributes, strict_mode); | 1664 return SetProperty(&result, name, value, attributes, strict_mode); |
1660 } | 1665 } |
| 1666 bool found = false; |
| 1667 MaybeObject* result_object; |
| 1668 result_object = SetPropertyWithCallbackSetterInPrototypes(name, |
| 1669 value, |
| 1670 attributes, |
| 1671 &found, |
| 1672 strict_mode); |
| 1673 if (found) return result_object; |
1661 // Add a new real property. | 1674 // Add a new real property. |
1662 return AddProperty(name, value, attributes, strict_mode); | 1675 return AddProperty(name, value, attributes, strict_mode); |
1663 } | 1676 } |
1664 | 1677 |
1665 | 1678 |
1666 MaybeObject* JSObject::ReplaceSlowProperty(String* name, | 1679 MaybeObject* JSObject::ReplaceSlowProperty(String* name, |
1667 Object* value, | 1680 Object* value, |
1668 PropertyAttributes attributes) { | 1681 PropertyAttributes attributes) { |
1669 StringDictionary* dictionary = property_dictionary(); | 1682 StringDictionary* dictionary = property_dictionary(); |
1670 int old_index = dictionary->FindEntry(name); | 1683 int old_index = dictionary->FindEntry(name); |
(...skipping 18 matching lines...) Expand all Loading... |
1689 { MaybeObject* maybe_result = | 1702 { MaybeObject* maybe_result = |
1690 ConvertDescriptorToField(name, new_value, attributes); | 1703 ConvertDescriptorToField(name, new_value, attributes); |
1691 if (!maybe_result->ToObject(&result)) return maybe_result; | 1704 if (!maybe_result->ToObject(&result)) return maybe_result; |
1692 } | 1705 } |
1693 // If we get to this point we have succeeded - do not return failure | 1706 // If we get to this point we have succeeded - do not return failure |
1694 // after this point. Later stuff is optional. | 1707 // after this point. Later stuff is optional. |
1695 if (!HasFastProperties()) { | 1708 if (!HasFastProperties()) { |
1696 return result; | 1709 return result; |
1697 } | 1710 } |
1698 // Do not add transitions to the map of "new Object()". | 1711 // Do not add transitions to the map of "new Object()". |
1699 if (map() == old_map->heap()->isolate()->context()->global_context()-> | 1712 if (map() == GetIsolate()->context()->global_context()-> |
1700 object_function()->map()) { | 1713 object_function()->map()) { |
1701 return result; | 1714 return result; |
1702 } | 1715 } |
1703 | 1716 |
1704 MapTransitionDescriptor transition(name, | 1717 MapTransitionDescriptor transition(name, |
1705 map(), | 1718 map(), |
1706 attributes); | 1719 attributes); |
1707 Object* new_descriptors; | 1720 Object* new_descriptors; |
1708 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()-> | 1721 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()-> |
1709 CopyInsert(&transition, KEEP_TRANSITIONS); | 1722 CopyInsert(&transition, KEEP_TRANSITIONS); |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1873 call_fun(v8::Utils::ToLocal(key), | 1886 call_fun(v8::Utils::ToLocal(key), |
1874 v8::Utils::ToLocal(value_handle), | 1887 v8::Utils::ToLocal(value_handle), |
1875 info); | 1888 info); |
1876 } | 1889 } |
1877 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 1890 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
1878 return *value_handle; | 1891 return *value_handle; |
1879 } | 1892 } |
1880 | 1893 |
1881 if (structure->IsFixedArray()) { | 1894 if (structure->IsFixedArray()) { |
1882 Object* setter = FixedArray::cast(structure)->get(kSetterIndex); | 1895 Object* setter = FixedArray::cast(structure)->get(kSetterIndex); |
1883 if (setter->IsJSFunction()) { | 1896 if (setter->IsSpecFunction()) { |
1884 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); | 1897 // TODO(rossberg): nicer would be to cast to some JSCallable here... |
| 1898 return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value); |
1885 } else { | 1899 } else { |
1886 if (strict_mode == kNonStrictMode) { | 1900 if (strict_mode == kNonStrictMode) { |
1887 return value; | 1901 return value; |
1888 } | 1902 } |
1889 Handle<String> key(name); | 1903 Handle<String> key(name); |
1890 Handle<Object> holder_handle(holder, isolate); | 1904 Handle<Object> holder_handle(holder, isolate); |
1891 Handle<Object> args[2] = { key, holder_handle }; | 1905 Handle<Object> args[2] = { key, holder_handle }; |
1892 return isolate->Throw( | 1906 return isolate->Throw( |
1893 *isolate->factory()->NewTypeError("no_setter_in_callback", | 1907 *isolate->factory()->NewTypeError("no_setter_in_callback", |
1894 HandleVector(args, 2))); | 1908 HandleVector(args, 2))); |
1895 } | 1909 } |
1896 } | 1910 } |
1897 | 1911 |
1898 UNREACHABLE(); | 1912 UNREACHABLE(); |
1899 return NULL; | 1913 return NULL; |
1900 } | 1914 } |
1901 | 1915 |
1902 | 1916 |
1903 MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter, | 1917 MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter, |
1904 Object* value) { | 1918 Object* value) { |
1905 Isolate* isolate = GetIsolate(); | 1919 Isolate* isolate = GetIsolate(); |
1906 Handle<Object> value_handle(value, isolate); | 1920 Handle<Object> value_handle(value, isolate); |
1907 Handle<JSFunction> fun(JSFunction::cast(setter), isolate); | 1921 Handle<JSReceiver> fun(setter, isolate); |
1908 Handle<JSObject> self(this, isolate); | 1922 Handle<JSReceiver> self(this, isolate); |
1909 #ifdef ENABLE_DEBUGGER_SUPPORT | 1923 #ifdef ENABLE_DEBUGGER_SUPPORT |
1910 Debug* debug = isolate->debug(); | 1924 Debug* debug = isolate->debug(); |
1911 // Handle stepping into a setter if step into is active. | 1925 // Handle stepping into a setter if step into is active. |
1912 if (debug->StepInActive()) { | 1926 // TODO(rossberg): should this apply to getters that are function proxies? |
1913 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false); | 1927 if (debug->StepInActive() && fun->IsJSFunction()) { |
| 1928 debug->HandleStepIn( |
| 1929 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false); |
1914 } | 1930 } |
1915 #endif | 1931 #endif |
1916 bool has_pending_exception; | 1932 bool has_pending_exception; |
1917 Object** argv[] = { value_handle.location() }; | 1933 Object** argv[] = { value_handle.location() }; |
1918 Execution::Call(fun, self, 1, argv, &has_pending_exception); | 1934 Execution::Call(fun, self, 1, argv, &has_pending_exception); |
1919 // Check for pending exception and return the result. | 1935 // Check for pending exception and return the result. |
1920 if (has_pending_exception) return Failure::Exception(); | 1936 if (has_pending_exception) return Failure::Exception(); |
1921 return *value_handle; | 1937 return *value_handle; |
1922 } | 1938 } |
1923 | 1939 |
1924 | 1940 |
1925 void JSObject::LookupCallbackSetterInPrototypes(String* name, | 1941 void JSObject::LookupCallbackSetterInPrototypes(String* name, |
1926 LookupResult* result) { | 1942 LookupResult* result) { |
1927 Heap* heap = GetHeap(); | 1943 Heap* heap = GetHeap(); |
1928 for (Object* pt = GetPrototype(); | 1944 for (Object* pt = GetPrototype(); |
1929 pt != heap->null_value(); | 1945 pt != heap->null_value(); |
1930 pt = pt->GetPrototype()) { | 1946 pt = pt->GetPrototype()) { |
| 1947 if (pt->IsJSProxy()) { |
| 1948 return result->HandlerResult(JSProxy::cast(pt)); |
| 1949 } |
1931 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result); | 1950 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result); |
1932 if (result->IsProperty()) { | 1951 if (result->IsProperty()) { |
1933 if (result->type() == CALLBACKS && !result->IsReadOnly()) return; | 1952 if (result->type() == CALLBACKS && !result->IsReadOnly()) return; |
1934 // Found non-callback or read-only callback, stop looking. | 1953 // Found non-callback or read-only callback, stop looking. |
1935 break; | 1954 break; |
1936 } | 1955 } |
1937 } | 1956 } |
1938 result->NotFound(); | 1957 result->NotFound(); |
1939 } | 1958 } |
1940 | 1959 |
1941 | 1960 |
1942 MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes( | 1961 MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes( |
1943 uint32_t index, | 1962 uint32_t index, |
1944 Object* value, | 1963 Object* value, |
1945 bool* found, | 1964 bool* found, |
1946 StrictModeFlag strict_mode) { | 1965 StrictModeFlag strict_mode) { |
1947 Heap* heap = GetHeap(); | 1966 Heap* heap = GetHeap(); |
1948 for (Object* pt = GetPrototype(); | 1967 for (Object* pt = GetPrototype(); |
1949 pt != heap->null_value(); | 1968 pt != heap->null_value(); |
1950 pt = pt->GetPrototype()) { | 1969 pt = pt->GetPrototype()) { |
| 1970 if (pt->IsJSProxy()) { |
| 1971 String* name; |
| 1972 MaybeObject* maybe = GetHeap()->Uint32ToString(index); |
| 1973 if (!maybe->To<String>(&name)) { |
| 1974 *found = true; // Force abort |
| 1975 return maybe; |
| 1976 } |
| 1977 return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter( |
| 1978 name, value, NONE, strict_mode, found); |
| 1979 } |
1951 if (!JSObject::cast(pt)->HasDictionaryElements()) { | 1980 if (!JSObject::cast(pt)->HasDictionaryElements()) { |
1952 continue; | 1981 continue; |
1953 } | 1982 } |
1954 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); | 1983 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); |
1955 int entry = dictionary->FindEntry(index); | 1984 int entry = dictionary->FindEntry(index); |
1956 if (entry != NumberDictionary::kNotFound) { | 1985 if (entry != NumberDictionary::kNotFound) { |
1957 PropertyDetails details = dictionary->DetailsAt(entry); | 1986 PropertyDetails details = dictionary->DetailsAt(entry); |
1958 if (details.type() == CALLBACKS) { | 1987 if (details.type() == CALLBACKS) { |
1959 *found = true; | 1988 *found = true; |
1960 return SetElementWithCallback(dictionary->ValueAt(entry), | 1989 return SetElementWithCallback(dictionary->ValueAt(entry), |
1961 index, | 1990 index, |
1962 value, | 1991 value, |
1963 JSObject::cast(pt), | 1992 JSObject::cast(pt), |
1964 strict_mode); | 1993 strict_mode); |
1965 } | 1994 } |
1966 } | 1995 } |
1967 } | 1996 } |
1968 *found = false; | 1997 *found = false; |
1969 return heap->the_hole_value(); | 1998 return heap->the_hole_value(); |
1970 } | 1999 } |
1971 | 2000 |
| 2001 MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes( |
| 2002 String* name, |
| 2003 Object* value, |
| 2004 PropertyAttributes attributes, |
| 2005 bool* found, |
| 2006 StrictModeFlag strict_mode) { |
| 2007 LookupResult result; |
| 2008 LookupCallbackSetterInPrototypes(name, &result); |
| 2009 Heap* heap = GetHeap(); |
| 2010 if (result.IsFound()) { |
| 2011 *found = true; |
| 2012 if (result.type() == CALLBACKS) { |
| 2013 return SetPropertyWithCallback(result.GetCallbackObject(), |
| 2014 name, |
| 2015 value, |
| 2016 result.holder(), |
| 2017 strict_mode); |
| 2018 } else if (result.type() == HANDLER) { |
| 2019 // We could not find a local property so let's check whether there is an |
| 2020 // accessor that wants to handle the property. |
| 2021 LookupResult accessor_result; |
| 2022 LookupCallbackSetterInPrototypes(name, &accessor_result); |
| 2023 if (accessor_result.IsFound()) { |
| 2024 if (accessor_result.type() == CALLBACKS) { |
| 2025 return SetPropertyWithCallback(accessor_result.GetCallbackObject(), |
| 2026 name, |
| 2027 value, |
| 2028 accessor_result.holder(), |
| 2029 strict_mode); |
| 2030 } else if (accessor_result.type() == HANDLER) { |
| 2031 // There is a proxy in the prototype chain. Invoke its |
| 2032 // getOwnPropertyDescriptor trap. |
| 2033 bool found = false; |
| 2034 // SetPropertyWithHandlerIfDefiningSetter can cause GC, |
| 2035 // make sure to use the handlified references after calling |
| 2036 // the function. |
| 2037 Handle<JSObject> self(this); |
| 2038 Handle<String> hname(name); |
| 2039 Handle<Object> hvalue(value); |
| 2040 MaybeObject* result = |
| 2041 accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter( |
| 2042 name, value, attributes, strict_mode, &found); |
| 2043 if (found) return result; |
| 2044 // The proxy does not define the property as an accessor. |
| 2045 // Consequently, it has no effect on setting the receiver. |
| 2046 return self->AddProperty(*hname, *hvalue, attributes, strict_mode); |
| 2047 } |
| 2048 } |
| 2049 } |
| 2050 } |
| 2051 *found = false; |
| 2052 return heap->the_hole_value(); |
| 2053 } |
| 2054 |
1972 | 2055 |
1973 void JSObject::LookupInDescriptor(String* name, LookupResult* result) { | 2056 void JSObject::LookupInDescriptor(String* name, LookupResult* result) { |
1974 DescriptorArray* descriptors = map()->instance_descriptors(); | 2057 DescriptorArray* descriptors = map()->instance_descriptors(); |
1975 int number = descriptors->SearchWithCache(name); | 2058 int number = descriptors->SearchWithCache(name); |
1976 if (number != DescriptorArray::kNotFound) { | 2059 if (number != DescriptorArray::kNotFound) { |
1977 result->DescriptorResult(this, descriptors->GetDetails(number), number); | 2060 result->DescriptorResult(this, descriptors->GetDetails(number), number); |
1978 } else { | 2061 } else { |
1979 result->NotFound(); | 2062 result->NotFound(); |
1980 } | 2063 } |
1981 } | 2064 } |
1982 | 2065 |
1983 | 2066 |
1984 void Map::LookupInDescriptors(JSObject* holder, | 2067 void Map::LookupInDescriptors(JSObject* holder, |
1985 String* name, | 2068 String* name, |
1986 LookupResult* result) { | 2069 LookupResult* result) { |
1987 DescriptorArray* descriptors = instance_descriptors(); | 2070 DescriptorArray* descriptors = instance_descriptors(); |
1988 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache(); | 2071 DescriptorLookupCache* cache = |
| 2072 GetHeap()->isolate()->descriptor_lookup_cache(); |
1989 int number = cache->Lookup(descriptors, name); | 2073 int number = cache->Lookup(descriptors, name); |
1990 if (number == DescriptorLookupCache::kAbsent) { | 2074 if (number == DescriptorLookupCache::kAbsent) { |
1991 number = descriptors->Search(name); | 2075 number = descriptors->Search(name); |
1992 cache->Update(descriptors, name, number); | 2076 cache->Update(descriptors, name, number); |
1993 } | 2077 } |
1994 if (number != DescriptorArray::kNotFound) { | 2078 if (number != DescriptorArray::kNotFound) { |
1995 result->DescriptorResult(holder, descriptors->GetDetails(number), number); | 2079 result->DescriptorResult(holder, descriptors->GetDetails(number), number); |
1996 } else { | 2080 } else { |
1997 result->NotFound(); | 2081 result->NotFound(); |
1998 } | 2082 } |
1999 } | 2083 } |
2000 | 2084 |
2001 | 2085 |
2002 MaybeObject* Map::GetElementsTransitionMap(ElementsKind elements_kind, | 2086 static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents, |
2003 bool safe_to_add_transition) { | 2087 ElementsKind elements_kind) { |
2004 Heap* current_heap = heap(); | 2088 if (descriptor_contents->IsMap()) { |
2005 DescriptorArray* descriptors = instance_descriptors(); | 2089 Map* map = Map::cast(descriptor_contents); |
| 2090 if (map->elements_kind() == elements_kind) { |
| 2091 return map; |
| 2092 } |
| 2093 return NULL; |
| 2094 } |
| 2095 |
| 2096 FixedArray* map_array = FixedArray::cast(descriptor_contents); |
| 2097 for (int i = 0; i < map_array->length(); ++i) { |
| 2098 Object* current = map_array->get(i); |
| 2099 // Skip undefined slots, they are sentinels for reclaimed maps. |
| 2100 if (!current->IsUndefined()) { |
| 2101 Map* current_map = Map::cast(map_array->get(i)); |
| 2102 if (current_map->elements_kind() == elements_kind) { |
| 2103 return current_map; |
| 2104 } |
| 2105 } |
| 2106 } |
| 2107 |
| 2108 return NULL; |
| 2109 } |
| 2110 |
| 2111 |
| 2112 static MaybeObject* AddElementsTransitionMapToDescriptor( |
| 2113 Object* descriptor_contents, |
| 2114 Map* new_map) { |
| 2115 // Nothing was in the descriptor for an ELEMENTS_TRANSITION, |
| 2116 // simply add the map. |
| 2117 if (descriptor_contents == NULL) { |
| 2118 return new_map; |
| 2119 } |
| 2120 |
| 2121 // There was already a map in the descriptor, create a 2-element FixedArray |
| 2122 // to contain the existing map plus the new one. |
| 2123 FixedArray* new_array; |
| 2124 Heap* heap = new_map->GetHeap(); |
| 2125 if (descriptor_contents->IsMap()) { |
| 2126 // Must tenure, DescriptorArray expects no new-space objects. |
| 2127 MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED); |
| 2128 if (!maybe_new_array->To<FixedArray>(&new_array)) { |
| 2129 return maybe_new_array; |
| 2130 } |
| 2131 new_array->set(0, descriptor_contents); |
| 2132 new_array->set(1, new_map); |
| 2133 return new_array; |
| 2134 } |
| 2135 |
| 2136 // The descriptor already contained a list of maps for different ElementKinds |
| 2137 // of ELEMENTS_TRANSITION, first check the existing array for an undefined |
| 2138 // slot, and if that's not available, create a FixedArray to hold the existing |
| 2139 // maps plus the new one and fill it in. |
| 2140 FixedArray* array = FixedArray::cast(descriptor_contents); |
| 2141 for (int i = 0; i < array->length(); ++i) { |
| 2142 if (array->get(i)->IsUndefined()) { |
| 2143 array->set(i, new_map); |
| 2144 return array; |
| 2145 } |
| 2146 } |
| 2147 |
| 2148 // Must tenure, DescriptorArray expects no new-space objects. |
| 2149 MaybeObject* maybe_new_array = |
| 2150 heap->AllocateFixedArray(array->length() + 1, TENURED); |
| 2151 if (!maybe_new_array->To<FixedArray>(&new_array)) { |
| 2152 return maybe_new_array; |
| 2153 } |
| 2154 int i = 0; |
| 2155 while (i < array->length()) { |
| 2156 new_array->set(i, array->get(i)); |
| 2157 ++i; |
| 2158 } |
| 2159 new_array->set(i, new_map); |
| 2160 return new_array; |
| 2161 } |
| 2162 |
| 2163 |
| 2164 MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind elements_kind) { |
| 2165 Heap* current_heap = GetHeap(); |
| 2166 Map* current_map = map(); |
| 2167 DescriptorArray* descriptors = current_map->instance_descriptors(); |
2006 String* elements_transition_sentinel_name = current_heap->empty_symbol(); | 2168 String* elements_transition_sentinel_name = current_heap->empty_symbol(); |
2007 | 2169 |
| 2170 if (current_map->elements_kind() == elements_kind) return current_map; |
| 2171 |
| 2172 // Only objects with FastProperties can have DescriptorArrays and can track |
| 2173 // element-related maps. Also don't add descriptors to maps that are shared. |
| 2174 bool safe_to_add_transition = HasFastProperties() && |
| 2175 !current_map->IsUndefined() && |
| 2176 !current_map->is_shared(); |
| 2177 |
| 2178 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps cause by objects |
| 2179 // with elements that switch back and forth between dictionary and fast |
| 2180 // element mode. |
| 2181 if ((current_map->elements_kind() == DICTIONARY_ELEMENTS && |
| 2182 elements_kind == FAST_ELEMENTS)) { |
| 2183 safe_to_add_transition = false; |
| 2184 } |
| 2185 |
| 2186 Object* descriptor_contents = NULL; |
2008 if (safe_to_add_transition) { | 2187 if (safe_to_add_transition) { |
2009 // It's only safe to manipulate the descriptor array if it would be | 2188 // It's only safe to manipulate the descriptor array if it would be |
2010 // safe to add a transition. | 2189 // safe to add a transition. |
2011 | 2190 |
2012 ASSERT(!is_shared()); // no transitions can be added to shared maps. | |
2013 // Check if the elements transition already exists. | 2191 // Check if the elements transition already exists. |
2014 DescriptorLookupCache* cache = | 2192 DescriptorLookupCache* cache = |
2015 current_heap->isolate()->descriptor_lookup_cache(); | 2193 current_heap->isolate()->descriptor_lookup_cache(); |
2016 int index = cache->Lookup(descriptors, elements_transition_sentinel_name); | 2194 int index = cache->Lookup(descriptors, elements_transition_sentinel_name); |
2017 if (index == DescriptorLookupCache::kAbsent) { | 2195 if (index == DescriptorLookupCache::kAbsent) { |
2018 index = descriptors->Search(elements_transition_sentinel_name); | 2196 index = descriptors->Search(elements_transition_sentinel_name); |
2019 cache->Update(descriptors, | 2197 cache->Update(descriptors, |
2020 elements_transition_sentinel_name, | 2198 elements_transition_sentinel_name, |
2021 index); | 2199 index); |
2022 } | 2200 } |
2023 | 2201 |
2024 // If the transition already exists, check the type. If there is a match, | 2202 // If the transition already exists, check the type. If there is a match, |
2025 // return it. | 2203 // return it. |
2026 if (index != DescriptorArray::kNotFound) { | 2204 if (index != DescriptorArray::kNotFound) { |
2027 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index))); | 2205 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index))); |
2028 if (details.type() == ELEMENTS_TRANSITION && | 2206 if (details.type() == ELEMENTS_TRANSITION) { |
2029 details.elements_kind() == elements_kind) { | 2207 descriptor_contents = descriptors->GetValue(index); |
2030 return descriptors->GetValue(index); | 2208 Map* maybe_transition_map = |
| 2209 GetElementsTransitionMapFromDescriptor(descriptor_contents, |
| 2210 elements_kind); |
| 2211 if (maybe_transition_map != NULL) { |
| 2212 ASSERT(maybe_transition_map->IsMap()); |
| 2213 return maybe_transition_map; |
| 2214 } |
2031 } else { | 2215 } else { |
2032 safe_to_add_transition = false; | 2216 safe_to_add_transition = false; |
2033 } | 2217 } |
2034 } | 2218 } |
2035 } | 2219 } |
2036 | 2220 |
2037 // No transition to an existing map for the given ElementsKind. Make a new | 2221 // No transition to an existing map for the given ElementsKind. Make a new |
2038 // one. | 2222 // one. |
2039 Object* obj; | 2223 Object* obj; |
2040 { MaybeObject* maybe_map = CopyDropTransitions(); | 2224 { MaybeObject* maybe_map = current_map->CopyDropTransitions(); |
2041 if (!maybe_map->ToObject(&obj)) return maybe_map; | 2225 if (!maybe_map->ToObject(&obj)) return maybe_map; |
2042 } | 2226 } |
2043 Map* new_map = Map::cast(obj); | 2227 Map* new_map = Map::cast(obj); |
2044 | 2228 |
2045 new_map->set_elements_kind(elements_kind); | 2229 new_map->set_elements_kind(elements_kind); |
2046 GetIsolate()->counters()->map_to_external_array_elements()->Increment(); | |
2047 | 2230 |
2048 // Only remember the map transition if the object's map is NOT equal to the | 2231 // Only remember the map transition if the object's map is NOT equal to the |
2049 // global object_function's map and there is not an already existing | 2232 // global object_function's map and there is not an already existing |
2050 // non-matching element transition. | 2233 // non-matching element transition. |
2051 bool allow_map_transition = | 2234 bool allow_map_transition = safe_to_add_transition && |
2052 safe_to_add_transition && | |
2053 (GetIsolate()->context()->global_context()->object_function()->map() != | 2235 (GetIsolate()->context()->global_context()->object_function()->map() != |
2054 map()); | 2236 map()); |
2055 if (allow_map_transition) { | 2237 if (allow_map_transition) { |
2056 // Allocate new instance descriptors for the old map with map transition. | 2238 MaybeObject* maybe_new_contents = |
| 2239 AddElementsTransitionMapToDescriptor(descriptor_contents, new_map); |
| 2240 Object* new_contents; |
| 2241 if (!maybe_new_contents->ToObject(&new_contents)) { |
| 2242 return maybe_new_contents; |
| 2243 } |
| 2244 |
2057 ElementsTransitionDescriptor desc(elements_transition_sentinel_name, | 2245 ElementsTransitionDescriptor desc(elements_transition_sentinel_name, |
2058 Map::cast(new_map), | 2246 new_contents); |
2059 elements_kind); | |
2060 Object* new_descriptors; | 2247 Object* new_descriptors; |
2061 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert( | 2248 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert( |
2062 &desc, | 2249 &desc, |
2063 KEEP_TRANSITIONS); | 2250 KEEP_TRANSITIONS); |
2064 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { | 2251 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { |
2065 return maybe_new_descriptors; | 2252 return maybe_new_descriptors; |
2066 } | 2253 } |
2067 descriptors = DescriptorArray::cast(new_descriptors); | 2254 descriptors = DescriptorArray::cast(new_descriptors); |
2068 set_instance_descriptors(descriptors); | 2255 current_map->set_instance_descriptors(descriptors); |
2069 } | 2256 } |
2070 | 2257 |
2071 return new_map; | 2258 return new_map; |
2072 } | 2259 } |
2073 | 2260 |
2074 | 2261 |
2075 void JSObject::LocalLookupRealNamedProperty(String* name, | 2262 void JSObject::LocalLookupRealNamedProperty(String* name, |
2076 LookupResult* result) { | 2263 LookupResult* result) { |
2077 if (IsJSGlobalProxy()) { | 2264 if (IsJSGlobalProxy()) { |
2078 Object* proto = GetPrototype(); | 2265 Object* proto = GetPrototype(); |
2079 if (proto->IsNull()) return result->NotFound(); | 2266 if (proto->IsNull()) return result->NotFound(); |
2080 ASSERT(proto->IsJSGlobalObject()); | 2267 ASSERT(proto->IsJSGlobalObject()); |
| 2268 // A GlobalProxy's prototype should always be a proper JSObject. |
2081 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result); | 2269 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result); |
2082 } | 2270 } |
2083 | 2271 |
2084 if (HasFastProperties()) { | 2272 if (HasFastProperties()) { |
2085 LookupInDescriptor(name, result); | 2273 LookupInDescriptor(name, result); |
2086 if (result->IsFound()) { | 2274 if (result->IsFound()) { |
2087 // A property, a map transition or a null descriptor was found. | 2275 // A property, a map transition or a null descriptor was found. |
2088 // We return all of these result types because | 2276 // We return all of these result types because |
2089 // LocalLookupRealNamedProperty is used when setting properties | 2277 // LocalLookupRealNamedProperty is used when setting properties |
2090 // where map transitions and null descriptors are handled. | 2278 // where map transitions and null descriptors are handled. |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2197 return *value_handle; | 2385 return *value_handle; |
2198 } | 2386 } |
2199 | 2387 |
2200 | 2388 |
2201 MaybeObject* JSReceiver::SetProperty(LookupResult* result, | 2389 MaybeObject* JSReceiver::SetProperty(LookupResult* result, |
2202 String* key, | 2390 String* key, |
2203 Object* value, | 2391 Object* value, |
2204 PropertyAttributes attributes, | 2392 PropertyAttributes attributes, |
2205 StrictModeFlag strict_mode) { | 2393 StrictModeFlag strict_mode) { |
2206 if (result->IsFound() && result->type() == HANDLER) { | 2394 if (result->IsFound() && result->type() == HANDLER) { |
2207 return JSProxy::cast(this)->SetPropertyWithHandler( | 2395 return result->proxy()->SetPropertyWithHandler( |
2208 key, value, attributes, strict_mode); | 2396 key, value, attributes, strict_mode); |
2209 } else { | 2397 } else { |
2210 return JSObject::cast(this)->SetPropertyForResult( | 2398 return JSObject::cast(this)->SetPropertyForResult( |
2211 result, key, value, attributes, strict_mode); | 2399 result, key, value, attributes, strict_mode); |
2212 } | 2400 } |
2213 } | 2401 } |
2214 | 2402 |
2215 | 2403 |
2216 bool JSProxy::HasPropertyWithHandler(String* name_raw) { | 2404 bool JSProxy::HasPropertyWithHandler(String* name_raw) { |
2217 Isolate* isolate = GetIsolate(); | 2405 Isolate* isolate = GetIsolate(); |
2218 HandleScope scope(isolate); | 2406 HandleScope scope(isolate); |
2219 Handle<Object> receiver(this); | 2407 Handle<Object> receiver(this); |
2220 Handle<Object> name(name_raw); | 2408 Handle<Object> name(name_raw); |
2221 Handle<Object> handler(this->handler()); | |
2222 | 2409 |
2223 // Extract trap function. | 2410 Handle<Object> args[] = { name }; |
2224 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has"); | 2411 Handle<Object> result = CallTrap( |
2225 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name)); | 2412 "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args); |
2226 if (isolate->has_pending_exception()) return Failure::Exception(); | 2413 if (isolate->has_pending_exception()) return Failure::Exception(); |
2227 if (trap->IsUndefined()) { | |
2228 trap = isolate->derived_has_trap(); | |
2229 } | |
2230 | |
2231 // Call trap function. | |
2232 Object** args[] = { name.location() }; | |
2233 bool has_exception; | |
2234 Handle<Object> result = | |
2235 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception); | |
2236 if (has_exception) return Failure::Exception(); | |
2237 | 2414 |
2238 return result->ToBoolean()->IsTrue(); | 2415 return result->ToBoolean()->IsTrue(); |
2239 } | 2416 } |
2240 | 2417 |
2241 | 2418 |
2242 MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler( | 2419 MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler( |
2243 String* name_raw, | 2420 String* name_raw, |
2244 Object* value_raw, | 2421 Object* value_raw, |
2245 PropertyAttributes attributes, | 2422 PropertyAttributes attributes, |
2246 StrictModeFlag strict_mode) { | 2423 StrictModeFlag strict_mode) { |
2247 Isolate* isolate = GetIsolate(); | 2424 Isolate* isolate = GetIsolate(); |
2248 HandleScope scope(isolate); | 2425 HandleScope scope(isolate); |
2249 Handle<Object> receiver(this); | 2426 Handle<Object> receiver(this); |
2250 Handle<Object> name(name_raw); | 2427 Handle<Object> name(name_raw); |
2251 Handle<Object> value(value_raw); | 2428 Handle<Object> value(value_raw); |
2252 Handle<Object> handler(this->handler()); | |
2253 | 2429 |
2254 // Extract trap function. | 2430 Handle<Object> args[] = { receiver, name, value }; |
2255 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set"); | 2431 CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args); |
2256 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name)); | |
2257 if (isolate->has_pending_exception()) return Failure::Exception(); | 2432 if (isolate->has_pending_exception()) return Failure::Exception(); |
2258 if (trap->IsUndefined()) { | |
2259 trap = isolate->derived_set_trap(); | |
2260 } | |
2261 | |
2262 // Call trap function. | |
2263 Object** args[] = { | |
2264 receiver.location(), name.location(), value.location() | |
2265 }; | |
2266 bool has_exception; | |
2267 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception); | |
2268 if (has_exception) return Failure::Exception(); | |
2269 | 2433 |
2270 return *value; | 2434 return *value; |
2271 } | 2435 } |
2272 | 2436 |
| 2437 |
| 2438 MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter( |
| 2439 String* name_raw, |
| 2440 Object* value_raw, |
| 2441 PropertyAttributes attributes, |
| 2442 StrictModeFlag strict_mode, |
| 2443 bool* found) { |
| 2444 *found = true; // except where defined otherwise... |
| 2445 Isolate* isolate = GetHeap()->isolate(); |
| 2446 Handle<JSProxy> proxy(this); |
| 2447 Handle<String> name(name_raw); |
| 2448 Handle<Object> value(value_raw); |
| 2449 Handle<Object> args[] = { name }; |
| 2450 Handle<Object> result = proxy->CallTrap( |
| 2451 "getOwnPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args); |
| 2452 if (isolate->has_pending_exception()) return Failure::Exception(); |
| 2453 |
| 2454 if (!result->IsUndefined()) { |
| 2455 // The proxy handler cares about this property. |
| 2456 // Check whether it is virtualized as an accessor. |
| 2457 // Emulate [[GetProperty]] semantics for proxies. |
| 2458 bool has_pending_exception; |
| 2459 Object** argv[] = { result.location() }; |
| 2460 Handle<Object> desc = |
| 2461 Execution::Call(isolate->to_complete_property_descriptor(), result, |
| 2462 ARRAY_SIZE(argv), argv, &has_pending_exception); |
| 2463 if (has_pending_exception) return Failure::Exception(); |
| 2464 |
| 2465 Handle<String> conf_name = |
| 2466 isolate->factory()->LookupAsciiSymbol("configurable_"); |
| 2467 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name)); |
| 2468 ASSERT(!isolate->has_pending_exception()); |
| 2469 if (configurable->IsFalse()) { |
| 2470 Handle<Object> args[] = { Handle<Object>(proxy->handler()), proxy, name }; |
| 2471 Handle<Object> error = isolate->factory()->NewTypeError( |
| 2472 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args))); |
| 2473 return isolate->Throw(*error); |
| 2474 } |
| 2475 ASSERT(configurable->IsTrue()); |
| 2476 |
| 2477 // Check for AccessorDescriptor. |
| 2478 Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_"); |
| 2479 Handle<Object> setter(v8::internal::GetProperty(desc, set_name)); |
| 2480 ASSERT(!isolate->has_pending_exception()); |
| 2481 if (!setter->IsUndefined()) { |
| 2482 // We have a setter -- invoke it. |
| 2483 // TODO(rossberg): nicer would be to cast to some JSCallable here... |
| 2484 return proxy->SetPropertyWithDefinedSetter( |
| 2485 JSReceiver::cast(*setter), *value); |
| 2486 } else { |
| 2487 Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_"); |
| 2488 Handle<Object> getter(v8::internal::GetProperty(desc, get_name)); |
| 2489 ASSERT(!isolate->has_pending_exception()); |
| 2490 if (!getter->IsUndefined()) { |
| 2491 // We have a getter but no setter -- the property may not be |
| 2492 // written. In strict mode, throw an error. |
| 2493 if (strict_mode == kNonStrictMode) return *value; |
| 2494 Handle<Object> args[] = { name, proxy }; |
| 2495 Handle<Object> error = isolate->factory()->NewTypeError( |
| 2496 "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args))); |
| 2497 return isolate->Throw(*error); |
| 2498 } |
| 2499 } |
| 2500 // Fall-through. |
| 2501 } |
| 2502 |
| 2503 // The proxy does not define the property as an accessor. |
| 2504 *found = false; |
| 2505 return *value; |
| 2506 } |
| 2507 |
2273 | 2508 |
2274 MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler( | 2509 MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler( |
2275 String* name_raw, DeleteMode mode) { | 2510 String* name_raw, DeleteMode mode) { |
2276 Isolate* isolate = GetIsolate(); | 2511 Isolate* isolate = GetIsolate(); |
2277 HandleScope scope(isolate); | 2512 HandleScope scope(isolate); |
2278 Handle<Object> receiver(this); | 2513 Handle<Object> receiver(this); |
2279 Handle<Object> name(name_raw); | 2514 Handle<Object> name(name_raw); |
2280 Handle<Object> handler(this->handler()); | |
2281 | 2515 |
2282 // Extract trap function. | 2516 Handle<Object> args[] = { name }; |
2283 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete"); | 2517 Handle<Object> result = CallTrap( |
2284 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name)); | 2518 "delete", Handle<Object>(), ARRAY_SIZE(args), args); |
2285 if (isolate->has_pending_exception()) return Failure::Exception(); | 2519 if (isolate->has_pending_exception()) return Failure::Exception(); |
2286 if (trap->IsUndefined()) { | |
2287 Handle<Object> args[] = { handler, trap_name }; | |
2288 Handle<Object> error = isolate->factory()->NewTypeError( | |
2289 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args))); | |
2290 isolate->Throw(*error); | |
2291 return Failure::Exception(); | |
2292 } | |
2293 | |
2294 // Call trap function. | |
2295 Object** args[] = { name.location() }; | |
2296 bool has_exception; | |
2297 Handle<Object> result = | |
2298 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception); | |
2299 if (has_exception) return Failure::Exception(); | |
2300 | 2520 |
2301 Object* bool_result = result->ToBoolean(); | 2521 Object* bool_result = result->ToBoolean(); |
2302 if (mode == STRICT_DELETION && | 2522 if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) { |
2303 bool_result == isolate->heap()->false_value()) { | 2523 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete"); |
2304 Handle<Object> args[] = { handler, trap_name }; | 2524 Handle<Object> args[] = { Handle<Object>(handler()), trap_name }; |
2305 Handle<Object> error = isolate->factory()->NewTypeError( | 2525 Handle<Object> error = isolate->factory()->NewTypeError( |
2306 "handler_failed", HandleVector(args, ARRAY_SIZE(args))); | 2526 "handler_failed", HandleVector(args, ARRAY_SIZE(args))); |
2307 isolate->Throw(*error); | 2527 isolate->Throw(*error); |
2308 return Failure::Exception(); | 2528 return Failure::Exception(); |
2309 } | 2529 } |
2310 return bool_result; | 2530 return bool_result; |
2311 } | 2531 } |
2312 | 2532 |
2313 | 2533 |
| 2534 MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler( |
| 2535 uint32_t index, |
| 2536 DeleteMode mode) { |
| 2537 Isolate* isolate = GetIsolate(); |
| 2538 HandleScope scope(isolate); |
| 2539 Handle<String> name = isolate->factory()->Uint32ToString(index); |
| 2540 return JSProxy::DeletePropertyWithHandler(*name, mode); |
| 2541 } |
| 2542 |
| 2543 |
2314 MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler( | 2544 MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler( |
2315 JSReceiver* receiver_raw, | 2545 JSReceiver* receiver_raw, |
2316 String* name_raw, | 2546 String* name_raw) { |
2317 bool* has_exception) { | |
2318 Isolate* isolate = GetIsolate(); | 2547 Isolate* isolate = GetIsolate(); |
2319 HandleScope scope(isolate); | 2548 HandleScope scope(isolate); |
| 2549 Handle<JSProxy> proxy(this); |
2320 Handle<JSReceiver> receiver(receiver_raw); | 2550 Handle<JSReceiver> receiver(receiver_raw); |
2321 Handle<Object> name(name_raw); | 2551 Handle<Object> name(name_raw); |
2322 Handle<Object> handler(this->handler()); | |
2323 | 2552 |
2324 // Extract trap function. | 2553 Handle<Object> args[] = { name }; |
2325 Handle<String> trap_name = | 2554 Handle<Object> result = CallTrap( |
2326 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor"); | 2555 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args); |
2327 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name)); | |
2328 if (isolate->has_pending_exception()) return NONE; | 2556 if (isolate->has_pending_exception()) return NONE; |
2329 if (trap->IsUndefined()) { | 2557 |
2330 Handle<Object> args[] = { handler, trap_name }; | 2558 if (result->IsUndefined()) return ABSENT; |
| 2559 |
| 2560 bool has_pending_exception; |
| 2561 Object** argv[] = { result.location() }; |
| 2562 Handle<Object> desc = |
| 2563 Execution::Call(isolate->to_complete_property_descriptor(), result, |
| 2564 ARRAY_SIZE(argv), argv, &has_pending_exception); |
| 2565 if (has_pending_exception) return NONE; |
| 2566 |
| 2567 // Convert result to PropertyAttributes. |
| 2568 Handle<String> enum_n = isolate->factory()->LookupAsciiSymbol("enumerable"); |
| 2569 Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_n)); |
| 2570 if (isolate->has_pending_exception()) return NONE; |
| 2571 Handle<String> conf_n = isolate->factory()->LookupAsciiSymbol("configurable"); |
| 2572 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_n)); |
| 2573 if (isolate->has_pending_exception()) return NONE; |
| 2574 Handle<String> writ_n = isolate->factory()->LookupAsciiSymbol("writable"); |
| 2575 Handle<Object> writable(v8::internal::GetProperty(desc, writ_n)); |
| 2576 if (isolate->has_pending_exception()) return NONE; |
| 2577 |
| 2578 if (configurable->IsFalse()) { |
| 2579 Handle<Object> args[] = { Handle<Object>(proxy->handler()), proxy, name }; |
2331 Handle<Object> error = isolate->factory()->NewTypeError( | 2580 Handle<Object> error = isolate->factory()->NewTypeError( |
2332 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args))); | 2581 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args))); |
2333 isolate->Throw(*error); | 2582 isolate->Throw(*error); |
2334 *has_exception = true; | |
2335 return NONE; | 2583 return NONE; |
2336 } | 2584 } |
2337 | 2585 |
2338 // Call trap function. | 2586 int attributes = NONE; |
2339 Object** args[] = { name.location() }; | 2587 if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM; |
2340 Handle<Object> result = | 2588 if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE; |
2341 Execution::Call(trap, handler, ARRAY_SIZE(args), args, has_exception); | 2589 if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY; |
2342 if (has_exception) return NONE; | 2590 return static_cast<PropertyAttributes>(attributes); |
2343 | |
2344 // TODO(rossberg): convert result to PropertyAttributes | |
2345 USE(result); | |
2346 return NONE; | |
2347 } | 2591 } |
2348 | 2592 |
2349 | 2593 |
| 2594 MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler( |
| 2595 JSReceiver* receiver, |
| 2596 uint32_t index) { |
| 2597 Isolate* isolate = GetIsolate(); |
| 2598 HandleScope scope(isolate); |
| 2599 Handle<String> name = isolate->factory()->Uint32ToString(index); |
| 2600 return GetPropertyAttributeWithHandler(receiver, *name); |
| 2601 } |
| 2602 |
| 2603 |
2350 void JSProxy::Fix() { | 2604 void JSProxy::Fix() { |
2351 Isolate* isolate = GetIsolate(); | 2605 Isolate* isolate = GetIsolate(); |
2352 HandleScope scope(isolate); | 2606 HandleScope scope(isolate); |
2353 Handle<JSProxy> self(this); | 2607 Handle<JSProxy> self(this); |
2354 | 2608 |
| 2609 // Save identity hash. |
| 2610 MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION); |
| 2611 |
2355 if (IsJSFunctionProxy()) { | 2612 if (IsJSFunctionProxy()) { |
2356 isolate->factory()->BecomeJSFunction(self); | 2613 isolate->factory()->BecomeJSFunction(self); |
2357 // Code will be set on the JavaScript side. | 2614 // Code will be set on the JavaScript side. |
2358 } else { | 2615 } else { |
2359 isolate->factory()->BecomeJSObject(self); | 2616 isolate->factory()->BecomeJSObject(self); |
2360 } | 2617 } |
2361 ASSERT(self->IsJSObject()); | 2618 ASSERT(self->IsJSObject()); |
| 2619 |
| 2620 // Inherit identity, if it was present. |
| 2621 Object* hash; |
| 2622 if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) { |
| 2623 Handle<JSObject> new_self(JSObject::cast(*self)); |
| 2624 isolate->factory()->SetIdentityHash(new_self, hash); |
| 2625 } |
2362 } | 2626 } |
2363 | 2627 |
2364 | 2628 |
| 2629 MUST_USE_RESULT Handle<Object> JSProxy::CallTrap( |
| 2630 const char* name, |
| 2631 Handle<Object> derived, |
| 2632 int argc, |
| 2633 Handle<Object> args[]) { |
| 2634 Isolate* isolate = GetIsolate(); |
| 2635 Handle<Object> handler(this->handler()); |
| 2636 |
| 2637 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol(name); |
| 2638 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name)); |
| 2639 if (isolate->has_pending_exception()) return trap; |
| 2640 |
| 2641 if (trap->IsUndefined()) { |
| 2642 if (derived.is_null()) { |
| 2643 Handle<Object> args[] = { handler, trap_name }; |
| 2644 Handle<Object> error = isolate->factory()->NewTypeError( |
| 2645 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args))); |
| 2646 isolate->Throw(*error); |
| 2647 return Handle<Object>(); |
| 2648 } |
| 2649 trap = Handle<Object>(derived); |
| 2650 } |
| 2651 |
| 2652 Object*** argv = reinterpret_cast<Object***>(args); |
| 2653 bool threw; |
| 2654 return Execution::Call(trap, handler, argc, argv, &threw); |
| 2655 } |
| 2656 |
2365 | 2657 |
2366 MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, | 2658 MaybeObject* JSObject::SetPropertyForResult(LookupResult* result, |
2367 String* name, | 2659 String* name, |
2368 Object* value, | 2660 Object* value, |
2369 PropertyAttributes attributes, | 2661 PropertyAttributes attributes, |
2370 StrictModeFlag strict_mode) { | 2662 StrictModeFlag strict_mode) { |
2371 Heap* heap = GetHeap(); | 2663 Heap* heap = GetHeap(); |
2372 // Make sure that the top context does not change when doing callbacks or | 2664 // Make sure that the top context does not change when doing callbacks or |
2373 // interceptor calls. | 2665 // interceptor calls. |
2374 AssertNoContextChange ncc; | 2666 AssertNoContextChange ncc; |
2375 | 2667 |
2376 // Optimization for 2-byte strings often used as keys in a decompression | 2668 // Optimization for 2-byte strings often used as keys in a decompression |
2377 // dictionary. We make these short keys into symbols to avoid constantly | 2669 // dictionary. We make these short keys into symbols to avoid constantly |
2378 // reallocating them. | 2670 // reallocating them. |
2379 if (!name->IsSymbol() && name->length() <= 2) { | 2671 if (!name->IsSymbol() && name->length() <= 2) { |
2380 Object* symbol_version; | 2672 Object* symbol_version; |
2381 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name); | 2673 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name); |
2382 if (maybe_symbol_version->ToObject(&symbol_version)) { | 2674 if (maybe_symbol_version->ToObject(&symbol_version)) { |
2383 name = String::cast(symbol_version); | 2675 name = String::cast(symbol_version); |
2384 } | 2676 } |
2385 } | 2677 } |
2386 } | 2678 } |
2387 | 2679 |
2388 // Check access rights if needed. | 2680 // Check access rights if needed. |
2389 if (IsAccessCheckNeeded() | 2681 if (IsAccessCheckNeeded()) { |
2390 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) { | 2682 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) { |
2391 return SetPropertyWithFailedAccessCheck(result, | 2683 return SetPropertyWithFailedAccessCheck( |
2392 name, | 2684 result, name, value, true, strict_mode); |
2393 value, | 2685 } |
2394 true, | |
2395 strict_mode); | |
2396 } | 2686 } |
2397 | 2687 |
2398 if (IsJSGlobalProxy()) { | 2688 if (IsJSGlobalProxy()) { |
2399 Object* proto = GetPrototype(); | 2689 Object* proto = GetPrototype(); |
2400 if (proto->IsNull()) return value; | 2690 if (proto->IsNull()) return value; |
2401 ASSERT(proto->IsJSGlobalObject()); | 2691 ASSERT(proto->IsJSGlobalObject()); |
2402 return JSObject::cast(proto)->SetProperty( | 2692 return JSObject::cast(proto)->SetPropertyForResult( |
2403 result, name, value, attributes, strict_mode); | 2693 result, name, value, attributes, strict_mode); |
2404 } | 2694 } |
2405 | 2695 |
2406 if (!result->IsProperty() && !IsJSContextExtensionObject()) { | 2696 if (!result->IsProperty() && !IsJSContextExtensionObject()) { |
2407 // We could not find a local property so let's check whether there is an | 2697 bool found = false; |
2408 // accessor that wants to handle the property. | 2698 MaybeObject* result_object; |
2409 LookupResult accessor_result; | 2699 result_object = SetPropertyWithCallbackSetterInPrototypes(name, |
2410 LookupCallbackSetterInPrototypes(name, &accessor_result); | 2700 value, |
2411 if (accessor_result.IsProperty()) { | 2701 attributes, |
2412 return SetPropertyWithCallback(accessor_result.GetCallbackObject(), | 2702 &found, |
2413 name, | 2703 strict_mode); |
2414 value, | 2704 if (found) return result_object; |
2415 accessor_result.holder(), | |
2416 strict_mode); | |
2417 } | |
2418 } | 2705 } |
| 2706 |
| 2707 // At this point, no GC should have happened, as this would invalidate |
| 2708 // 'result', which we cannot handlify! |
| 2709 |
2419 if (!result->IsFound()) { | 2710 if (!result->IsFound()) { |
2420 // Neither properties nor transitions found. | 2711 // Neither properties nor transitions found. |
2421 return AddProperty(name, value, attributes, strict_mode); | 2712 return AddProperty(name, value, attributes, strict_mode); |
2422 } | 2713 } |
2423 if (result->IsReadOnly() && result->IsProperty()) { | 2714 if (result->IsReadOnly() && result->IsProperty()) { |
2424 if (strict_mode == kStrictMode) { | 2715 if (strict_mode == kStrictMode) { |
2425 HandleScope scope(heap->isolate()); | 2716 Handle<JSObject> self(this); |
2426 Handle<String> key(name); | 2717 Handle<String> hname(name); |
2427 Handle<Object> holder(this); | 2718 Handle<Object> args[] = { hname, self }; |
2428 Handle<Object> args[2] = { key, holder }; | |
2429 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError( | 2719 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError( |
2430 "strict_read_only_property", HandleVector(args, 2))); | 2720 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); |
2431 } else { | 2721 } else { |
2432 return value; | 2722 return value; |
2433 } | 2723 } |
2434 } | 2724 } |
2435 // This is a real property that is not read-only, or it is a | 2725 // This is a real property that is not read-only, or it is a |
2436 // transition or null descriptor and there are no setters in the prototypes. | 2726 // transition or null descriptor and there are no setters in the prototypes. |
2437 switch (result->type()) { | 2727 switch (result->type()) { |
2438 case NORMAL: | 2728 case NORMAL: |
2439 return SetNormalizedProperty(result, value); | 2729 return SetNormalizedProperty(result, value); |
2440 case FIELD: | 2730 case FIELD: |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2649 *name_handle, | 2939 *name_handle, |
2650 continue_search); | 2940 continue_search); |
2651 } | 2941 } |
2652 | 2942 |
2653 | 2943 |
2654 PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver( | 2944 PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver( |
2655 JSReceiver* receiver, | 2945 JSReceiver* receiver, |
2656 String* key) { | 2946 String* key) { |
2657 uint32_t index = 0; | 2947 uint32_t index = 0; |
2658 if (IsJSObject() && key->AsArrayIndex(&index)) { | 2948 if (IsJSObject() && key->AsArrayIndex(&index)) { |
2659 if (JSObject::cast(this)->HasElementWithReceiver(receiver, index)) | 2949 return JSObject::cast(this)->HasElementWithReceiver(receiver, index) |
2660 return NONE; | 2950 ? NONE : ABSENT; |
2661 return ABSENT; | |
2662 } | 2951 } |
2663 // Named property. | 2952 // Named property. |
2664 LookupResult result; | 2953 LookupResult result; |
2665 Lookup(key, &result); | 2954 Lookup(key, &result); |
2666 return GetPropertyAttribute(receiver, &result, key, true); | 2955 return GetPropertyAttribute(receiver, &result, key, true); |
2667 } | 2956 } |
2668 | 2957 |
2669 | 2958 |
2670 PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver, | 2959 PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver, |
2671 LookupResult* result, | 2960 LookupResult* result, |
2672 String* name, | 2961 String* name, |
2673 bool continue_search) { | 2962 bool continue_search) { |
2674 // Check access rights if needed. | 2963 // Check access rights if needed. |
2675 if (IsAccessCheckNeeded()) { | 2964 if (IsAccessCheckNeeded()) { |
2676 JSObject* this_obj = JSObject::cast(this); | 2965 JSObject* this_obj = JSObject::cast(this); |
2677 Heap* heap = GetHeap(); | 2966 Heap* heap = GetHeap(); |
2678 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) { | 2967 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) { |
2679 return this_obj->GetPropertyAttributeWithFailedAccessCheck( | 2968 return this_obj->GetPropertyAttributeWithFailedAccessCheck( |
2680 receiver, result, name, continue_search); | 2969 receiver, result, name, continue_search); |
2681 } | 2970 } |
2682 } | 2971 } |
2683 if (result->IsProperty()) { | 2972 if (result->IsProperty()) { |
2684 switch (result->type()) { | 2973 switch (result->type()) { |
2685 case NORMAL: // fall through | 2974 case NORMAL: // fall through |
2686 case FIELD: | 2975 case FIELD: |
2687 case CONSTANT_FUNCTION: | 2976 case CONSTANT_FUNCTION: |
2688 case CALLBACKS: | 2977 case CALLBACKS: |
2689 return result->GetAttributes(); | 2978 return result->GetAttributes(); |
2690 case HANDLER: { | 2979 case HANDLER: { |
2691 // TODO(rossberg): propagate exceptions properly. | 2980 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler( |
2692 bool has_exception = false; | 2981 receiver, name); |
2693 return JSProxy::cast(this)->GetPropertyAttributeWithHandler( | |
2694 receiver, name, &has_exception); | |
2695 } | 2982 } |
2696 case INTERCEPTOR: | 2983 case INTERCEPTOR: |
2697 return result->holder()->GetPropertyAttributeWithInterceptor( | 2984 return result->holder()->GetPropertyAttributeWithInterceptor( |
2698 JSObject::cast(receiver), name, continue_search); | 2985 JSObject::cast(receiver), name, continue_search); |
2699 default: | 2986 default: |
2700 UNREACHABLE(); | 2987 UNREACHABLE(); |
2701 } | 2988 } |
2702 } | 2989 } |
2703 return ABSENT; | 2990 return ABSENT; |
2704 } | 2991 } |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2850 case CONSTANT_TRANSITION: | 3137 case CONSTANT_TRANSITION: |
2851 case NULL_DESCRIPTOR: | 3138 case NULL_DESCRIPTOR: |
2852 case INTERCEPTOR: | 3139 case INTERCEPTOR: |
2853 case ELEMENTS_TRANSITION: | 3140 case ELEMENTS_TRANSITION: |
2854 break; | 3141 break; |
2855 default: | 3142 default: |
2856 UNREACHABLE(); | 3143 UNREACHABLE(); |
2857 } | 3144 } |
2858 } | 3145 } |
2859 | 3146 |
2860 Heap* current_heap = map_of_this->heap(); | 3147 Heap* current_heap = GetHeap(); |
2861 | 3148 |
2862 // Copy the next enumeration index from instance descriptor. | 3149 // Copy the next enumeration index from instance descriptor. |
2863 int index = map_of_this->instance_descriptors()->NextEnumerationIndex(); | 3150 int index = map_of_this->instance_descriptors()->NextEnumerationIndex(); |
2864 dictionary->SetNextEnumerationIndex(index); | 3151 dictionary->SetNextEnumerationIndex(index); |
2865 | 3152 |
2866 { MaybeObject* maybe_obj = | 3153 { MaybeObject* maybe_obj = |
2867 current_heap->isolate()->context()->global_context()-> | 3154 current_heap->isolate()->context()->global_context()-> |
2868 normalized_map_cache()->Get(this, mode); | 3155 normalized_map_cache()->Get(this, mode); |
2869 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 3156 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
2870 } | 3157 } |
2871 Map* new_map = Map::cast(obj); | 3158 Map* new_map = Map::cast(obj); |
2872 | 3159 |
2873 // We have now successfully allocated all the necessary objects. | 3160 // We have now successfully allocated all the necessary objects. |
2874 // Changes can now be made with the guarantee that all of them take effect. | 3161 // Changes can now be made with the guarantee that all of them take effect. |
2875 | 3162 |
2876 // Resize the object in the heap if necessary. | 3163 // Resize the object in the heap if necessary. |
2877 int new_instance_size = new_map->instance_size(); | 3164 int new_instance_size = new_map->instance_size(); |
2878 int instance_size_delta = map_of_this->instance_size() - new_instance_size; | 3165 int instance_size_delta = map_of_this->instance_size() - new_instance_size; |
2879 ASSERT(instance_size_delta >= 0); | 3166 ASSERT(instance_size_delta >= 0); |
2880 current_heap->CreateFillerObjectAt(this->address() + new_instance_size, | 3167 current_heap->CreateFillerObjectAt(this->address() + new_instance_size, |
2881 instance_size_delta); | 3168 instance_size_delta); |
| 3169 if (Marking::IsBlack(Marking::MarkBitFrom(this))) { |
| 3170 MemoryChunk::IncrementLiveBytes(this->address(), -instance_size_delta); |
| 3171 } |
| 3172 |
2882 | 3173 |
2883 set_map(new_map); | 3174 set_map(new_map); |
2884 new_map->clear_instance_descriptors(); | 3175 new_map->clear_instance_descriptors(); |
2885 | 3176 |
2886 set_properties(dictionary); | 3177 set_properties(dictionary); |
2887 | 3178 |
2888 current_heap->isolate()->counters()->props_to_dictionary()->Increment(); | 3179 current_heap->isolate()->counters()->props_to_dictionary()->Increment(); |
2889 | 3180 |
2890 #ifdef DEBUG | 3181 #ifdef DEBUG |
2891 if (FLAG_trace_normalization) { | 3182 if (FLAG_trace_normalization) { |
(...skipping 13 matching lines...) Expand all Loading... |
2905 } | 3196 } |
2906 | 3197 |
2907 | 3198 |
2908 MaybeObject* JSObject::NormalizeElements() { | 3199 MaybeObject* JSObject::NormalizeElements() { |
2909 ASSERT(!HasExternalArrayElements()); | 3200 ASSERT(!HasExternalArrayElements()); |
2910 | 3201 |
2911 // Find the backing store. | 3202 // Find the backing store. |
2912 FixedArrayBase* array = FixedArrayBase::cast(elements()); | 3203 FixedArrayBase* array = FixedArrayBase::cast(elements()); |
2913 Map* old_map = array->map(); | 3204 Map* old_map = array->map(); |
2914 bool is_arguments = | 3205 bool is_arguments = |
2915 (old_map == old_map->heap()->non_strict_arguments_elements_map()); | 3206 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map()); |
2916 if (is_arguments) { | 3207 if (is_arguments) { |
2917 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1)); | 3208 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1)); |
2918 } | 3209 } |
2919 if (array->IsDictionary()) return array; | 3210 if (array->IsDictionary()) return array; |
2920 | 3211 |
2921 ASSERT(HasFastElements() || | 3212 ASSERT(HasFastElements() || |
| 3213 HasFastSmiOnlyElements() || |
2922 HasFastDoubleElements() || | 3214 HasFastDoubleElements() || |
2923 HasFastArgumentsElements()); | 3215 HasFastArgumentsElements()); |
2924 // Compute the effective length and allocate a new backing store. | 3216 // Compute the effective length and allocate a new backing store. |
2925 int length = IsJSArray() | 3217 int length = IsJSArray() |
2926 ? Smi::cast(JSArray::cast(this)->length())->value() | 3218 ? Smi::cast(JSArray::cast(this)->length())->value() |
2927 : array->length(); | 3219 : array->length(); |
2928 int old_capacity = 0; | 3220 int old_capacity = 0; |
2929 int used_elements = 0; | 3221 int used_elements = 0; |
2930 GetElementsCapacityAndUsage(&old_capacity, &used_elements); | 3222 GetElementsCapacityAndUsage(&old_capacity, &used_elements); |
2931 NumberDictionary* dictionary = NULL; | 3223 NumberDictionary* dictionary = NULL; |
(...skipping 14 matching lines...) Expand all Loading... |
2946 } else { | 3238 } else { |
2947 // Objects must be allocated in the old object space, since the | 3239 // Objects must be allocated in the old object space, since the |
2948 // overall number of HeapNumbers needed for the conversion might | 3240 // overall number of HeapNumbers needed for the conversion might |
2949 // exceed the capacity of new space, and we would fail repeatedly | 3241 // exceed the capacity of new space, and we would fail repeatedly |
2950 // trying to convert the FixedDoubleArray. | 3242 // trying to convert the FixedDoubleArray. |
2951 MaybeObject* maybe_value_object = | 3243 MaybeObject* maybe_value_object = |
2952 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED); | 3244 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED); |
2953 if (!maybe_value_object->ToObject(&value)) return maybe_value_object; | 3245 if (!maybe_value_object->ToObject(&value)) return maybe_value_object; |
2954 } | 3246 } |
2955 } else { | 3247 } else { |
2956 ASSERT(old_map->has_fast_elements()); | 3248 ASSERT(old_map->has_fast_elements() || |
| 3249 old_map->has_fast_smi_only_elements()); |
2957 value = FixedArray::cast(array)->get(i); | 3250 value = FixedArray::cast(array)->get(i); |
2958 } | 3251 } |
2959 PropertyDetails details = PropertyDetails(NONE, NORMAL); | 3252 PropertyDetails details = PropertyDetails(NONE, NORMAL); |
2960 if (!value->IsTheHole()) { | 3253 if (!value->IsTheHole()) { |
2961 Object* result; | 3254 Object* result; |
2962 MaybeObject* maybe_result = | 3255 MaybeObject* maybe_result = |
2963 dictionary->AddNumberEntry(i, value, details); | 3256 dictionary->AddNumberEntry(i, value, details); |
2964 if (!maybe_result->ToObject(&result)) return maybe_result; | 3257 if (!maybe_result->ToObject(&result)) return maybe_result; |
2965 dictionary = NumberDictionary::cast(result); | 3258 dictionary = NumberDictionary::cast(result); |
2966 } | 3259 } |
2967 } | 3260 } |
2968 | 3261 |
2969 // Switch to using the dictionary as the backing storage for elements. | 3262 // Switch to using the dictionary as the backing storage for elements. |
2970 if (is_arguments) { | 3263 if (is_arguments) { |
2971 FixedArray::cast(elements())->set(1, dictionary); | 3264 FixedArray::cast(elements())->set(1, dictionary); |
2972 } else { | 3265 } else { |
2973 // Set the new map first to satify the elements type assert in | 3266 // Set the new map first to satify the elements type assert in |
2974 // set_elements(). | 3267 // set_elements(). |
2975 Object* new_map; | 3268 Object* new_map; |
2976 MaybeObject* maybe = map()->GetSlowElementsMap(); | 3269 MaybeObject* maybe = GetElementsTransitionMap(DICTIONARY_ELEMENTS); |
2977 if (!maybe->ToObject(&new_map)) return maybe; | 3270 if (!maybe->ToObject(&new_map)) return maybe; |
2978 set_map(Map::cast(new_map)); | 3271 set_map(Map::cast(new_map)); |
2979 set_elements(dictionary); | 3272 set_elements(dictionary); |
2980 } | 3273 } |
2981 | 3274 |
2982 old_map->isolate()->counters()->elements_to_dictionary()->Increment(); | 3275 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()-> |
| 3276 Increment(); |
2983 | 3277 |
2984 #ifdef DEBUG | 3278 #ifdef DEBUG |
2985 if (FLAG_trace_normalization) { | 3279 if (FLAG_trace_normalization) { |
2986 PrintF("Object elements have been normalized:\n"); | 3280 PrintF("Object elements have been normalized:\n"); |
2987 Print(); | 3281 Print(); |
2988 } | 3282 } |
2989 #endif | 3283 #endif |
2990 | 3284 |
2991 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); | 3285 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
2992 return dictionary; | 3286 return dictionary; |
2993 } | 3287 } |
2994 | 3288 |
2995 | 3289 |
2996 MaybeObject* JSObject::GetHiddenProperties(HiddenPropertiesFlag flag) { | 3290 Smi* JSReceiver::GenerateIdentityHash() { |
2997 Isolate* isolate = GetIsolate(); | 3291 Isolate* isolate = GetIsolate(); |
2998 Heap* heap = isolate->heap(); | |
2999 Object* holder = BypassGlobalProxy(); | |
3000 if (holder->IsUndefined()) return heap->undefined_value(); | |
3001 JSObject* obj = JSObject::cast(holder); | |
3002 if (obj->HasFastProperties()) { | |
3003 // If the object has fast properties, check whether the first slot | |
3004 // in the descriptor array matches the hidden symbol. Since the | |
3005 // hidden symbols hash code is zero (and no other string has hash | |
3006 // code zero) it will always occupy the first entry if present. | |
3007 DescriptorArray* descriptors = obj->map()->instance_descriptors(); | |
3008 if ((descriptors->number_of_descriptors() > 0) && | |
3009 (descriptors->GetKey(0) == heap->hidden_symbol()) && | |
3010 descriptors->IsProperty(0)) { | |
3011 ASSERT(descriptors->GetType(0) == FIELD); | |
3012 return obj->FastPropertyAt(descriptors->GetFieldIndex(0)); | |
3013 } | |
3014 } | |
3015 | |
3016 // Only attempt to find the hidden properties in the local object and not | |
3017 // in the prototype chain. | |
3018 if (!obj->HasHiddenPropertiesObject()) { | |
3019 // Hidden properties object not found. Allocate a new hidden properties | |
3020 // object if requested. Otherwise return the undefined value. | |
3021 if (flag == ALLOW_CREATION) { | |
3022 Object* hidden_obj; | |
3023 { MaybeObject* maybe_obj = heap->AllocateJSObject( | |
3024 isolate->context()->global_context()->object_function()); | |
3025 if (!maybe_obj->ToObject(&hidden_obj)) return maybe_obj; | |
3026 } | |
3027 // Don't allow leakage of the hidden object through accessors | |
3028 // on Object.prototype. | |
3029 { | |
3030 MaybeObject* maybe_obj = | |
3031 JSObject::cast(hidden_obj)->SetPrototype(heap->null_value(), false); | |
3032 if (maybe_obj->IsFailure()) return maybe_obj; | |
3033 } | |
3034 return obj->SetHiddenPropertiesObject(hidden_obj); | |
3035 } else { | |
3036 return heap->undefined_value(); | |
3037 } | |
3038 } | |
3039 return obj->GetHiddenPropertiesObject(); | |
3040 } | |
3041 | |
3042 | |
3043 MaybeObject* JSObject::GetIdentityHash(HiddenPropertiesFlag flag) { | |
3044 Isolate* isolate = GetIsolate(); | |
3045 Object* hidden_props_obj; | |
3046 { MaybeObject* maybe_obj = GetHiddenProperties(flag); | |
3047 if (!maybe_obj->ToObject(&hidden_props_obj)) return maybe_obj; | |
3048 } | |
3049 if (!hidden_props_obj->IsJSObject()) { | |
3050 // We failed to create hidden properties. That's a detached | |
3051 // global proxy. | |
3052 ASSERT(hidden_props_obj->IsUndefined()); | |
3053 return Smi::FromInt(0); | |
3054 } | |
3055 JSObject* hidden_props = JSObject::cast(hidden_props_obj); | |
3056 String* hash_symbol = isolate->heap()->identity_hash_symbol(); | |
3057 { | |
3058 // Note that HasLocalProperty() can cause a GC in the general case in the | |
3059 // presence of interceptors. | |
3060 AssertNoAllocation no_alloc; | |
3061 if (hidden_props->HasLocalProperty(hash_symbol)) { | |
3062 MaybeObject* hash = hidden_props->GetProperty(hash_symbol); | |
3063 return Smi::cast(hash->ToObjectChecked()); | |
3064 } | |
3065 } | |
3066 | 3292 |
3067 int hash_value; | 3293 int hash_value; |
3068 int attempts = 0; | 3294 int attempts = 0; |
3069 do { | 3295 do { |
3070 // Generate a random 32-bit hash value but limit range to fit | 3296 // Generate a random 32-bit hash value but limit range to fit |
3071 // within a smi. | 3297 // within a smi. |
3072 hash_value = V8::Random(isolate) & Smi::kMaxValue; | 3298 hash_value = V8::Random(isolate) & Smi::kMaxValue; |
3073 attempts++; | 3299 attempts++; |
3074 } while (hash_value == 0 && attempts < 30); | 3300 } while (hash_value == 0 && attempts < 30); |
3075 hash_value = hash_value != 0 ? hash_value : 1; // never return 0 | 3301 hash_value = hash_value != 0 ? hash_value : 1; // never return 0 |
3076 | 3302 |
3077 Smi* hash = Smi::FromInt(hash_value); | 3303 return Smi::FromInt(hash_value); |
3078 { MaybeObject* result = hidden_props->SetLocalPropertyIgnoreAttributes( | 3304 } |
3079 hash_symbol, | 3305 |
3080 hash, | 3306 |
3081 static_cast<PropertyAttributes>(None)); | 3307 MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) { |
3082 if (result->IsFailure()) return result; | 3308 MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(), |
| 3309 hash); |
| 3310 if (maybe->IsFailure()) return maybe; |
| 3311 return this; |
| 3312 } |
| 3313 |
| 3314 |
| 3315 MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) { |
| 3316 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol()); |
| 3317 if (stored_value->IsSmi()) return stored_value; |
| 3318 |
| 3319 Smi* hash = GenerateIdentityHash(); |
| 3320 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(), |
| 3321 hash); |
| 3322 if (result->IsFailure()) return result; |
| 3323 if (result->ToObjectUnchecked()->IsUndefined()) { |
| 3324 // Trying to get hash of detached proxy. |
| 3325 return Smi::FromInt(0); |
3083 } | 3326 } |
3084 return hash; | 3327 return hash; |
3085 } | 3328 } |
3086 | 3329 |
3087 | 3330 |
| 3331 MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) { |
| 3332 Object* hash = this->hash(); |
| 3333 if (!hash->IsSmi() && flag == ALLOW_CREATION) { |
| 3334 hash = GenerateIdentityHash(); |
| 3335 set_hash(hash); |
| 3336 } |
| 3337 return hash; |
| 3338 } |
| 3339 |
| 3340 |
| 3341 Object* JSObject::GetHiddenProperty(String* key) { |
| 3342 if (IsJSGlobalProxy()) { |
| 3343 // For a proxy, use the prototype as target object. |
| 3344 Object* proxy_parent = GetPrototype(); |
| 3345 // If the proxy is detached, return undefined. |
| 3346 if (proxy_parent->IsNull()) return GetHeap()->undefined_value(); |
| 3347 ASSERT(proxy_parent->IsJSGlobalObject()); |
| 3348 return JSObject::cast(proxy_parent)->GetHiddenProperty(key); |
| 3349 } |
| 3350 ASSERT(!IsJSGlobalProxy()); |
| 3351 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false); |
| 3352 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg. |
| 3353 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) { |
| 3354 return GetHeap()->undefined_value(); |
| 3355 } |
| 3356 StringDictionary* dictionary = |
| 3357 StringDictionary::cast(hidden_lookup->ToObjectUnchecked()); |
| 3358 int entry = dictionary->FindEntry(key); |
| 3359 if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value(); |
| 3360 return dictionary->ValueAt(entry); |
| 3361 } |
| 3362 |
| 3363 |
| 3364 MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) { |
| 3365 if (IsJSGlobalProxy()) { |
| 3366 // For a proxy, use the prototype as target object. |
| 3367 Object* proxy_parent = GetPrototype(); |
| 3368 // If the proxy is detached, return undefined. |
| 3369 if (proxy_parent->IsNull()) return GetHeap()->undefined_value(); |
| 3370 ASSERT(proxy_parent->IsJSGlobalObject()); |
| 3371 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value); |
| 3372 } |
| 3373 ASSERT(!IsJSGlobalProxy()); |
| 3374 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true); |
| 3375 StringDictionary* dictionary; |
| 3376 if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup; |
| 3377 |
| 3378 // If it was found, check if the key is already in the dictionary. |
| 3379 int entry = dictionary->FindEntry(key); |
| 3380 if (entry != StringDictionary::kNotFound) { |
| 3381 // If key was found, just update the value. |
| 3382 dictionary->ValueAtPut(entry, value); |
| 3383 return this; |
| 3384 } |
| 3385 // Key was not already in the dictionary, so add the entry. |
| 3386 MaybeObject* insert_result = dictionary->Add(key, |
| 3387 value, |
| 3388 PropertyDetails(NONE, NORMAL)); |
| 3389 StringDictionary* new_dict; |
| 3390 if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result; |
| 3391 if (new_dict != dictionary) { |
| 3392 // If adding the key expanded the dictionary (i.e., Add returned a new |
| 3393 // dictionary), store it back to the object. |
| 3394 MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict); |
| 3395 if (store_result->IsFailure()) return store_result; |
| 3396 } |
| 3397 // Return this to mark success. |
| 3398 return this; |
| 3399 } |
| 3400 |
| 3401 |
| 3402 void JSObject::DeleteHiddenProperty(String* key) { |
| 3403 if (IsJSGlobalProxy()) { |
| 3404 // For a proxy, use the prototype as target object. |
| 3405 Object* proxy_parent = GetPrototype(); |
| 3406 // If the proxy is detached, return immediately. |
| 3407 if (proxy_parent->IsNull()) return; |
| 3408 ASSERT(proxy_parent->IsJSGlobalObject()); |
| 3409 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key); |
| 3410 return; |
| 3411 } |
| 3412 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false); |
| 3413 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg. |
| 3414 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return; |
| 3415 StringDictionary* dictionary = |
| 3416 StringDictionary::cast(hidden_lookup->ToObjectUnchecked()); |
| 3417 int entry = dictionary->FindEntry(key); |
| 3418 if (entry == StringDictionary::kNotFound) { |
| 3419 // Key wasn't in dictionary. Deletion is a success. |
| 3420 return; |
| 3421 } |
| 3422 // Key was in the dictionary. Remove it. |
| 3423 dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION); |
| 3424 } |
| 3425 |
| 3426 |
| 3427 bool JSObject::HasHiddenProperties() { |
| 3428 LookupResult lookup; |
| 3429 LocalLookupRealNamedProperty(GetHeap()->hidden_symbol(), &lookup); |
| 3430 return lookup.IsFound(); |
| 3431 } |
| 3432 |
| 3433 |
| 3434 MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) { |
| 3435 ASSERT(!IsJSGlobalProxy()); |
| 3436 if (HasFastProperties()) { |
| 3437 // If the object has fast properties, check whether the first slot |
| 3438 // in the descriptor array matches the hidden symbol. Since the |
| 3439 // hidden symbols hash code is zero (and no other string has hash |
| 3440 // code zero) it will always occupy the first entry if present. |
| 3441 DescriptorArray* descriptors = this->map()->instance_descriptors(); |
| 3442 if ((descriptors->number_of_descriptors() > 0) && |
| 3443 (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) && |
| 3444 descriptors->IsProperty(0)) { |
| 3445 ASSERT(descriptors->GetType(0) == FIELD); |
| 3446 Object* hidden_store = |
| 3447 this->FastPropertyAt(descriptors->GetFieldIndex(0)); |
| 3448 return StringDictionary::cast(hidden_store); |
| 3449 } |
| 3450 } else { |
| 3451 PropertyAttributes attributes; |
| 3452 // You can't install a getter on a property indexed by the hidden symbol, |
| 3453 // so we can be sure that GetLocalPropertyPostInterceptor returns a real |
| 3454 // object. |
| 3455 Object* lookup = |
| 3456 GetLocalPropertyPostInterceptor(this, |
| 3457 GetHeap()->hidden_symbol(), |
| 3458 &attributes)->ToObjectUnchecked(); |
| 3459 if (!lookup->IsUndefined()) { |
| 3460 return StringDictionary::cast(lookup); |
| 3461 } |
| 3462 } |
| 3463 if (!create_if_absent) return GetHeap()->undefined_value(); |
| 3464 const int kInitialSize = 5; |
| 3465 MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize); |
| 3466 StringDictionary* dictionary; |
| 3467 if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc; |
| 3468 MaybeObject* store_result = |
| 3469 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), |
| 3470 dictionary, |
| 3471 DONT_ENUM, |
| 3472 kNonStrictMode); |
| 3473 if (store_result->IsFailure()) return store_result; |
| 3474 return dictionary; |
| 3475 } |
| 3476 |
| 3477 |
| 3478 MaybeObject* JSObject::SetHiddenPropertiesDictionary( |
| 3479 StringDictionary* dictionary) { |
| 3480 ASSERT(!IsJSGlobalProxy()); |
| 3481 ASSERT(HasHiddenProperties()); |
| 3482 if (HasFastProperties()) { |
| 3483 // If the object has fast properties, check whether the first slot |
| 3484 // in the descriptor array matches the hidden symbol. Since the |
| 3485 // hidden symbols hash code is zero (and no other string has hash |
| 3486 // code zero) it will always occupy the first entry if present. |
| 3487 DescriptorArray* descriptors = this->map()->instance_descriptors(); |
| 3488 if ((descriptors->number_of_descriptors() > 0) && |
| 3489 (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) && |
| 3490 descriptors->IsProperty(0)) { |
| 3491 ASSERT(descriptors->GetType(0) == FIELD); |
| 3492 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary); |
| 3493 return this; |
| 3494 } |
| 3495 } |
| 3496 MaybeObject* store_result = |
| 3497 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), |
| 3498 dictionary, |
| 3499 DONT_ENUM, |
| 3500 kNonStrictMode); |
| 3501 if (store_result->IsFailure()) return store_result; |
| 3502 return this; |
| 3503 } |
| 3504 |
| 3505 |
3088 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, | 3506 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, |
3089 DeleteMode mode) { | 3507 DeleteMode mode) { |
3090 // Check local property, ignore interceptor. | 3508 // Check local property, ignore interceptor. |
3091 LookupResult result; | 3509 LookupResult result; |
3092 LocalLookupRealNamedProperty(name, &result); | 3510 LocalLookupRealNamedProperty(name, &result); |
3093 if (!result.IsProperty()) return GetHeap()->true_value(); | 3511 if (!result.IsProperty()) return GetHeap()->true_value(); |
3094 | 3512 |
3095 // Normalize object if needed. | 3513 // Normalize object if needed. |
3096 Object* obj; | 3514 Object* obj; |
3097 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 3515 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3194 mode = JSReceiver::FORCE_DELETION; | 3612 mode = JSReceiver::FORCE_DELETION; |
3195 } | 3613 } |
3196 | 3614 |
3197 return GetElementsAccessor()->Delete(this, index, mode); | 3615 return GetElementsAccessor()->Delete(this, index, mode); |
3198 } | 3616 } |
3199 | 3617 |
3200 | 3618 |
3201 MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) { | 3619 MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) { |
3202 if (IsJSProxy()) { | 3620 if (IsJSProxy()) { |
3203 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode); | 3621 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode); |
3204 } else { | |
3205 return JSObject::cast(this)->DeleteProperty(name, mode); | |
3206 } | 3622 } |
| 3623 return JSObject::cast(this)->DeleteProperty(name, mode); |
| 3624 } |
| 3625 |
| 3626 |
| 3627 MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) { |
| 3628 if (IsJSProxy()) { |
| 3629 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode); |
| 3630 } |
| 3631 return JSObject::cast(this)->DeleteElement(index, mode); |
3207 } | 3632 } |
3208 | 3633 |
3209 | 3634 |
3210 MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { | 3635 MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { |
3211 Isolate* isolate = GetIsolate(); | 3636 Isolate* isolate = GetIsolate(); |
3212 // ECMA-262, 3rd, 8.6.2.5 | 3637 // ECMA-262, 3rd, 8.6.2.5 |
3213 ASSERT(name->IsString()); | 3638 ASSERT(name->IsString()); |
3214 | 3639 |
3215 // Check access rights if needed. | 3640 // Check access rights if needed. |
3216 if (IsAccessCheckNeeded() && | 3641 if (IsAccessCheckNeeded() && |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3260 } | 3685 } |
3261 // Make sure the properties are normalized before removing the entry. | 3686 // Make sure the properties are normalized before removing the entry. |
3262 return DeleteNormalizedProperty(name, mode); | 3687 return DeleteNormalizedProperty(name, mode); |
3263 } | 3688 } |
3264 } | 3689 } |
3265 | 3690 |
3266 | 3691 |
3267 bool JSObject::ReferencesObjectFromElements(FixedArray* elements, | 3692 bool JSObject::ReferencesObjectFromElements(FixedArray* elements, |
3268 ElementsKind kind, | 3693 ElementsKind kind, |
3269 Object* object) { | 3694 Object* object) { |
3270 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS); | 3695 ASSERT(kind == FAST_ELEMENTS || |
| 3696 kind == DICTIONARY_ELEMENTS); |
3271 if (kind == FAST_ELEMENTS) { | 3697 if (kind == FAST_ELEMENTS) { |
3272 int length = IsJSArray() | 3698 int length = IsJSArray() |
3273 ? Smi::cast(JSArray::cast(this)->length())->value() | 3699 ? Smi::cast(JSArray::cast(this)->length())->value() |
3274 : elements->length(); | 3700 : elements->length(); |
3275 for (int i = 0; i < length; ++i) { | 3701 for (int i = 0; i < length; ++i) { |
3276 Object* element = elements->get(i); | 3702 Object* element = elements->get(i); |
3277 if (!element->IsTheHole() && element == object) return true; | 3703 if (!element->IsTheHole() && element == object) return true; |
3278 } | 3704 } |
3279 } else { | 3705 } else { |
3280 Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object); | 3706 Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object); |
3281 if (!key->IsUndefined()) return true; | 3707 if (!key->IsUndefined()) return true; |
3282 } | 3708 } |
3283 return false; | 3709 return false; |
3284 } | 3710 } |
3285 | 3711 |
3286 | 3712 |
3287 // Check whether this object references another object. | 3713 // Check whether this object references another object. |
3288 bool JSObject::ReferencesObject(Object* obj) { | 3714 bool JSObject::ReferencesObject(Object* obj) { |
3289 Map* map_of_this = map(); | 3715 Map* map_of_this = map(); |
3290 Heap* heap = map_of_this->heap(); | 3716 Heap* heap = GetHeap(); |
3291 AssertNoAllocation no_alloc; | 3717 AssertNoAllocation no_alloc; |
3292 | 3718 |
3293 // Is the object the constructor for this object? | 3719 // Is the object the constructor for this object? |
3294 if (map_of_this->constructor() == obj) { | 3720 if (map_of_this->constructor() == obj) { |
3295 return true; | 3721 return true; |
3296 } | 3722 } |
3297 | 3723 |
3298 // Is the object the prototype for this object? | 3724 // Is the object the prototype for this object? |
3299 if (map_of_this->prototype() == obj) { | 3725 if (map_of_this->prototype() == obj) { |
3300 return true; | 3726 return true; |
(...skipping 14 matching lines...) Expand all Loading... |
3315 case EXTERNAL_SHORT_ELEMENTS: | 3741 case EXTERNAL_SHORT_ELEMENTS: |
3316 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 3742 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
3317 case EXTERNAL_INT_ELEMENTS: | 3743 case EXTERNAL_INT_ELEMENTS: |
3318 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3744 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
3319 case EXTERNAL_FLOAT_ELEMENTS: | 3745 case EXTERNAL_FLOAT_ELEMENTS: |
3320 case EXTERNAL_DOUBLE_ELEMENTS: | 3746 case EXTERNAL_DOUBLE_ELEMENTS: |
3321 case FAST_DOUBLE_ELEMENTS: | 3747 case FAST_DOUBLE_ELEMENTS: |
3322 // Raw pixels and external arrays do not reference other | 3748 // Raw pixels and external arrays do not reference other |
3323 // objects. | 3749 // objects. |
3324 break; | 3750 break; |
| 3751 case FAST_SMI_ONLY_ELEMENTS: |
| 3752 break; |
3325 case FAST_ELEMENTS: | 3753 case FAST_ELEMENTS: |
3326 case DICTIONARY_ELEMENTS: { | 3754 case DICTIONARY_ELEMENTS: { |
3327 FixedArray* elements = FixedArray::cast(this->elements()); | 3755 FixedArray* elements = FixedArray::cast(this->elements()); |
3328 if (ReferencesObjectFromElements(elements, kind, obj)) return true; | 3756 if (ReferencesObjectFromElements(elements, kind, obj)) return true; |
3329 break; | 3757 break; |
3330 } | 3758 } |
3331 case NON_STRICT_ARGUMENTS_ELEMENTS: { | 3759 case NON_STRICT_ARGUMENTS_ELEMENTS: { |
3332 FixedArray* parameter_map = FixedArray::cast(elements()); | 3760 FixedArray* parameter_map = FixedArray::cast(elements()); |
3333 // Check the mapped parameters. | 3761 // Check the mapped parameters. |
3334 int length = parameter_map->length(); | 3762 int length = parameter_map->length(); |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3502 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 3930 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
3503 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) { | 3931 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) { |
3504 return descs->GetCallbacks(i); | 3932 return descs->GetCallbacks(i); |
3505 } | 3933 } |
3506 } | 3934 } |
3507 return NULL; | 3935 return NULL; |
3508 } | 3936 } |
3509 | 3937 |
3510 | 3938 |
3511 void JSReceiver::LocalLookup(String* name, LookupResult* result) { | 3939 void JSReceiver::LocalLookup(String* name, LookupResult* result) { |
3512 if (IsJSProxy()) { | |
3513 result->HandlerResult(); | |
3514 } else { | |
3515 JSObject::cast(this)->LocalLookup(name, result); | |
3516 } | |
3517 } | |
3518 | |
3519 | |
3520 void JSObject::LocalLookup(String* name, LookupResult* result) { | |
3521 ASSERT(name->IsString()); | 3940 ASSERT(name->IsString()); |
3522 | 3941 |
3523 Heap* heap = GetHeap(); | 3942 Heap* heap = GetHeap(); |
3524 | 3943 |
3525 if (IsJSGlobalProxy()) { | 3944 if (IsJSGlobalProxy()) { |
3526 Object* proto = GetPrototype(); | 3945 Object* proto = GetPrototype(); |
3527 if (proto->IsNull()) return result->NotFound(); | 3946 if (proto->IsNull()) return result->NotFound(); |
3528 ASSERT(proto->IsJSGlobalObject()); | 3947 ASSERT(proto->IsJSGlobalObject()); |
3529 return JSObject::cast(proto)->LocalLookup(name, result); | 3948 return JSReceiver::cast(proto)->LocalLookup(name, result); |
| 3949 } |
| 3950 |
| 3951 if (IsJSProxy()) { |
| 3952 result->HandlerResult(JSProxy::cast(this)); |
| 3953 return; |
3530 } | 3954 } |
3531 | 3955 |
3532 // Do not use inline caching if the object is a non-global object | 3956 // Do not use inline caching if the object is a non-global object |
3533 // that requires access checks. | 3957 // that requires access checks. |
3534 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) { | 3958 if (IsAccessCheckNeeded()) { |
3535 result->DisallowCaching(); | 3959 result->DisallowCaching(); |
3536 } | 3960 } |
3537 | 3961 |
| 3962 JSObject* js_object = JSObject::cast(this); |
| 3963 |
3538 // Check __proto__ before interceptor. | 3964 // Check __proto__ before interceptor. |
3539 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) { | 3965 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) { |
3540 result->ConstantResult(this); | 3966 result->ConstantResult(js_object); |
3541 return; | 3967 return; |
3542 } | 3968 } |
3543 | 3969 |
3544 // Check for lookup interceptor except when bootstrapping. | 3970 // Check for lookup interceptor except when bootstrapping. |
3545 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) { | 3971 if (js_object->HasNamedInterceptor() && |
3546 result->InterceptorResult(this); | 3972 !heap->isolate()->bootstrapper()->IsActive()) { |
| 3973 result->InterceptorResult(js_object); |
3547 return; | 3974 return; |
3548 } | 3975 } |
3549 | 3976 |
3550 LocalLookupRealNamedProperty(name, result); | 3977 js_object->LocalLookupRealNamedProperty(name, result); |
3551 } | 3978 } |
3552 | 3979 |
3553 | 3980 |
3554 void JSReceiver::Lookup(String* name, LookupResult* result) { | 3981 void JSReceiver::Lookup(String* name, LookupResult* result) { |
3555 // Ecma-262 3rd 8.6.2.4 | 3982 // Ecma-262 3rd 8.6.2.4 |
3556 Heap* heap = GetHeap(); | 3983 Heap* heap = GetHeap(); |
3557 for (Object* current = this; | 3984 for (Object* current = this; |
3558 current != heap->null_value(); | 3985 current != heap->null_value(); |
3559 current = JSObject::cast(current)->GetPrototype()) { | 3986 current = JSObject::cast(current)->GetPrototype()) { |
3560 JSObject::cast(current)->LocalLookup(name, result); | 3987 JSReceiver::cast(current)->LocalLookup(name, result); |
3561 if (result->IsProperty()) return; | 3988 if (result->IsProperty()) return; |
3562 } | 3989 } |
3563 result->NotFound(); | 3990 result->NotFound(); |
3564 } | 3991 } |
3565 | 3992 |
3566 | 3993 |
3567 // Search object and it's prototype chain for callback properties. | 3994 // Search object and it's prototype chain for callback properties. |
3568 void JSObject::LookupCallback(String* name, LookupResult* result) { | 3995 void JSObject::LookupCallback(String* name, LookupResult* result) { |
3569 Heap* heap = GetHeap(); | 3996 Heap* heap = GetHeap(); |
3570 for (Object* current = this; | 3997 for (Object* current = this; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3607 | 4034 |
3608 if (!CanSetCallback(name)) { | 4035 if (!CanSetCallback(name)) { |
3609 return heap->undefined_value(); | 4036 return heap->undefined_value(); |
3610 } | 4037 } |
3611 | 4038 |
3612 uint32_t index = 0; | 4039 uint32_t index = 0; |
3613 bool is_element = name->AsArrayIndex(&index); | 4040 bool is_element = name->AsArrayIndex(&index); |
3614 | 4041 |
3615 if (is_element) { | 4042 if (is_element) { |
3616 switch (GetElementsKind()) { | 4043 switch (GetElementsKind()) { |
| 4044 case FAST_SMI_ONLY_ELEMENTS: |
3617 case FAST_ELEMENTS: | 4045 case FAST_ELEMENTS: |
3618 case FAST_DOUBLE_ELEMENTS: | 4046 case FAST_DOUBLE_ELEMENTS: |
3619 break; | 4047 break; |
3620 case EXTERNAL_PIXEL_ELEMENTS: | 4048 case EXTERNAL_PIXEL_ELEMENTS: |
3621 case EXTERNAL_BYTE_ELEMENTS: | 4049 case EXTERNAL_BYTE_ELEMENTS: |
3622 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 4050 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
3623 case EXTERNAL_SHORT_ELEMENTS: | 4051 case EXTERNAL_SHORT_ELEMENTS: |
3624 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 4052 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
3625 case EXTERNAL_INT_ELEMENTS: | 4053 case EXTERNAL_INT_ELEMENTS: |
3626 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 4054 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3793 if (!maybe_ok->ToObject(&ok)) return maybe_ok; | 4221 if (!maybe_ok->ToObject(&ok)) return maybe_ok; |
3794 } | 4222 } |
3795 } | 4223 } |
3796 return result; | 4224 return result; |
3797 } | 4225 } |
3798 | 4226 |
3799 MaybeObject* JSObject::DefineAccessor(String* name, | 4227 MaybeObject* JSObject::DefineAccessor(String* name, |
3800 bool is_getter, | 4228 bool is_getter, |
3801 Object* fun, | 4229 Object* fun, |
3802 PropertyAttributes attributes) { | 4230 PropertyAttributes attributes) { |
3803 ASSERT(fun->IsJSFunction() || fun->IsUndefined()); | 4231 ASSERT(fun->IsSpecFunction() || fun->IsUndefined()); |
3804 Isolate* isolate = GetIsolate(); | 4232 Isolate* isolate = GetIsolate(); |
3805 // Check access rights if needed. | 4233 // Check access rights if needed. |
3806 if (IsAccessCheckNeeded() && | 4234 if (IsAccessCheckNeeded() && |
3807 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { | 4235 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { |
3808 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); | 4236 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); |
3809 return isolate->heap()->undefined_value(); | 4237 return isolate->heap()->undefined_value(); |
3810 } | 4238 } |
3811 | 4239 |
3812 if (IsJSGlobalProxy()) { | 4240 if (IsJSGlobalProxy()) { |
3813 Object* proto = GetPrototype(); | 4241 Object* proto = GetPrototype(); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3856 } | 4284 } |
3857 | 4285 |
3858 uint32_t index = 0; | 4286 uint32_t index = 0; |
3859 bool is_element = name->AsArrayIndex(&index); | 4287 bool is_element = name->AsArrayIndex(&index); |
3860 | 4288 |
3861 if (is_element) { | 4289 if (is_element) { |
3862 if (IsJSArray()) return isolate->heap()->undefined_value(); | 4290 if (IsJSArray()) return isolate->heap()->undefined_value(); |
3863 | 4291 |
3864 // Accessors overwrite previous callbacks (cf. with getters/setters). | 4292 // Accessors overwrite previous callbacks (cf. with getters/setters). |
3865 switch (GetElementsKind()) { | 4293 switch (GetElementsKind()) { |
| 4294 case FAST_SMI_ONLY_ELEMENTS: |
3866 case FAST_ELEMENTS: | 4295 case FAST_ELEMENTS: |
3867 case FAST_DOUBLE_ELEMENTS: | 4296 case FAST_DOUBLE_ELEMENTS: |
3868 break; | 4297 break; |
3869 case EXTERNAL_PIXEL_ELEMENTS: | 4298 case EXTERNAL_PIXEL_ELEMENTS: |
3870 case EXTERNAL_BYTE_ELEMENTS: | 4299 case EXTERNAL_BYTE_ELEMENTS: |
3871 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 4300 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
3872 case EXTERNAL_SHORT_ELEMENTS: | 4301 case EXTERNAL_SHORT_ELEMENTS: |
3873 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 4302 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
3874 case EXTERNAL_INT_ELEMENTS: | 4303 case EXTERNAL_INT_ELEMENTS: |
3875 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 4304 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4079 } | 4508 } |
4080 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); | 4509 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); |
4081 return new_map; | 4510 return new_map; |
4082 } | 4511 } |
4083 | 4512 |
4084 | 4513 |
4085 MaybeObject* Map::UpdateCodeCache(String* name, Code* code) { | 4514 MaybeObject* Map::UpdateCodeCache(String* name, Code* code) { |
4086 // Allocate the code cache if not present. | 4515 // Allocate the code cache if not present. |
4087 if (code_cache()->IsFixedArray()) { | 4516 if (code_cache()->IsFixedArray()) { |
4088 Object* result; | 4517 Object* result; |
4089 { MaybeObject* maybe_result = code->heap()->AllocateCodeCache(); | 4518 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache(); |
4090 if (!maybe_result->ToObject(&result)) return maybe_result; | 4519 if (!maybe_result->ToObject(&result)) return maybe_result; |
4091 } | 4520 } |
4092 set_code_cache(result); | 4521 set_code_cache(result); |
4093 } | 4522 } |
4094 | 4523 |
4095 // Update the code cache. | 4524 // Update the code cache. |
4096 return CodeCache::cast(code_cache())->Update(name, code); | 4525 return CodeCache::cast(code_cache())->Update(name, code); |
4097 } | 4526 } |
4098 | 4527 |
4099 | 4528 |
(...skipping 21 matching lines...) Expand all Loading... |
4121 // RemoveFromCodeCache so the code cache must be there. | 4550 // RemoveFromCodeCache so the code cache must be there. |
4122 ASSERT(!code_cache()->IsFixedArray()); | 4551 ASSERT(!code_cache()->IsFixedArray()); |
4123 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); | 4552 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); |
4124 } | 4553 } |
4125 | 4554 |
4126 | 4555 |
4127 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { | 4556 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { |
4128 // Traverse the transition tree without using a stack. We do this by | 4557 // Traverse the transition tree without using a stack. We do this by |
4129 // reversing the pointers in the maps and descriptor arrays. | 4558 // reversing the pointers in the maps and descriptor arrays. |
4130 Map* current = this; | 4559 Map* current = this; |
4131 Map* meta_map = heap()->meta_map(); | 4560 Map* meta_map = GetHeap()->meta_map(); |
4132 Object** map_or_index_field = NULL; | 4561 Object** map_or_index_field = NULL; |
4133 while (current != meta_map) { | 4562 while (current != meta_map) { |
4134 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( | 4563 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( |
4135 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset)); | 4564 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset)); |
4136 if (!d->IsEmpty()) { | 4565 if (!d->IsEmpty()) { |
4137 FixedArray* contents = reinterpret_cast<FixedArray*>( | 4566 FixedArray* contents = reinterpret_cast<FixedArray*>( |
4138 d->get(DescriptorArray::kContentArrayIndex)); | 4567 d->get(DescriptorArray::kContentArrayIndex)); |
4139 map_or_index_field = RawField(contents, HeapObject::kMapOffset); | 4568 map_or_index_field = RawField(contents, HeapObject::kMapOffset); |
4140 Object* map_or_index = *map_or_index_field; | 4569 Object* map_or_index = *map_or_index_field; |
4141 bool map_done = true; // Controls a nested continue statement. | 4570 bool map_done = true; // Controls a nested continue statement. |
4142 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0; | 4571 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0; |
4143 i < contents->length(); | 4572 i < contents->length(); |
4144 i += 2) { | 4573 i += 2) { |
4145 PropertyDetails details(Smi::cast(contents->get(i + 1))); | 4574 PropertyDetails details(Smi::cast(contents->get(i + 1))); |
4146 if (details.IsTransition()) { | 4575 if (details.IsTransition()) { |
4147 // Found a map in the transition array. We record our progress in | 4576 // Found a map in the transition array. We record our progress in |
4148 // the transition array by recording the current map in the map field | 4577 // the transition array by recording the current map in the map field |
4149 // of the next map and recording the index in the transition array in | 4578 // of the next map and recording the index in the transition array in |
4150 // the map field of the array. | 4579 // the map field of the array. |
4151 Map* next = Map::cast(contents->get(i)); | 4580 Map* next = Map::cast(contents->get(i)); |
4152 next->set_map(current); | 4581 next->set_map_unsafe(current); |
4153 *map_or_index_field = Smi::FromInt(i + 2); | 4582 *map_or_index_field = Smi::FromInt(i + 2); |
4154 current = next; | 4583 current = next; |
4155 map_done = false; | 4584 map_done = false; |
4156 break; | 4585 break; |
4157 } | 4586 } |
4158 } | 4587 } |
4159 if (!map_done) continue; | 4588 if (!map_done) continue; |
4160 } else { | 4589 } else { |
4161 map_or_index_field = NULL; | 4590 map_or_index_field = NULL; |
4162 } | 4591 } |
4163 // That was the regular transitions, now for the prototype transitions. | 4592 // That was the regular transitions, now for the prototype transitions. |
4164 FixedArray* prototype_transitions = | 4593 FixedArray* prototype_transitions = |
4165 current->unchecked_prototype_transitions(); | 4594 current->unchecked_prototype_transitions(); |
4166 Object** proto_map_or_index_field = | 4595 Object** proto_map_or_index_field = |
4167 RawField(prototype_transitions, HeapObject::kMapOffset); | 4596 RawField(prototype_transitions, HeapObject::kMapOffset); |
4168 Object* map_or_index = *proto_map_or_index_field; | 4597 Object* map_or_index = *proto_map_or_index_field; |
4169 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; | 4598 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; |
4170 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start; | 4599 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start; |
4171 if (i < prototype_transitions->length()) { | 4600 if (i < prototype_transitions->length()) { |
4172 // Found a map in the prototype transition array. Record progress in | 4601 // Found a map in the prototype transition array. Record progress in |
4173 // an analogous way to the regular transitions array above. | 4602 // an analogous way to the regular transitions array above. |
4174 Object* perhaps_map = prototype_transitions->get(i); | 4603 Object* perhaps_map = prototype_transitions->get(i); |
4175 if (perhaps_map->IsMap()) { | 4604 if (perhaps_map->IsMap()) { |
4176 Map* next = Map::cast(perhaps_map); | 4605 Map* next = Map::cast(perhaps_map); |
4177 next->set_map(current); | 4606 next->set_map_unsafe(current); |
4178 *proto_map_or_index_field = | 4607 *proto_map_or_index_field = |
4179 Smi::FromInt(i + kProtoTransitionElementsPerEntry); | 4608 Smi::FromInt(i + kProtoTransitionElementsPerEntry); |
4180 current = next; | 4609 current = next; |
4181 continue; | 4610 continue; |
4182 } | 4611 } |
4183 } | 4612 } |
4184 *proto_map_or_index_field = heap()->fixed_array_map(); | 4613 *proto_map_or_index_field = GetHeap()->fixed_array_map(); |
4185 if (map_or_index_field != NULL) { | 4614 if (map_or_index_field != NULL) { |
4186 *map_or_index_field = heap()->fixed_array_map(); | 4615 *map_or_index_field = GetHeap()->fixed_array_map(); |
4187 } | 4616 } |
4188 | 4617 |
4189 // The callback expects a map to have a real map as its map, so we save | 4618 // The callback expects a map to have a real map as its map, so we save |
4190 // the map field, which is being used to track the traversal and put the | 4619 // the map field, which is being used to track the traversal and put the |
4191 // correct map (the meta_map) in place while we do the callback. | 4620 // correct map (the meta_map) in place while we do the callback. |
4192 Map* prev = current->map(); | 4621 Map* prev = current->map(); |
4193 current->set_map(meta_map); | 4622 current->set_map_unsafe(meta_map); |
4194 callback(current, data); | 4623 callback(current, data); |
4195 current = prev; | 4624 current = prev; |
4196 } | 4625 } |
4197 } | 4626 } |
4198 | 4627 |
4199 | 4628 |
4200 MaybeObject* CodeCache::Update(String* name, Code* code) { | 4629 MaybeObject* CodeCache::Update(String* name, Code* code) { |
4201 // The number of monomorphic stubs for normal load/store/call IC's can grow to | 4630 // The number of monomorphic stubs for normal load/store/call IC's can grow to |
4202 // a large number and therefore they need to go into a hash table. They are | 4631 // a large number and therefore they need to go into a hash table. They are |
4203 // used to load global properties from cells. | 4632 // used to load global properties from cells. |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4399 uint32_t HashForObject(Object* obj) { | 4828 uint32_t HashForObject(Object* obj) { |
4400 FixedArray* pair = FixedArray::cast(obj); | 4829 FixedArray* pair = FixedArray::cast(obj); |
4401 String* name = String::cast(pair->get(0)); | 4830 String* name = String::cast(pair->get(0)); |
4402 Code* code = Code::cast(pair->get(1)); | 4831 Code* code = Code::cast(pair->get(1)); |
4403 return NameFlagsHashHelper(name, code->flags()); | 4832 return NameFlagsHashHelper(name, code->flags()); |
4404 } | 4833 } |
4405 | 4834 |
4406 MUST_USE_RESULT MaybeObject* AsObject() { | 4835 MUST_USE_RESULT MaybeObject* AsObject() { |
4407 ASSERT(code_ != NULL); | 4836 ASSERT(code_ != NULL); |
4408 Object* obj; | 4837 Object* obj; |
4409 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2); | 4838 { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2); |
4410 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 4839 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
4411 } | 4840 } |
4412 FixedArray* pair = FixedArray::cast(obj); | 4841 FixedArray* pair = FixedArray::cast(obj); |
4413 pair->set(0, name_); | 4842 pair->set(0, name_); |
4414 pair->set(1, code_); | 4843 pair->set(1, code_); |
4415 return pair; | 4844 return pair; |
4416 } | 4845 } |
4417 | 4846 |
4418 private: | 4847 private: |
4419 String* name_; | 4848 String* name_; |
(...skipping 1568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5988 return CompareStringContentsPartial(isolate, | 6417 return CompareStringContentsPartial(isolate, |
5989 isolate->objects_string_compare_buffer_a(), rhs); | 6418 isolate->objects_string_compare_buffer_a(), rhs); |
5990 } | 6419 } |
5991 } | 6420 } |
5992 | 6421 |
5993 | 6422 |
5994 bool String::MarkAsUndetectable() { | 6423 bool String::MarkAsUndetectable() { |
5995 if (StringShape(this).IsSymbol()) return false; | 6424 if (StringShape(this).IsSymbol()) return false; |
5996 | 6425 |
5997 Map* map = this->map(); | 6426 Map* map = this->map(); |
5998 Heap* heap = map->heap(); | 6427 Heap* heap = GetHeap(); |
5999 if (map == heap->string_map()) { | 6428 if (map == heap->string_map()) { |
6000 this->set_map(heap->undetectable_string_map()); | 6429 this->set_map(heap->undetectable_string_map()); |
6001 return true; | 6430 return true; |
6002 } else if (map == heap->ascii_string_map()) { | 6431 } else if (map == heap->ascii_string_map()) { |
6003 this->set_map(heap->undetectable_ascii_string_map()); | 6432 this->set_map(heap->undetectable_ascii_string_map()); |
6004 return true; | 6433 return true; |
6005 } | 6434 } |
6006 // Rest cannot be marked as undetectable | 6435 // Rest cannot be marked as undetectable |
6007 return false; | 6436 return false; |
6008 } | 6437 } |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6191 | 6620 |
6192 | 6621 |
6193 void String::PrintOn(FILE* file) { | 6622 void String::PrintOn(FILE* file) { |
6194 int length = this->length(); | 6623 int length = this->length(); |
6195 for (int i = 0; i < length; i++) { | 6624 for (int i = 0; i < length; i++) { |
6196 fprintf(file, "%c", Get(i)); | 6625 fprintf(file, "%c", Get(i)); |
6197 } | 6626 } |
6198 } | 6627 } |
6199 | 6628 |
6200 | 6629 |
| 6630 void Map::CreateOneBackPointer(Map* target) { |
| 6631 #ifdef DEBUG |
| 6632 // Verify target. |
| 6633 Object* source_prototype = prototype(); |
| 6634 Object* target_prototype = target->prototype(); |
| 6635 ASSERT(source_prototype->IsJSReceiver() || |
| 6636 source_prototype->IsMap() || |
| 6637 source_prototype->IsNull()); |
| 6638 ASSERT(target_prototype->IsJSReceiver() || |
| 6639 target_prototype->IsNull()); |
| 6640 ASSERT(source_prototype->IsMap() || |
| 6641 source_prototype == target_prototype); |
| 6642 #endif |
| 6643 // Point target back to source. set_prototype() will not let us set |
| 6644 // the prototype to a map, as we do here. |
| 6645 *RawField(target, kPrototypeOffset) = this; |
| 6646 } |
| 6647 |
| 6648 |
6201 void Map::CreateBackPointers() { | 6649 void Map::CreateBackPointers() { |
6202 DescriptorArray* descriptors = instance_descriptors(); | 6650 DescriptorArray* descriptors = instance_descriptors(); |
6203 for (int i = 0; i < descriptors->number_of_descriptors(); i++) { | 6651 for (int i = 0; i < descriptors->number_of_descriptors(); i++) { |
6204 if (descriptors->GetType(i) == MAP_TRANSITION || | 6652 if (descriptors->GetType(i) == MAP_TRANSITION || |
6205 descriptors->GetType(i) == ELEMENTS_TRANSITION || | 6653 descriptors->GetType(i) == ELEMENTS_TRANSITION || |
6206 descriptors->GetType(i) == CONSTANT_TRANSITION) { | 6654 descriptors->GetType(i) == CONSTANT_TRANSITION) { |
6207 // Get target. | 6655 Object* object = reinterpret_cast<Object*>(descriptors->GetValue(i)); |
6208 Map* target = Map::cast(descriptors->GetValue(i)); | 6656 if (object->IsMap()) { |
6209 #ifdef DEBUG | 6657 CreateOneBackPointer(reinterpret_cast<Map*>(object)); |
6210 // Verify target. | 6658 } else { |
6211 Object* source_prototype = prototype(); | 6659 ASSERT(object->IsFixedArray()); |
6212 Object* target_prototype = target->prototype(); | 6660 ASSERT(descriptors->GetType(i) == ELEMENTS_TRANSITION); |
6213 ASSERT(source_prototype->IsJSObject() || | 6661 FixedArray* array = reinterpret_cast<FixedArray*>(object); |
6214 source_prototype->IsMap() || | 6662 for (int i = 0; i < array->length(); ++i) { |
6215 source_prototype->IsNull()); | 6663 Map* target = reinterpret_cast<Map*>(array->get(i)); |
6216 ASSERT(target_prototype->IsJSObject() || | 6664 if (!target->IsUndefined()) { |
6217 target_prototype->IsNull()); | 6665 CreateOneBackPointer(target); |
6218 ASSERT(source_prototype->IsMap() || | 6666 } |
6219 source_prototype == target_prototype); | 6667 } |
6220 #endif | 6668 } |
6221 // Point target back to source. set_prototype() will not let us set | |
6222 // the prototype to a map, as we do here. | |
6223 *RawField(target, kPrototypeOffset) = this; | |
6224 } | 6669 } |
6225 } | 6670 } |
6226 } | 6671 } |
6227 | 6672 |
6228 | 6673 |
6229 void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { | 6674 void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { |
6230 // Live DescriptorArray objects will be marked, so we must use | 6675 // Live DescriptorArray objects will be marked, so we must use |
6231 // low-level accessors to get and modify their data. | 6676 // low-level accessors to get and modify their data. |
6232 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( | 6677 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( |
6233 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset)); | 6678 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset)); |
6234 if (d->IsEmpty()) return; | 6679 if (d->IsEmpty()) return; |
6235 Smi* NullDescriptorDetails = | 6680 Smi* NullDescriptorDetails = |
6236 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); | 6681 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); |
6237 FixedArray* contents = reinterpret_cast<FixedArray*>( | 6682 FixedArray* contents = reinterpret_cast<FixedArray*>( |
6238 d->get(DescriptorArray::kContentArrayIndex)); | 6683 d->get(DescriptorArray::kContentArrayIndex)); |
6239 ASSERT(contents->length() >= 2); | 6684 ASSERT(contents->length() >= 2); |
6240 for (int i = 0; i < contents->length(); i += 2) { | 6685 for (int i = 0; i < contents->length(); i += 2) { |
6241 // If the pair (value, details) is a map transition, | 6686 // If the pair (value, details) is a map transition, |
6242 // check if the target is live. If not, null the descriptor. | 6687 // check if the target is live. If not, null the descriptor. |
6243 // Also drop the back pointer for that map transition, so that this | 6688 // Also drop the back pointer for that map transition, so that this |
6244 // map is not reached again by following a back pointer from a | 6689 // map is not reached again by following a back pointer from a |
6245 // non-live object. | 6690 // non-live object. |
6246 PropertyDetails details(Smi::cast(contents->get(i + 1))); | 6691 PropertyDetails details(Smi::cast(contents->get(i + 1))); |
6247 if (details.type() == MAP_TRANSITION || | 6692 if (details.type() == MAP_TRANSITION || |
6248 details.type() == ELEMENTS_TRANSITION || | 6693 details.type() == ELEMENTS_TRANSITION || |
6249 details.type() == CONSTANT_TRANSITION) { | 6694 details.type() == CONSTANT_TRANSITION) { |
6250 Map* target = reinterpret_cast<Map*>(contents->get(i)); | 6695 Object* object = reinterpret_cast<Object*>(contents->get(i)); |
6251 ASSERT(target->IsHeapObject()); | 6696 if (object->IsMap()) { |
6252 if (!target->IsMarked()) { | 6697 Map* target = reinterpret_cast<Map*>(object); |
6253 ASSERT(target->IsMap()); | 6698 ASSERT(target->IsHeapObject()); |
6254 contents->set_unchecked(i + 1, NullDescriptorDetails); | 6699 MarkBit map_mark = Marking::MarkBitFrom(target); |
6255 contents->set_null_unchecked(heap, i); | 6700 if (!map_mark.Get()) { |
6256 ASSERT(target->prototype() == this || | 6701 ASSERT(target->IsMap()); |
6257 target->prototype() == real_prototype); | 6702 contents->set_unchecked(i + 1, NullDescriptorDetails); |
6258 // Getter prototype() is read-only, set_prototype() has side effects. | 6703 contents->set_null_unchecked(heap, i); |
6259 *RawField(target, Map::kPrototypeOffset) = real_prototype; | 6704 ASSERT(target->prototype() == this || |
| 6705 target->prototype() == real_prototype); |
| 6706 // Getter prototype() is read-only, set_prototype() has side effects. |
| 6707 *RawField(target, Map::kPrototypeOffset) = real_prototype; |
| 6708 } |
| 6709 } else { |
| 6710 ASSERT(object->IsFixedArray()); |
| 6711 ASSERT(details.type() == ELEMENTS_TRANSITION); |
| 6712 FixedArray* array = reinterpret_cast<FixedArray*>(contents->get(i)); |
| 6713 bool reachable_map_found = false; |
| 6714 for (int j = 0; j < array->length(); ++j) { |
| 6715 Map* target = reinterpret_cast<Map*>(array->get(j)); |
| 6716 ASSERT(target->IsHeapObject()); |
| 6717 MarkBit map_mark = Marking::MarkBitFrom(target); |
| 6718 if (!map_mark.Get()) { |
| 6719 ASSERT(target->IsMap()); |
| 6720 array->set_undefined(j); |
| 6721 ASSERT(target->prototype() == this || |
| 6722 target->prototype() == real_prototype); |
| 6723 // Getter prototype() is read-only, set_prototype() has side |
| 6724 // effects. |
| 6725 *RawField(target, Map::kPrototypeOffset) = real_prototype; |
| 6726 } else { |
| 6727 reachable_map_found = true; |
| 6728 } |
| 6729 } |
| 6730 // If no map was found, make sure the FixedArray also gets collected. |
| 6731 if (!reachable_map_found) { |
| 6732 contents->set_unchecked(i + 1, NullDescriptorDetails); |
| 6733 contents->set_null_unchecked(heap, i); |
| 6734 } |
6260 } | 6735 } |
6261 } | 6736 } |
6262 } | 6737 } |
6263 } | 6738 } |
6264 | 6739 |
6265 | 6740 |
6266 int Map::Hash() { | 6741 int Map::Hash() { |
6267 // For performance reasons we only hash the 3 most variable fields of a map: | 6742 // For performance reasons we only hash the 3 most variable fields of a map: |
6268 // constructor, prototype and bit_field2. | 6743 // constructor, prototype and bit_field2. |
6269 | 6744 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6355 // See ECMA-262 13.2.2. | 6830 // See ECMA-262 13.2.2. |
6356 if (!value->IsJSObject()) { | 6831 if (!value->IsJSObject()) { |
6357 // Copy the map so this does not affect unrelated functions. | 6832 // Copy the map so this does not affect unrelated functions. |
6358 // Remove map transitions because they point to maps with a | 6833 // Remove map transitions because they point to maps with a |
6359 // different prototype. | 6834 // different prototype. |
6360 Object* new_object; | 6835 Object* new_object; |
6361 { MaybeObject* maybe_new_map = map()->CopyDropTransitions(); | 6836 { MaybeObject* maybe_new_map = map()->CopyDropTransitions(); |
6362 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map; | 6837 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map; |
6363 } | 6838 } |
6364 Map* new_map = Map::cast(new_object); | 6839 Map* new_map = Map::cast(new_object); |
6365 Heap* heap = new_map->heap(); | 6840 Heap* heap = new_map->GetHeap(); |
6366 set_map(new_map); | 6841 set_map(new_map); |
6367 new_map->set_constructor(value); | 6842 new_map->set_constructor(value); |
6368 new_map->set_non_instance_prototype(true); | 6843 new_map->set_non_instance_prototype(true); |
6369 construct_prototype = | 6844 construct_prototype = |
6370 heap->isolate()->context()->global_context()-> | 6845 heap->isolate()->context()->global_context()-> |
6371 initial_object_prototype(); | 6846 initial_object_prototype(); |
6372 } else { | 6847 } else { |
6373 map()->set_non_instance_prototype(false); | 6848 map()->set_non_instance_prototype(false); |
6374 } | 6849 } |
6375 | 6850 |
(...skipping 10 matching lines...) Expand all Loading... |
6386 if (map() == no_prototype_map) { | 6861 if (map() == no_prototype_map) { |
6387 // Be idempotent. | 6862 // Be idempotent. |
6388 return this; | 6863 return this; |
6389 } | 6864 } |
6390 | 6865 |
6391 ASSERT(!shared()->strict_mode() || | 6866 ASSERT(!shared()->strict_mode() || |
6392 map() == global_context->strict_mode_function_map()); | 6867 map() == global_context->strict_mode_function_map()); |
6393 ASSERT(shared()->strict_mode() || map() == global_context->function_map()); | 6868 ASSERT(shared()->strict_mode() || map() == global_context->function_map()); |
6394 | 6869 |
6395 set_map(no_prototype_map); | 6870 set_map(no_prototype_map); |
6396 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value()); | 6871 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value()); |
6397 return this; | 6872 return this; |
6398 } | 6873 } |
6399 | 6874 |
6400 | 6875 |
6401 Object* JSFunction::SetInstanceClassName(String* name) { | 6876 Object* JSFunction::SetInstanceClassName(String* name) { |
6402 shared()->set_instance_class_name(name); | 6877 shared()->set_instance_class_name(name); |
6403 return this; | 6878 return this; |
6404 } | 6879 } |
6405 | 6880 |
6406 | 6881 |
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6694 if (Serializer::enabled()) return; | 7169 if (Serializer::enabled()) return; |
6695 | 7170 |
6696 if (map->unused_property_fields() == 0) return; | 7171 if (map->unused_property_fields() == 0) return; |
6697 | 7172 |
6698 // Nonzero counter is a leftover from the previous attempt interrupted | 7173 // Nonzero counter is a leftover from the previous attempt interrupted |
6699 // by GC, keep it. | 7174 // by GC, keep it. |
6700 if (construction_count() == 0) { | 7175 if (construction_count() == 0) { |
6701 set_construction_count(kGenerousAllocationCount); | 7176 set_construction_count(kGenerousAllocationCount); |
6702 } | 7177 } |
6703 set_initial_map(map); | 7178 set_initial_map(map); |
6704 Builtins* builtins = map->heap()->isolate()->builtins(); | 7179 Builtins* builtins = map->GetHeap()->isolate()->builtins(); |
6705 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric), | 7180 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric), |
6706 construct_stub()); | 7181 construct_stub()); |
6707 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown)); | 7182 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown)); |
6708 } | 7183 } |
6709 | 7184 |
6710 | 7185 |
6711 // Called from GC, hence reinterpret_cast and unchecked accessors. | 7186 // Called from GC, hence reinterpret_cast and unchecked accessors. |
6712 void SharedFunctionInfo::DetachInitialMap() { | 7187 void SharedFunctionInfo::DetachInitialMap() { |
6713 Map* map = reinterpret_cast<Map*>(initial_map()); | 7188 Map* map = reinterpret_cast<Map*>(initial_map()); |
6714 | 7189 |
6715 // Make the map remember to restore the link if it survives the GC. | 7190 // Make the map remember to restore the link if it survives the GC. |
6716 map->set_bit_field2( | 7191 map->set_bit_field2( |
6717 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo)); | 7192 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo)); |
6718 | 7193 |
6719 // Undo state changes made by StartInobjectTracking (except the | 7194 // Undo state changes made by StartInobjectTracking (except the |
6720 // construction_count). This way if the initial map does not survive the GC | 7195 // construction_count). This way if the initial map does not survive the GC |
6721 // then StartInobjectTracking will be called again the next time the | 7196 // then StartInobjectTracking will be called again the next time the |
6722 // constructor is called. The countdown will continue and (possibly after | 7197 // constructor is called. The countdown will continue and (possibly after |
6723 // several more GCs) CompleteInobjectSlackTracking will eventually be called. | 7198 // several more GCs) CompleteInobjectSlackTracking will eventually be called. |
6724 set_initial_map(map->heap()->raw_unchecked_undefined_value()); | 7199 Heap* heap = map->GetHeap(); |
6725 Builtins* builtins = map->heap()->isolate()->builtins(); | 7200 set_initial_map(heap->raw_unchecked_undefined_value()); |
| 7201 Builtins* builtins = heap->isolate()->builtins(); |
6726 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), | 7202 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), |
6727 *RawField(this, kConstructStubOffset)); | 7203 *RawField(this, kConstructStubOffset)); |
6728 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); | 7204 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); |
6729 // It is safe to clear the flag: it will be set again if the map is live. | 7205 // It is safe to clear the flag: it will be set again if the map is live. |
6730 set_live_objects_may_exist(false); | 7206 set_live_objects_may_exist(false); |
6731 } | 7207 } |
6732 | 7208 |
6733 | 7209 |
6734 // Called from GC, hence reinterpret_cast and unchecked accessors. | 7210 // Called from GC, hence reinterpret_cast and unchecked accessors. |
6735 void SharedFunctionInfo::AttachInitialMap(Map* map) { | 7211 void SharedFunctionInfo::AttachInitialMap(Map* map) { |
6736 map->set_bit_field2( | 7212 map->set_bit_field2( |
6737 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo)); | 7213 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo)); |
6738 | 7214 |
6739 // Resume inobject slack tracking. | 7215 // Resume inobject slack tracking. |
6740 set_initial_map(map); | 7216 set_initial_map(map); |
6741 Builtins* builtins = map->heap()->isolate()->builtins(); | 7217 Builtins* builtins = map->GetHeap()->isolate()->builtins(); |
6742 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric), | 7218 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric), |
6743 *RawField(this, kConstructStubOffset)); | 7219 *RawField(this, kConstructStubOffset)); |
6744 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown)); | 7220 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown)); |
6745 // The map survived the gc, so there may be objects referencing it. | 7221 // The map survived the gc, so there may be objects referencing it. |
6746 set_live_objects_may_exist(true); | 7222 set_live_objects_may_exist(true); |
6747 } | 7223 } |
6748 | 7224 |
6749 | 7225 |
6750 static void GetMinInobjectSlack(Map* map, void* data) { | 7226 static void GetMinInobjectSlack(Map* map, void* data) { |
6751 int slack = map->unused_property_fields(); | 7227 int slack = map->unused_property_fields(); |
(...skipping 11 matching lines...) Expand all Loading... |
6763 | 7239 |
6764 // Visitor id might depend on the instance size, recalculate it. | 7240 // Visitor id might depend on the instance size, recalculate it. |
6765 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map)); | 7241 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map)); |
6766 } | 7242 } |
6767 | 7243 |
6768 | 7244 |
6769 void SharedFunctionInfo::CompleteInobjectSlackTracking() { | 7245 void SharedFunctionInfo::CompleteInobjectSlackTracking() { |
6770 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress()); | 7246 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress()); |
6771 Map* map = Map::cast(initial_map()); | 7247 Map* map = Map::cast(initial_map()); |
6772 | 7248 |
6773 Heap* heap = map->heap(); | 7249 Heap* heap = map->GetHeap(); |
6774 set_initial_map(heap->undefined_value()); | 7250 set_initial_map(heap->undefined_value()); |
6775 Builtins* builtins = heap->isolate()->builtins(); | 7251 Builtins* builtins = heap->isolate()->builtins(); |
6776 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), | 7252 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), |
6777 construct_stub()); | 7253 construct_stub()); |
6778 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); | 7254 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); |
6779 | 7255 |
6780 int slack = map->unused_property_fields(); | 7256 int slack = map->unused_property_fields(); |
6781 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack); | 7257 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack); |
6782 if (slack != 0) { | 7258 if (slack != 0) { |
6783 // Resize the initial map and all maps in its transition tree. | 7259 // Resize the initial map and all maps in its transition tree. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6826 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && | 7302 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && |
6827 rinfo->IsPatchedDebugBreakSlotSequence())); | 7303 rinfo->IsPatchedDebugBreakSlotSequence())); |
6828 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); | 7304 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address()); |
6829 Object* old_target = target; | 7305 Object* old_target = target; |
6830 VisitPointer(&target); | 7306 VisitPointer(&target); |
6831 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target. | 7307 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target. |
6832 } | 7308 } |
6833 | 7309 |
6834 | 7310 |
6835 void Code::InvalidateRelocation() { | 7311 void Code::InvalidateRelocation() { |
6836 set_relocation_info(heap()->empty_byte_array()); | 7312 set_relocation_info(GetHeap()->empty_byte_array()); |
6837 } | 7313 } |
6838 | 7314 |
6839 | 7315 |
6840 void Code::Relocate(intptr_t delta) { | 7316 void Code::Relocate(intptr_t delta) { |
6841 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) { | 7317 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) { |
6842 it.rinfo()->apply(delta); | 7318 it.rinfo()->apply(delta); |
6843 } | 7319 } |
6844 CPU::FlushICache(instruction_start(), instruction_size()); | 7320 CPU::FlushICache(instruction_start(), instruction_size()); |
6845 } | 7321 } |
6846 | 7322 |
(...skipping 13 matching lines...) Expand all Loading... |
6860 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | | 7336 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | |
6861 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) | | 7337 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) | |
6862 RelocInfo::kApplyMask; | 7338 RelocInfo::kApplyMask; |
6863 Assembler* origin = desc.origin; // Needed to find target_object on X64. | 7339 Assembler* origin = desc.origin; // Needed to find target_object on X64. |
6864 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { | 7340 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) { |
6865 RelocInfo::Mode mode = it.rinfo()->rmode(); | 7341 RelocInfo::Mode mode = it.rinfo()->rmode(); |
6866 if (mode == RelocInfo::EMBEDDED_OBJECT) { | 7342 if (mode == RelocInfo::EMBEDDED_OBJECT) { |
6867 Handle<Object> p = it.rinfo()->target_object_handle(origin); | 7343 Handle<Object> p = it.rinfo()->target_object_handle(origin); |
6868 it.rinfo()->set_target_object(*p); | 7344 it.rinfo()->set_target_object(*p); |
6869 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) { | 7345 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) { |
6870 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle(); | 7346 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle(); |
6871 it.rinfo()->set_target_cell(*cell); | 7347 it.rinfo()->set_target_cell(*cell); |
6872 } else if (RelocInfo::IsCodeTarget(mode)) { | 7348 } else if (RelocInfo::IsCodeTarget(mode)) { |
6873 // rewrite code handles in inline cache targets to direct | 7349 // rewrite code handles in inline cache targets to direct |
6874 // pointers to the first instruction in the code object | 7350 // pointers to the first instruction in the code object |
6875 Handle<Object> p = it.rinfo()->target_object_handle(origin); | 7351 Handle<Object> p = it.rinfo()->target_object_handle(origin); |
6876 Code* code = Code::cast(*p); | 7352 Code* code = Code::cast(*p); |
6877 it.rinfo()->set_target_address(code->instruction_start()); | 7353 it.rinfo()->set_target_address(code->instruction_start()); |
6878 } else { | 7354 } else { |
6879 it.rinfo()->apply(delta); | 7355 it.rinfo()->apply(delta); |
6880 } | 7356 } |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7263 for (int i = 0; i < source->Capacity(); ++i) { | 7739 for (int i = 0; i < source->Capacity(); ++i) { |
7264 Object* key = source->KeyAt(i); | 7740 Object* key = source->KeyAt(i); |
7265 if (key->IsNumber()) { | 7741 if (key->IsNumber()) { |
7266 uint32_t entry = static_cast<uint32_t>(key->Number()); | 7742 uint32_t entry = static_cast<uint32_t>(key->Number()); |
7267 destination->set(entry, source->ValueAt(i), mode); | 7743 destination->set(entry, source->ValueAt(i), mode); |
7268 } | 7744 } |
7269 } | 7745 } |
7270 } | 7746 } |
7271 | 7747 |
7272 | 7748 |
7273 MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, | 7749 MaybeObject* JSObject::SetFastElementsCapacityAndLength( |
7274 int length) { | 7750 int capacity, |
| 7751 int length, |
| 7752 SetFastElementsCapacityMode set_capacity_mode) { |
7275 Heap* heap = GetHeap(); | 7753 Heap* heap = GetHeap(); |
7276 // We should never end in here with a pixel or external array. | 7754 // We should never end in here with a pixel or external array. |
7277 ASSERT(!HasExternalArrayElements()); | 7755 ASSERT(!HasExternalArrayElements()); |
7278 | 7756 |
7279 // Allocate a new fast elements backing store. | 7757 // Allocate a new fast elements backing store. |
7280 FixedArray* new_elements = NULL; | 7758 FixedArray* new_elements = NULL; |
7281 { Object* object; | 7759 { Object* object; |
7282 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity); | 7760 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity); |
7283 if (!maybe->ToObject(&object)) return maybe; | 7761 if (!maybe->ToObject(&object)) return maybe; |
7284 new_elements = FixedArray::cast(object); | 7762 new_elements = FixedArray::cast(object); |
7285 } | 7763 } |
7286 | 7764 |
7287 // Find the new map to use for this object if there is a map change. | 7765 // Find the new map to use for this object if there is a map change. |
7288 Map* new_map = NULL; | 7766 Map* new_map = NULL; |
7289 if (elements()->map() != heap->non_strict_arguments_elements_map()) { | 7767 if (elements()->map() != heap->non_strict_arguments_elements_map()) { |
7290 Object* object; | 7768 Object* object; |
7291 MaybeObject* maybe = map()->GetFastElementsMap(); | 7769 bool has_fast_smi_only_elements = |
| 7770 FLAG_smi_only_arrays && |
| 7771 (set_capacity_mode == kAllowSmiOnlyElements) && |
| 7772 (elements()->map()->has_fast_smi_only_elements() || |
| 7773 elements() == heap->empty_fixed_array()); |
| 7774 ElementsKind elements_kind = has_fast_smi_only_elements |
| 7775 ? FAST_SMI_ONLY_ELEMENTS |
| 7776 : FAST_ELEMENTS; |
| 7777 MaybeObject* maybe = GetElementsTransitionMap(elements_kind); |
7292 if (!maybe->ToObject(&object)) return maybe; | 7778 if (!maybe->ToObject(&object)) return maybe; |
7293 new_map = Map::cast(object); | 7779 new_map = Map::cast(object); |
7294 } | 7780 } |
7295 | 7781 |
7296 switch (GetElementsKind()) { | 7782 ElementsKind elements_kind = GetElementsKind(); |
| 7783 switch (elements_kind) { |
| 7784 case FAST_SMI_ONLY_ELEMENTS: |
7297 case FAST_ELEMENTS: { | 7785 case FAST_ELEMENTS: { |
7298 AssertNoAllocation no_gc; | 7786 AssertNoAllocation no_gc; |
7299 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc); | 7787 WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc)); |
7300 CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode); | 7788 CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode); |
7301 set_map(new_map); | 7789 set_map(new_map); |
7302 set_elements(new_elements); | 7790 set_elements(new_elements); |
7303 break; | 7791 break; |
7304 } | 7792 } |
7305 case DICTIONARY_ELEMENTS: { | 7793 case DICTIONARY_ELEMENTS: { |
7306 AssertNoAllocation no_gc; | 7794 AssertNoAllocation no_gc; |
7307 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc); | 7795 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc); |
7308 CopySlowElementsToFast(NumberDictionary::cast(elements()), | 7796 CopySlowElementsToFast(NumberDictionary::cast(elements()), |
7309 new_elements, | 7797 new_elements, |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7384 // We should never end in here with a pixel or external array. | 7872 // We should never end in here with a pixel or external array. |
7385 ASSERT(!HasExternalArrayElements()); | 7873 ASSERT(!HasExternalArrayElements()); |
7386 | 7874 |
7387 Object* obj; | 7875 Object* obj; |
7388 { MaybeObject* maybe_obj = | 7876 { MaybeObject* maybe_obj = |
7389 heap->AllocateUninitializedFixedDoubleArray(capacity); | 7877 heap->AllocateUninitializedFixedDoubleArray(capacity); |
7390 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 7878 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
7391 } | 7879 } |
7392 FixedDoubleArray* elems = FixedDoubleArray::cast(obj); | 7880 FixedDoubleArray* elems = FixedDoubleArray::cast(obj); |
7393 | 7881 |
7394 { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap(); | 7882 { MaybeObject* maybe_obj = |
| 7883 GetElementsTransitionMap(FAST_DOUBLE_ELEMENTS); |
7395 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 7884 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
7396 } | 7885 } |
7397 Map* new_map = Map::cast(obj); | 7886 Map* new_map = Map::cast(obj); |
7398 | 7887 |
7399 AssertNoAllocation no_gc; | 7888 AssertNoAllocation no_gc; |
7400 switch (GetElementsKind()) { | 7889 switch (GetElementsKind()) { |
| 7890 case FAST_SMI_ONLY_ELEMENTS: |
7401 case FAST_ELEMENTS: { | 7891 case FAST_ELEMENTS: { |
7402 elems->Initialize(FixedArray::cast(elements())); | 7892 elems->Initialize(FixedArray::cast(elements())); |
7403 break; | 7893 break; |
7404 } | 7894 } |
7405 case FAST_DOUBLE_ELEMENTS: { | 7895 case FAST_DOUBLE_ELEMENTS: { |
7406 elems->Initialize(FixedDoubleArray::cast(elements())); | 7896 elems->Initialize(FixedDoubleArray::cast(elements())); |
7407 break; | 7897 break; |
7408 } | 7898 } |
7409 case DICTIONARY_ELEMENTS: { | 7899 case DICTIONARY_ELEMENTS: { |
7410 elems->Initialize(NumberDictionary::cast(elements())); | 7900 elems->Initialize(NumberDictionary::cast(elements())); |
(...skipping 17 matching lines...) Expand all Loading... |
7428 } | 7918 } |
7429 | 7919 |
7430 | 7920 |
7431 MaybeObject* JSObject::SetSlowElements(Object* len) { | 7921 MaybeObject* JSObject::SetSlowElements(Object* len) { |
7432 // We should never end in here with a pixel or external array. | 7922 // We should never end in here with a pixel or external array. |
7433 ASSERT(!HasExternalArrayElements()); | 7923 ASSERT(!HasExternalArrayElements()); |
7434 | 7924 |
7435 uint32_t new_length = static_cast<uint32_t>(len->Number()); | 7925 uint32_t new_length = static_cast<uint32_t>(len->Number()); |
7436 | 7926 |
7437 switch (GetElementsKind()) { | 7927 switch (GetElementsKind()) { |
7438 case FAST_ELEMENTS: { | 7928 case FAST_SMI_ONLY_ELEMENTS: |
7439 case FAST_DOUBLE_ELEMENTS: | 7929 case FAST_ELEMENTS: |
| 7930 case FAST_DOUBLE_ELEMENTS: { |
7440 // Make sure we never try to shrink dense arrays into sparse arrays. | 7931 // Make sure we never try to shrink dense arrays into sparse arrays. |
7441 ASSERT(static_cast<uint32_t>( | 7932 ASSERT(static_cast<uint32_t>( |
7442 FixedArrayBase::cast(elements())->length()) <= new_length); | 7933 FixedArrayBase::cast(elements())->length()) <= new_length); |
7443 MaybeObject* result = NormalizeElements(); | 7934 MaybeObject* result = NormalizeElements(); |
7444 if (result->IsFailure()) return result; | 7935 if (result->IsFailure()) return result; |
7445 | 7936 |
7446 // Update length for JSArrays. | 7937 // Update length for JSArrays. |
7447 if (IsJSArray()) JSArray::cast(this)->set_length(len); | 7938 if (IsJSArray()) JSArray::cast(this)->set_length(len); |
7448 break; | 7939 break; |
7449 } | 7940 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7495 | 7986 |
7496 | 7987 |
7497 void JSArray::Expand(int required_size) { | 7988 void JSArray::Expand(int required_size) { |
7498 Handle<JSArray> self(this); | 7989 Handle<JSArray> self(this); |
7499 Handle<FixedArray> old_backing(FixedArray::cast(elements())); | 7990 Handle<FixedArray> old_backing(FixedArray::cast(elements())); |
7500 int old_size = old_backing->length(); | 7991 int old_size = old_backing->length(); |
7501 int new_size = required_size > old_size ? required_size : old_size; | 7992 int new_size = required_size > old_size ? required_size : old_size; |
7502 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size); | 7993 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size); |
7503 // Can't use this any more now because we may have had a GC! | 7994 // Can't use this any more now because we may have had a GC! |
7504 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i)); | 7995 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i)); |
7505 self->SetContent(*new_backing); | 7996 GetIsolate()->factory()->SetContent(self, new_backing); |
7506 } | 7997 } |
7507 | 7998 |
7508 | 7999 |
7509 static Failure* ArrayLengthRangeError(Heap* heap) { | 8000 static Failure* ArrayLengthRangeError(Heap* heap) { |
7510 HandleScope scope(heap->isolate()); | 8001 HandleScope scope(heap->isolate()); |
7511 return heap->isolate()->Throw( | 8002 return heap->isolate()->Throw( |
7512 *FACTORY->NewRangeError("invalid_array_length", | 8003 *FACTORY->NewRangeError("invalid_array_length", |
7513 HandleVector<Object>(NULL, 0))); | 8004 HandleVector<Object>(NULL, 0))); |
7514 } | 8005 } |
7515 | 8006 |
7516 | 8007 |
7517 MaybeObject* JSObject::SetElementsLength(Object* len) { | 8008 MaybeObject* JSObject::SetElementsLength(Object* len) { |
7518 // We should never end in here with a pixel or external array. | 8009 // We should never end in here with a pixel or external array. |
7519 ASSERT(AllowsSetElementsLength()); | 8010 ASSERT(AllowsSetElementsLength()); |
7520 | 8011 |
7521 MaybeObject* maybe_smi_length = len->ToSmi(); | 8012 MaybeObject* maybe_smi_length = len->ToSmi(); |
7522 Object* smi_length = Smi::FromInt(0); | 8013 Object* smi_length = Smi::FromInt(0); |
7523 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) { | 8014 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) { |
7524 const int value = Smi::cast(smi_length)->value(); | 8015 const int value = Smi::cast(smi_length)->value(); |
7525 if (value < 0) return ArrayLengthRangeError(GetHeap()); | 8016 if (value < 0) return ArrayLengthRangeError(GetHeap()); |
7526 ElementsKind elements_kind = GetElementsKind(); | 8017 ElementsKind elements_kind = GetElementsKind(); |
7527 switch (elements_kind) { | 8018 switch (elements_kind) { |
| 8019 case FAST_SMI_ONLY_ELEMENTS: |
7528 case FAST_ELEMENTS: | 8020 case FAST_ELEMENTS: |
7529 case FAST_DOUBLE_ELEMENTS: { | 8021 case FAST_DOUBLE_ELEMENTS: { |
7530 int old_capacity = FixedArrayBase::cast(elements())->length(); | 8022 int old_capacity = FixedArrayBase::cast(elements())->length(); |
7531 if (value <= old_capacity) { | 8023 if (value <= old_capacity) { |
7532 if (IsJSArray()) { | 8024 if (IsJSArray()) { |
7533 Object* obj; | 8025 Object* obj; |
7534 if (elements_kind == FAST_ELEMENTS) { | 8026 if (elements_kind == FAST_ELEMENTS || |
| 8027 elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
7535 MaybeObject* maybe_obj = EnsureWritableFastElements(); | 8028 MaybeObject* maybe_obj = EnsureWritableFastElements(); |
7536 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 8029 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
7537 } | 8030 } |
7538 if (2 * value <= old_capacity) { | 8031 if (2 * value <= old_capacity) { |
7539 // If more than half the elements won't be used, trim the array. | 8032 // If more than half the elements won't be used, trim the array. |
7540 if (value == 0) { | 8033 if (value == 0) { |
7541 initialize_elements(); | 8034 initialize_elements(); |
7542 } else { | 8035 } else { |
7543 Address filler_start; | 8036 Address filler_start; |
7544 int filler_size; | 8037 int filler_size; |
7545 if (GetElementsKind() == FAST_ELEMENTS) { | 8038 if (elements_kind == FAST_ELEMENTS || |
| 8039 elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
7546 FixedArray* fast_elements = FixedArray::cast(elements()); | 8040 FixedArray* fast_elements = FixedArray::cast(elements()); |
7547 fast_elements->set_length(value); | 8041 fast_elements->set_length(value); |
7548 filler_start = fast_elements->address() + | 8042 filler_start = fast_elements->address() + |
7549 FixedArray::OffsetOfElementAt(value); | 8043 FixedArray::OffsetOfElementAt(value); |
7550 filler_size = (old_capacity - value) * kPointerSize; | 8044 filler_size = (old_capacity - value) * kPointerSize; |
7551 } else { | 8045 } else { |
7552 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS); | 8046 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS); |
7553 FixedDoubleArray* fast_double_elements = | 8047 FixedDoubleArray* fast_double_elements = |
7554 FixedDoubleArray::cast(elements()); | 8048 FixedDoubleArray::cast(elements()); |
7555 fast_double_elements->set_length(value); | 8049 fast_double_elements->set_length(value); |
7556 filler_start = fast_double_elements->address() + | 8050 filler_start = fast_double_elements->address() + |
7557 FixedDoubleArray::OffsetOfElementAt(value); | 8051 FixedDoubleArray::OffsetOfElementAt(value); |
7558 filler_size = (old_capacity - value) * kDoubleSize; | 8052 filler_size = (old_capacity - value) * kDoubleSize; |
7559 } | 8053 } |
7560 GetHeap()->CreateFillerObjectAt(filler_start, filler_size); | 8054 GetHeap()->CreateFillerObjectAt(filler_start, filler_size); |
7561 } | 8055 } |
7562 } else { | 8056 } else { |
7563 // Otherwise, fill the unused tail with holes. | 8057 // Otherwise, fill the unused tail with holes. |
7564 int old_length = FastD2I(JSArray::cast(this)->length()->Number()); | 8058 int old_length = FastD2I(JSArray::cast(this)->length()->Number()); |
7565 if (GetElementsKind() == FAST_ELEMENTS) { | 8059 if (elements_kind == FAST_ELEMENTS || |
| 8060 elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
7566 FixedArray* fast_elements = FixedArray::cast(elements()); | 8061 FixedArray* fast_elements = FixedArray::cast(elements()); |
7567 for (int i = value; i < old_length; i++) { | 8062 for (int i = value; i < old_length; i++) { |
7568 fast_elements->set_the_hole(i); | 8063 fast_elements->set_the_hole(i); |
7569 } | 8064 } |
7570 } else { | 8065 } else { |
7571 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS); | 8066 ASSERT(elements_kind == FAST_DOUBLE_ELEMENTS); |
7572 FixedDoubleArray* fast_double_elements = | 8067 FixedDoubleArray* fast_double_elements = |
7573 FixedDoubleArray::cast(elements()); | 8068 FixedDoubleArray::cast(elements()); |
7574 for (int i = value; i < old_length; i++) { | 8069 for (int i = value; i < old_length; i++) { |
7575 fast_double_elements->set_the_hole(i); | 8070 fast_double_elements->set_the_hole(i); |
7576 } | 8071 } |
7577 } | 8072 } |
7578 } | 8073 } |
7579 JSArray::cast(this)->set_length(Smi::cast(smi_length)); | 8074 JSArray::cast(this)->set_length(Smi::cast(smi_length)); |
7580 } | 8075 } |
7581 return this; | 8076 return this; |
7582 } | 8077 } |
7583 int min = NewElementsCapacity(old_capacity); | 8078 int min = NewElementsCapacity(old_capacity); |
7584 int new_capacity = value > min ? value : min; | 8079 int new_capacity = value > min ? value : min; |
7585 if (!ShouldConvertToSlowElements(new_capacity)) { | 8080 if (!ShouldConvertToSlowElements(new_capacity)) { |
7586 MaybeObject* result; | 8081 MaybeObject* result; |
7587 if (GetElementsKind() == FAST_ELEMENTS) { | 8082 if (elements_kind == FAST_ELEMENTS || |
7588 result = SetFastElementsCapacityAndLength(new_capacity, value); | 8083 elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
| 8084 SetFastElementsCapacityMode set_capacity_mode = |
| 8085 elements_kind == FAST_SMI_ONLY_ELEMENTS |
| 8086 ? kAllowSmiOnlyElements |
| 8087 : kDontAllowSmiOnlyElements; |
| 8088 result = SetFastElementsCapacityAndLength(new_capacity, |
| 8089 value, |
| 8090 set_capacity_mode); |
7589 } else { | 8091 } else { |
7590 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS); | 8092 ASSERT(elements_kind == FAST_DOUBLE_ELEMENTS); |
7591 result = SetFastDoubleElementsCapacityAndLength(new_capacity, | 8093 result = SetFastDoubleElementsCapacityAndLength(new_capacity, |
7592 value); | 8094 value); |
7593 } | 8095 } |
7594 if (result->IsFailure()) return result; | 8096 if (result->IsFailure()) return result; |
7595 return this; | 8097 return this; |
7596 } | 8098 } |
7597 break; | 8099 break; |
7598 } | 8100 } |
7599 case DICTIONARY_ELEMENTS: { | 8101 case DICTIONARY_ELEMENTS: { |
7600 if (IsJSArray()) { | 8102 if (IsJSArray()) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7637 if (len->ToArrayIndex(&length)) { | 8139 if (len->ToArrayIndex(&length)) { |
7638 return SetSlowElements(len); | 8140 return SetSlowElements(len); |
7639 } else { | 8141 } else { |
7640 return ArrayLengthRangeError(GetHeap()); | 8142 return ArrayLengthRangeError(GetHeap()); |
7641 } | 8143 } |
7642 } | 8144 } |
7643 | 8145 |
7644 // len is not a number so make the array size one and | 8146 // len is not a number so make the array size one and |
7645 // set only element to len. | 8147 // set only element to len. |
7646 Object* obj; | 8148 Object* obj; |
7647 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1); | 8149 MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1); |
7648 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 8150 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
7649 } | |
7650 FixedArray::cast(obj)->set(0, len); | 8151 FixedArray::cast(obj)->set(0, len); |
| 8152 |
| 8153 maybe_obj = EnsureCanContainElements(&len, 1); |
| 8154 if (maybe_obj->IsFailure()) return maybe_obj; |
| 8155 |
7651 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); | 8156 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); |
7652 set_elements(FixedArray::cast(obj)); | 8157 set_elements(FixedArray::cast(obj)); |
7653 return this; | 8158 return this; |
7654 } | 8159 } |
7655 | 8160 |
7656 | 8161 |
7657 Object* Map::GetPrototypeTransition(Object* prototype) { | 8162 Object* Map::GetPrototypeTransition(Object* prototype) { |
7658 FixedArray* cache = prototype_transitions(); | 8163 FixedArray* cache = prototype_transitions(); |
7659 int number_of_transitions = NumberOfProtoTransitions(); | 8164 int number_of_transitions = NumberOfProtoTransitions(); |
7660 const int proto_offset = | 8165 const int proto_offset = |
(...skipping 25 matching lines...) Expand all Loading... |
7686 int capacity = (cache->length() - header) / step; | 8191 int capacity = (cache->length() - header) / step; |
7687 | 8192 |
7688 int transitions = NumberOfProtoTransitions() + 1; | 8193 int transitions = NumberOfProtoTransitions() + 1; |
7689 | 8194 |
7690 if (transitions > capacity) { | 8195 if (transitions > capacity) { |
7691 if (capacity > kMaxCachedPrototypeTransitions) return this; | 8196 if (capacity > kMaxCachedPrototypeTransitions) return this; |
7692 | 8197 |
7693 FixedArray* new_cache; | 8198 FixedArray* new_cache; |
7694 // Grow array by factor 2 over and above what we need. | 8199 // Grow array by factor 2 over and above what we need. |
7695 { MaybeObject* maybe_cache = | 8200 { MaybeObject* maybe_cache = |
7696 heap()->AllocateFixedArray(transitions * 2 * step + header); | 8201 GetHeap()->AllocateFixedArray(transitions * 2 * step + header); |
7697 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache; | 8202 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache; |
7698 } | 8203 } |
7699 | 8204 |
7700 for (int i = 0; i < capacity * step; i++) { | 8205 for (int i = 0; i < capacity * step; i++) { |
7701 new_cache->set(i + header, cache->get(i + header)); | 8206 new_cache->set(i + header, cache->get(i + header)); |
7702 } | 8207 } |
7703 cache = new_cache; | 8208 cache = new_cache; |
7704 set_prototype_transitions(cache); | 8209 set_prototype_transitions(cache); |
7705 } | 8210 } |
7706 | 8211 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7739 return heap->isolate()->Throw( | 8244 return heap->isolate()->Throw( |
7740 *FACTORY->NewTypeError("non_extensible_proto", | 8245 *FACTORY->NewTypeError("non_extensible_proto", |
7741 HandleVector<Object>(&handle, 1))); | 8246 HandleVector<Object>(&handle, 1))); |
7742 } | 8247 } |
7743 | 8248 |
7744 // Before we can set the prototype we need to be sure | 8249 // Before we can set the prototype we need to be sure |
7745 // prototype cycles are prevented. | 8250 // prototype cycles are prevented. |
7746 // It is sufficient to validate that the receiver is not in the new prototype | 8251 // It is sufficient to validate that the receiver is not in the new prototype |
7747 // chain. | 8252 // chain. |
7748 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) { | 8253 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) { |
7749 if (JSObject::cast(pt) == this) { | 8254 if (JSReceiver::cast(pt) == this) { |
7750 // Cycle detected. | 8255 // Cycle detected. |
7751 HandleScope scope(heap->isolate()); | 8256 HandleScope scope(heap->isolate()); |
7752 return heap->isolate()->Throw( | 8257 return heap->isolate()->Throw( |
7753 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0))); | 8258 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0))); |
7754 } | 8259 } |
7755 } | 8260 } |
7756 | 8261 |
7757 JSReceiver* real_receiver = this; | 8262 JSReceiver* real_receiver = this; |
7758 | 8263 |
7759 if (skip_hidden_prototypes) { | 8264 if (skip_hidden_prototypes) { |
7760 // Find the first object in the chain whose prototype object is not | 8265 // Find the first object in the chain whose prototype object is not |
7761 // hidden and set the new prototype on that object. | 8266 // hidden and set the new prototype on that object. |
7762 Object* current_proto = real_receiver->GetPrototype(); | 8267 Object* current_proto = real_receiver->GetPrototype(); |
7763 while (current_proto->IsJSObject() && | 8268 while (current_proto->IsJSObject() && |
7764 JSObject::cast(current_proto)->map()->is_hidden_prototype()) { | 8269 JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) { |
7765 real_receiver = JSObject::cast(current_proto); | 8270 real_receiver = JSReceiver::cast(current_proto); |
7766 current_proto = current_proto->GetPrototype(); | 8271 current_proto = current_proto->GetPrototype(); |
7767 } | 8272 } |
7768 } | 8273 } |
7769 | 8274 |
7770 // Set the new prototype of the object. | 8275 // Set the new prototype of the object. |
7771 Map* map = real_receiver->map(); | 8276 Map* map = real_receiver->map(); |
7772 | 8277 |
7773 // Nothing to do if prototype is already set. | 8278 // Nothing to do if prototype is already set. |
7774 if (map->prototype() == value) return value; | 8279 if (map->prototype() == value) return value; |
7775 | 8280 |
(...skipping 12 matching lines...) Expand all Loading... |
7788 } | 8293 } |
7789 ASSERT(Map::cast(new_map)->prototype() == value); | 8294 ASSERT(Map::cast(new_map)->prototype() == value); |
7790 real_receiver->set_map(Map::cast(new_map)); | 8295 real_receiver->set_map(Map::cast(new_map)); |
7791 | 8296 |
7792 heap->ClearInstanceofCache(); | 8297 heap->ClearInstanceofCache(); |
7793 ASSERT(size == Size()); | 8298 ASSERT(size == Size()); |
7794 return value; | 8299 return value; |
7795 } | 8300 } |
7796 | 8301 |
7797 | 8302 |
| 8303 MaybeObject* JSObject::EnsureCanContainElements(Arguments* args, |
| 8304 uint32_t first_arg, |
| 8305 uint32_t arg_count) { |
| 8306 return EnsureCanContainElements(args->arguments() - first_arg, arg_count); |
| 8307 } |
| 8308 |
| 8309 |
7798 bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) { | 8310 bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) { |
7799 switch (GetElementsKind()) { | 8311 switch (GetElementsKind()) { |
| 8312 case FAST_SMI_ONLY_ELEMENTS: |
7800 case FAST_ELEMENTS: { | 8313 case FAST_ELEMENTS: { |
7801 uint32_t length = IsJSArray() ? | 8314 uint32_t length = IsJSArray() ? |
7802 static_cast<uint32_t> | 8315 static_cast<uint32_t> |
7803 (Smi::cast(JSArray::cast(this)->length())->value()) : | 8316 (Smi::cast(JSArray::cast(this)->length())->value()) : |
7804 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 8317 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
7805 if ((index < length) && | 8318 if ((index < length) && |
7806 !FixedArray::cast(elements())->get(index)->IsTheHole()) { | 8319 !FixedArray::cast(elements())->get(index)->IsTheHole()) { |
7807 return true; | 8320 return true; |
7808 } | 8321 } |
7809 break; | 8322 break; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7850 case NON_STRICT_ARGUMENTS_ELEMENTS: | 8363 case NON_STRICT_ARGUMENTS_ELEMENTS: |
7851 UNREACHABLE(); | 8364 UNREACHABLE(); |
7852 break; | 8365 break; |
7853 } | 8366 } |
7854 | 8367 |
7855 // Handle [] on String objects. | 8368 // Handle [] on String objects. |
7856 if (this->IsStringObjectWithCharacterAt(index)) return true; | 8369 if (this->IsStringObjectWithCharacterAt(index)) return true; |
7857 | 8370 |
7858 Object* pt = GetPrototype(); | 8371 Object* pt = GetPrototype(); |
7859 if (pt->IsNull()) return false; | 8372 if (pt->IsNull()) return false; |
| 8373 if (pt->IsJSProxy()) { |
| 8374 // We need to follow the spec and simulate a call to [[GetOwnProperty]]. |
| 8375 return JSProxy::cast(pt)->GetElementAttributeWithHandler( |
| 8376 receiver, index) != ABSENT; |
| 8377 } |
7860 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); | 8378 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); |
7861 } | 8379 } |
7862 | 8380 |
7863 | 8381 |
7864 bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) { | 8382 bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) { |
7865 Isolate* isolate = GetIsolate(); | 8383 Isolate* isolate = GetIsolate(); |
7866 // Make sure that the top context does not change when doing | 8384 // Make sure that the top context does not change when doing |
7867 // callbacks or interceptor calls. | 8385 // callbacks or interceptor calls. |
7868 AssertNoContextChange ncc; | 8386 AssertNoContextChange ncc; |
7869 HandleScope scope(isolate); | 8387 HandleScope scope(isolate); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7926 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT | 8444 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT |
7927 : UNDEFINED_ELEMENT; | 8445 : UNDEFINED_ELEMENT; |
7928 } | 8446 } |
7929 | 8447 |
7930 // Handle [] on String objects. | 8448 // Handle [] on String objects. |
7931 if (this->IsStringObjectWithCharacterAt(index)) { | 8449 if (this->IsStringObjectWithCharacterAt(index)) { |
7932 return STRING_CHARACTER_ELEMENT; | 8450 return STRING_CHARACTER_ELEMENT; |
7933 } | 8451 } |
7934 | 8452 |
7935 switch (GetElementsKind()) { | 8453 switch (GetElementsKind()) { |
| 8454 case FAST_SMI_ONLY_ELEMENTS: |
7936 case FAST_ELEMENTS: { | 8455 case FAST_ELEMENTS: { |
7937 uint32_t length = IsJSArray() ? | 8456 uint32_t length = IsJSArray() ? |
7938 static_cast<uint32_t> | 8457 static_cast<uint32_t> |
7939 (Smi::cast(JSArray::cast(this)->length())->value()) : | 8458 (Smi::cast(JSArray::cast(this)->length())->value()) : |
7940 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 8459 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
7941 if ((index < length) && | 8460 if ((index < length) && |
7942 !FixedArray::cast(elements())->get(index)->IsTheHole()) { | 8461 !FixedArray::cast(elements())->get(index)->IsTheHole()) { |
7943 return FAST_ELEMENT; | 8462 return FAST_ELEMENT; |
7944 } | 8463 } |
7945 break; | 8464 break; |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8040 } | 8559 } |
8041 } | 8560 } |
8042 | 8561 |
8043 // Check for lookup interceptor | 8562 // Check for lookup interceptor |
8044 if (HasIndexedInterceptor()) { | 8563 if (HasIndexedInterceptor()) { |
8045 return HasElementWithInterceptor(receiver, index); | 8564 return HasElementWithInterceptor(receiver, index); |
8046 } | 8565 } |
8047 | 8566 |
8048 ElementsKind kind = GetElementsKind(); | 8567 ElementsKind kind = GetElementsKind(); |
8049 switch (kind) { | 8568 switch (kind) { |
| 8569 case FAST_SMI_ONLY_ELEMENTS: |
8050 case FAST_ELEMENTS: { | 8570 case FAST_ELEMENTS: { |
8051 uint32_t length = IsJSArray() ? | 8571 uint32_t length = IsJSArray() ? |
8052 static_cast<uint32_t> | 8572 static_cast<uint32_t> |
8053 (Smi::cast(JSArray::cast(this)->length())->value()) : | 8573 (Smi::cast(JSArray::cast(this)->length())->value()) : |
8054 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 8574 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
8055 if ((index < length) && | 8575 if ((index < length) && |
8056 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; | 8576 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; |
8057 break; | 8577 break; |
8058 } | 8578 } |
8059 case FAST_DOUBLE_ELEMENTS: { | 8579 case FAST_DOUBLE_ELEMENTS: { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8106 if (HasElementInElements(arguments, kind, index)) return true; | 8626 if (HasElementInElements(arguments, kind, index)) return true; |
8107 break; | 8627 break; |
8108 } | 8628 } |
8109 } | 8629 } |
8110 | 8630 |
8111 // Handle [] on String objects. | 8631 // Handle [] on String objects. |
8112 if (this->IsStringObjectWithCharacterAt(index)) return true; | 8632 if (this->IsStringObjectWithCharacterAt(index)) return true; |
8113 | 8633 |
8114 Object* pt = GetPrototype(); | 8634 Object* pt = GetPrototype(); |
8115 if (pt->IsNull()) return false; | 8635 if (pt->IsNull()) return false; |
| 8636 if (pt->IsJSProxy()) { |
| 8637 // We need to follow the spec and simulate a call to [[GetOwnProperty]]. |
| 8638 return JSProxy::cast(pt)->GetElementAttributeWithHandler( |
| 8639 receiver, index) != ABSENT; |
| 8640 } |
8116 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); | 8641 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); |
8117 } | 8642 } |
8118 | 8643 |
8119 | 8644 |
8120 MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index, | 8645 MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index, |
8121 Object* value, | 8646 Object* value, |
8122 StrictModeFlag strict_mode, | 8647 StrictModeFlag strict_mode, |
8123 bool check_prototype) { | 8648 bool check_prototype) { |
8124 Isolate* isolate = GetIsolate(); | 8649 Isolate* isolate = GetIsolate(); |
8125 // Make sure that the top context does not change when doing | 8650 // Make sure that the top context does not change when doing |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8182 result = call_fun(v8::Utils::ToLocal(key), info); | 8707 result = call_fun(v8::Utils::ToLocal(key), info); |
8183 } | 8708 } |
8184 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 8709 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
8185 if (result.IsEmpty()) return isolate->heap()->undefined_value(); | 8710 if (result.IsEmpty()) return isolate->heap()->undefined_value(); |
8186 return *v8::Utils::OpenHandle(*result); | 8711 return *v8::Utils::OpenHandle(*result); |
8187 } | 8712 } |
8188 | 8713 |
8189 // __defineGetter__ callback | 8714 // __defineGetter__ callback |
8190 if (structure->IsFixedArray()) { | 8715 if (structure->IsFixedArray()) { |
8191 Object* getter = FixedArray::cast(structure)->get(kGetterIndex); | 8716 Object* getter = FixedArray::cast(structure)->get(kGetterIndex); |
8192 if (getter->IsJSFunction()) { | 8717 if (getter->IsSpecFunction()) { |
8193 return Object::GetPropertyWithDefinedGetter(receiver, | 8718 // TODO(rossberg): nicer would be to cast to some JSCallable here... |
8194 JSFunction::cast(getter)); | 8719 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter)); |
8195 } | 8720 } |
8196 // Getter is not a function. | 8721 // Getter is not a function. |
8197 return isolate->heap()->undefined_value(); | 8722 return isolate->heap()->undefined_value(); |
8198 } | 8723 } |
8199 | 8724 |
8200 UNREACHABLE(); | 8725 UNREACHABLE(); |
8201 return NULL; | 8726 return NULL; |
8202 } | 8727 } |
8203 | 8728 |
8204 | 8729 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8239 call_fun(v8::Utils::ToLocal(key), | 8764 call_fun(v8::Utils::ToLocal(key), |
8240 v8::Utils::ToLocal(value_handle), | 8765 v8::Utils::ToLocal(value_handle), |
8241 info); | 8766 info); |
8242 } | 8767 } |
8243 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 8768 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
8244 return *value_handle; | 8769 return *value_handle; |
8245 } | 8770 } |
8246 | 8771 |
8247 if (structure->IsFixedArray()) { | 8772 if (structure->IsFixedArray()) { |
8248 Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex)); | 8773 Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex)); |
8249 if (setter->IsJSFunction()) { | 8774 if (setter->IsSpecFunction()) { |
8250 return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value); | 8775 // TODO(rossberg): nicer would be to cast to some JSCallable here... |
| 8776 return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value); |
8251 } else { | 8777 } else { |
8252 if (strict_mode == kNonStrictMode) { | 8778 if (strict_mode == kNonStrictMode) { |
8253 return value; | 8779 return value; |
8254 } | 8780 } |
8255 Handle<Object> holder_handle(holder, isolate); | 8781 Handle<Object> holder_handle(holder, isolate); |
8256 Handle<Object> key(isolate->factory()->NewNumberFromUint(index)); | 8782 Handle<Object> key(isolate->factory()->NewNumberFromUint(index)); |
8257 Handle<Object> args[2] = { key, holder_handle }; | 8783 Handle<Object> args[2] = { key, holder_handle }; |
8258 return isolate->Throw( | 8784 return isolate->Throw( |
8259 *isolate->factory()->NewTypeError("no_setter_in_callback", | 8785 *isolate->factory()->NewTypeError("no_setter_in_callback", |
8260 HandleVector(args, 2))); | 8786 HandleVector(args, 2))); |
(...skipping 29 matching lines...) Expand all Loading... |
8290 } | 8816 } |
8291 | 8817 |
8292 | 8818 |
8293 // Adding n elements in fast case is O(n*n). | 8819 // Adding n elements in fast case is O(n*n). |
8294 // Note: revisit design to have dual undefined values to capture absent | 8820 // Note: revisit design to have dual undefined values to capture absent |
8295 // elements. | 8821 // elements. |
8296 MaybeObject* JSObject::SetFastElement(uint32_t index, | 8822 MaybeObject* JSObject::SetFastElement(uint32_t index, |
8297 Object* value, | 8823 Object* value, |
8298 StrictModeFlag strict_mode, | 8824 StrictModeFlag strict_mode, |
8299 bool check_prototype) { | 8825 bool check_prototype) { |
8300 ASSERT(HasFastElements() || HasFastArgumentsElements()); | 8826 ASSERT(HasFastTypeElements() || |
| 8827 HasFastArgumentsElements()); |
8301 | 8828 |
8302 FixedArray* backing_store = FixedArray::cast(elements()); | 8829 FixedArray* backing_store = FixedArray::cast(elements()); |
8303 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) { | 8830 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) { |
8304 backing_store = FixedArray::cast(backing_store->get(1)); | 8831 backing_store = FixedArray::cast(backing_store->get(1)); |
8305 } else { | 8832 } else { |
8306 Object* writable; | 8833 Object* writable; |
8307 MaybeObject* maybe = EnsureWritableFastElements(); | 8834 MaybeObject* maybe = EnsureWritableFastElements(); |
8308 if (!maybe->ToObject(&writable)) return maybe; | 8835 if (!maybe->ToObject(&writable)) return maybe; |
8309 backing_store = FixedArray::cast(writable); | 8836 backing_store = FixedArray::cast(writable); |
8310 } | 8837 } |
8311 uint32_t length = static_cast<uint32_t>(backing_store->length()); | 8838 uint32_t length = static_cast<uint32_t>(backing_store->length()); |
8312 | 8839 |
8313 if (check_prototype && | 8840 if (check_prototype && |
8314 (index >= length || backing_store->get(index)->IsTheHole())) { | 8841 (index >= length || backing_store->get(index)->IsTheHole())) { |
8315 bool found; | 8842 bool found; |
8316 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, | 8843 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, |
8317 value, | 8844 value, |
8318 &found, | 8845 &found, |
8319 strict_mode); | 8846 strict_mode); |
8320 if (found) return result; | 8847 if (found) return result; |
8321 } | 8848 } |
8322 | 8849 |
8323 // Check whether there is extra space in fixed array. | 8850 // Check whether there is extra space in fixed array. |
8324 if (index < length) { | 8851 if (index < length) { |
| 8852 if (HasFastSmiOnlyElements()) { |
| 8853 if (!value->IsSmi()) { |
| 8854 // If the value is a number, transition from smi-only to |
| 8855 // FastDoubleElements. |
| 8856 if (value->IsNumber()) { |
| 8857 MaybeObject* maybe = |
| 8858 SetFastDoubleElementsCapacityAndLength(length, length); |
| 8859 if (maybe->IsFailure()) return maybe; |
| 8860 FixedDoubleArray::cast(elements())->set(index, value->Number()); |
| 8861 return value; |
| 8862 } |
| 8863 // Value is not a number, transition to generic fast elements. |
| 8864 MaybeObject* maybe_new_map = GetElementsTransitionMap(FAST_ELEMENTS); |
| 8865 Map* new_map; |
| 8866 if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map; |
| 8867 set_map(new_map); |
| 8868 } |
| 8869 } |
8325 backing_store->set(index, value); | 8870 backing_store->set(index, value); |
8326 if (IsJSArray()) { | 8871 if (IsJSArray()) { |
8327 // Update the length of the array if needed. | 8872 // Update the length of the array if needed. |
8328 uint32_t array_length = 0; | 8873 uint32_t array_length = 0; |
8329 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); | 8874 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); |
8330 if (index >= array_length) { | 8875 if (index >= array_length) { |
8331 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); | 8876 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); |
8332 } | 8877 } |
8333 } | 8878 } |
8334 return value; | 8879 return value; |
8335 } | 8880 } |
8336 | 8881 |
8337 // Allow gap in fast case. | 8882 // Allow gap in fast case. |
8338 if ((index - length) < kMaxGap) { | 8883 if ((index - length) < kMaxGap) { |
8339 // Try allocating extra space. | 8884 // Try allocating extra space. |
8340 int new_capacity = NewElementsCapacity(index + 1); | 8885 int new_capacity = NewElementsCapacity(index + 1); |
8341 if (!ShouldConvertToSlowElements(new_capacity)) { | 8886 if (!ShouldConvertToSlowElements(new_capacity)) { |
8342 ASSERT(static_cast<uint32_t>(new_capacity) > index); | 8887 ASSERT(static_cast<uint32_t>(new_capacity) > index); |
8343 Object* new_elements; | 8888 Object* new_elements; |
| 8889 SetFastElementsCapacityMode set_capacity_mode = |
| 8890 value->IsSmi() && HasFastSmiOnlyElements() |
| 8891 ? kAllowSmiOnlyElements |
| 8892 : kDontAllowSmiOnlyElements; |
8344 MaybeObject* maybe = | 8893 MaybeObject* maybe = |
8345 SetFastElementsCapacityAndLength(new_capacity, index + 1); | 8894 SetFastElementsCapacityAndLength(new_capacity, |
| 8895 index + 1, |
| 8896 set_capacity_mode); |
8346 if (!maybe->ToObject(&new_elements)) return maybe; | 8897 if (!maybe->ToObject(&new_elements)) return maybe; |
8347 FixedArray::cast(new_elements)->set(index, value); | 8898 FixedArray::cast(new_elements)->set(index, value); |
8348 return value; | 8899 return value; |
8349 } | 8900 } |
8350 } | 8901 } |
8351 | 8902 |
8352 // Otherwise default to slow case. | 8903 // Otherwise default to slow case. |
8353 MaybeObject* result = NormalizeElements(); | 8904 MaybeObject* result = NormalizeElements(); |
8354 if (result->IsFailure()) return result; | 8905 if (result->IsFailure()) return result; |
8355 return SetDictionaryElement(index, value, strict_mode, check_prototype); | 8906 return SetDictionaryElement(index, value, strict_mode, check_prototype); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8441 // Attempt to put this object back in fast case. | 8992 // Attempt to put this object back in fast case. |
8442 if (ShouldConvertToFastElements()) { | 8993 if (ShouldConvertToFastElements()) { |
8443 uint32_t new_length = 0; | 8994 uint32_t new_length = 0; |
8444 if (IsJSArray()) { | 8995 if (IsJSArray()) { |
8445 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); | 8996 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); |
8446 } else { | 8997 } else { |
8447 new_length = dictionary->max_number_key() + 1; | 8998 new_length = dictionary->max_number_key() + 1; |
8448 } | 8999 } |
8449 MaybeObject* result = CanConvertToFastDoubleElements() | 9000 MaybeObject* result = CanConvertToFastDoubleElements() |
8450 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length) | 9001 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length) |
8451 : SetFastElementsCapacityAndLength(new_length, new_length); | 9002 : SetFastElementsCapacityAndLength(new_length, |
| 9003 new_length, |
| 9004 kDontAllowSmiOnlyElements); |
8452 if (result->IsFailure()) return result; | 9005 if (result->IsFailure()) return result; |
8453 #ifdef DEBUG | 9006 #ifdef DEBUG |
8454 if (FLAG_trace_normalization) { | 9007 if (FLAG_trace_normalization) { |
8455 PrintF("Object elements are fast case again:\n"); | 9008 PrintF("Object elements are fast case again:\n"); |
8456 Print(); | 9009 Print(); |
8457 } | 9010 } |
8458 #endif | 9011 #endif |
8459 } | 9012 } |
8460 return value; | 9013 return value; |
8461 } | 9014 } |
(...skipping 23 matching lines...) Expand all Loading... |
8485 | 9038 |
8486 // If the value object is not a heap number, switch to fast elements and try | 9039 // If the value object is not a heap number, switch to fast elements and try |
8487 // again. | 9040 // again. |
8488 bool value_is_smi = value->IsSmi(); | 9041 bool value_is_smi = value->IsSmi(); |
8489 if (!value->IsNumber()) { | 9042 if (!value->IsNumber()) { |
8490 Object* obj; | 9043 Object* obj; |
8491 uint32_t length = elms_length; | 9044 uint32_t length = elms_length; |
8492 if (IsJSArray()) { | 9045 if (IsJSArray()) { |
8493 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); | 9046 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); |
8494 } | 9047 } |
8495 MaybeObject* maybe_obj = | 9048 MaybeObject* maybe_obj = SetFastElementsCapacityAndLength( |
8496 SetFastElementsCapacityAndLength(elms_length, length); | 9049 elms_length, |
| 9050 length, |
| 9051 kDontAllowSmiOnlyElements); |
8497 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 9052 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
8498 return SetFastElement(index, value, strict_mode, check_prototype); | 9053 return SetFastElement(index, |
| 9054 value, |
| 9055 strict_mode, |
| 9056 check_prototype); |
8499 } | 9057 } |
8500 | 9058 |
8501 double double_value = value_is_smi | 9059 double double_value = value_is_smi |
8502 ? static_cast<double>(Smi::cast(value)->value()) | 9060 ? static_cast<double>(Smi::cast(value)->value()) |
8503 : HeapNumber::cast(value)->value(); | 9061 : HeapNumber::cast(value)->value(); |
8504 | 9062 |
8505 // Check whether there is extra space in the fixed array. | 9063 // Check whether there is extra space in the fixed array. |
8506 if (index < elms_length) { | 9064 if (index < elms_length) { |
8507 elms->set(index, double_value); | 9065 elms->set(index, double_value); |
8508 if (IsJSArray()) { | 9066 if (IsJSArray()) { |
(...skipping 30 matching lines...) Expand all Loading... |
8539 ASSERT(elements()->IsFixedDoubleArray()); | 9097 ASSERT(elements()->IsFixedDoubleArray()); |
8540 Object* obj; | 9098 Object* obj; |
8541 { MaybeObject* maybe_obj = NormalizeElements(); | 9099 { MaybeObject* maybe_obj = NormalizeElements(); |
8542 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 9100 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
8543 } | 9101 } |
8544 ASSERT(HasDictionaryElements()); | 9102 ASSERT(HasDictionaryElements()); |
8545 return SetElement(index, value, strict_mode, check_prototype); | 9103 return SetElement(index, value, strict_mode, check_prototype); |
8546 } | 9104 } |
8547 | 9105 |
8548 | 9106 |
| 9107 MaybeObject* JSReceiver::SetElement(uint32_t index, |
| 9108 Object* value, |
| 9109 StrictModeFlag strict_mode, |
| 9110 bool check_proto) { |
| 9111 return IsJSProxy() |
| 9112 ? JSProxy::cast(this)->SetElementWithHandler(index, value, strict_mode) |
| 9113 : JSObject::cast(this)->SetElement(index, value, strict_mode, check_proto) |
| 9114 ; |
| 9115 } |
| 9116 |
| 9117 |
8549 MaybeObject* JSObject::SetElement(uint32_t index, | 9118 MaybeObject* JSObject::SetElement(uint32_t index, |
8550 Object* value, | 9119 Object* value, |
8551 StrictModeFlag strict_mode, | 9120 StrictModeFlag strict_mode, |
8552 bool check_prototype) { | 9121 bool check_prototype) { |
8553 // Check access rights if needed. | 9122 // Check access rights if needed. |
8554 if (IsAccessCheckNeeded()) { | 9123 if (IsAccessCheckNeeded()) { |
8555 Heap* heap = GetHeap(); | 9124 Heap* heap = GetHeap(); |
8556 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { | 9125 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { |
8557 HandleScope scope(heap->isolate()); | 9126 HandleScope scope(heap->isolate()); |
8558 Handle<Object> value_handle(value); | 9127 Handle<Object> value_handle(value); |
(...skipping 26 matching lines...) Expand all Loading... |
8585 check_prototype); | 9154 check_prototype); |
8586 } | 9155 } |
8587 | 9156 |
8588 | 9157 |
8589 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, | 9158 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, |
8590 Object* value, | 9159 Object* value, |
8591 StrictModeFlag strict_mode, | 9160 StrictModeFlag strict_mode, |
8592 bool check_prototype) { | 9161 bool check_prototype) { |
8593 Isolate* isolate = GetIsolate(); | 9162 Isolate* isolate = GetIsolate(); |
8594 switch (GetElementsKind()) { | 9163 switch (GetElementsKind()) { |
| 9164 case FAST_SMI_ONLY_ELEMENTS: |
8595 case FAST_ELEMENTS: | 9165 case FAST_ELEMENTS: |
8596 return SetFastElement(index, value, strict_mode, check_prototype); | 9166 return SetFastElement(index, value, strict_mode, check_prototype); |
8597 case FAST_DOUBLE_ELEMENTS: | 9167 case FAST_DOUBLE_ELEMENTS: |
8598 return SetFastDoubleElement(index, value, strict_mode, check_prototype); | 9168 return SetFastDoubleElement(index, value, strict_mode, check_prototype); |
8599 case EXTERNAL_PIXEL_ELEMENTS: { | 9169 case EXTERNAL_PIXEL_ELEMENTS: { |
8600 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); | 9170 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); |
8601 return pixels->SetValue(index, value); | 9171 return pixels->SetValue(index, value); |
8602 } | 9172 } |
8603 case EXTERNAL_BYTE_ELEMENTS: { | 9173 case EXTERNAL_BYTE_ELEMENTS: { |
8604 ExternalByteArray* array = ExternalByteArray::cast(elements()); | 9174 ExternalByteArray* array = ExternalByteArray::cast(elements()); |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8747 backing_store_base = | 9317 backing_store_base = |
8748 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1)); | 9318 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1)); |
8749 backing_store = FixedArray::cast(backing_store_base); | 9319 backing_store = FixedArray::cast(backing_store_base); |
8750 if (backing_store->IsDictionary()) { | 9320 if (backing_store->IsDictionary()) { |
8751 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); | 9321 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); |
8752 *capacity = dictionary->Capacity(); | 9322 *capacity = dictionary->Capacity(); |
8753 *used = dictionary->NumberOfElements(); | 9323 *used = dictionary->NumberOfElements(); |
8754 break; | 9324 break; |
8755 } | 9325 } |
8756 // Fall through. | 9326 // Fall through. |
| 9327 case FAST_SMI_ONLY_ELEMENTS: |
8757 case FAST_ELEMENTS: | 9328 case FAST_ELEMENTS: |
8758 backing_store = FixedArray::cast(backing_store_base); | 9329 backing_store = FixedArray::cast(backing_store_base); |
8759 *capacity = backing_store->length(); | 9330 *capacity = backing_store->length(); |
8760 for (int i = 0; i < *capacity; ++i) { | 9331 for (int i = 0; i < *capacity; ++i) { |
8761 if (!backing_store->get(i)->IsTheHole()) ++(*used); | 9332 if (!backing_store->get(i)->IsTheHole()) ++(*used); |
8762 } | 9333 } |
8763 break; | 9334 break; |
8764 case DICTIONARY_ELEMENTS: { | 9335 case DICTIONARY_ELEMENTS: { |
8765 NumberDictionary* dictionary = | 9336 NumberDictionary* dictionary = |
8766 NumberDictionary::cast(FixedArray::cast(elements())); | 9337 NumberDictionary::cast(FixedArray::cast(elements())); |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9022 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { | 9593 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { |
9023 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); | 9594 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
9024 return false; | 9595 return false; |
9025 } | 9596 } |
9026 } | 9597 } |
9027 | 9598 |
9028 // Handle [] on String objects. | 9599 // Handle [] on String objects. |
9029 if (this->IsStringObjectWithCharacterAt(index)) return true; | 9600 if (this->IsStringObjectWithCharacterAt(index)) return true; |
9030 | 9601 |
9031 switch (GetElementsKind()) { | 9602 switch (GetElementsKind()) { |
| 9603 case FAST_SMI_ONLY_ELEMENTS: |
9032 case FAST_ELEMENTS: { | 9604 case FAST_ELEMENTS: { |
9033 uint32_t length = IsJSArray() ? | 9605 uint32_t length = IsJSArray() ? |
9034 static_cast<uint32_t>( | 9606 static_cast<uint32_t>( |
9035 Smi::cast(JSArray::cast(this)->length())->value()) : | 9607 Smi::cast(JSArray::cast(this)->length())->value()) : |
9036 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 9608 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
9037 return (index < length) && | 9609 return (index < length) && |
9038 !FixedArray::cast(elements())->get(index)->IsTheHole(); | 9610 !FixedArray::cast(elements())->get(index)->IsTheHole(); |
9039 } | 9611 } |
9040 case FAST_DOUBLE_ELEMENTS: { | 9612 case FAST_DOUBLE_ELEMENTS: { |
9041 uint32_t length = IsJSArray() ? | 9613 uint32_t length = IsJSArray() ? |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9261 } | 9833 } |
9262 // Compute the number of enumerable elements. | 9834 // Compute the number of enumerable elements. |
9263 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM)); | 9835 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM)); |
9264 } | 9836 } |
9265 | 9837 |
9266 | 9838 |
9267 int JSObject::GetLocalElementKeys(FixedArray* storage, | 9839 int JSObject::GetLocalElementKeys(FixedArray* storage, |
9268 PropertyAttributes filter) { | 9840 PropertyAttributes filter) { |
9269 int counter = 0; | 9841 int counter = 0; |
9270 switch (GetElementsKind()) { | 9842 switch (GetElementsKind()) { |
| 9843 case FAST_SMI_ONLY_ELEMENTS: |
9271 case FAST_ELEMENTS: { | 9844 case FAST_ELEMENTS: { |
9272 int length = IsJSArray() ? | 9845 int length = IsJSArray() ? |
9273 Smi::cast(JSArray::cast(this)->length())->value() : | 9846 Smi::cast(JSArray::cast(this)->length())->value() : |
9274 FixedArray::cast(elements())->length(); | 9847 FixedArray::cast(elements())->length(); |
9275 for (int i = 0; i < length; i++) { | 9848 for (int i = 0; i < length; i++) { |
9276 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) { | 9849 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) { |
9277 if (storage != NULL) { | 9850 if (storage != NULL) { |
9278 storage->set(counter, Smi::FromInt(i)); | 9851 storage->set(counter, Smi::FromInt(i)); |
9279 } | 9852 } |
9280 counter++; | 9853 counter++; |
(...skipping 845 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10126 result_double->set_value(static_cast<double>(result)); | 10699 result_double->set_value(static_cast<double>(result)); |
10127 return result_double; | 10700 return result_double; |
10128 } | 10701 } |
10129 | 10702 |
10130 | 10703 |
10131 // Collects all defined (non-hole) and non-undefined (array) elements at | 10704 // Collects all defined (non-hole) and non-undefined (array) elements at |
10132 // the start of the elements array. | 10705 // the start of the elements array. |
10133 // If the object is in dictionary mode, it is converted to fast elements | 10706 // If the object is in dictionary mode, it is converted to fast elements |
10134 // mode. | 10707 // mode. |
10135 MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { | 10708 MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { |
10136 ASSERT(!HasExternalArrayElements()); | |
10137 | |
10138 Heap* heap = GetHeap(); | 10709 Heap* heap = GetHeap(); |
10139 | 10710 |
10140 if (HasDictionaryElements()) { | 10711 if (HasDictionaryElements()) { |
10141 // Convert to fast elements containing only the existing properties. | 10712 // Convert to fast elements containing only the existing properties. |
10142 // Ordering is irrelevant, since we are going to sort anyway. | 10713 // Ordering is irrelevant, since we are going to sort anyway. |
10143 NumberDictionary* dict = element_dictionary(); | 10714 NumberDictionary* dict = element_dictionary(); |
10144 if (IsJSArray() || dict->requires_slow_elements() || | 10715 if (IsJSArray() || dict->requires_slow_elements() || |
10145 dict->max_number_key() >= limit) { | 10716 dict->max_number_key() >= limit) { |
10146 return PrepareSlowElementsForSort(limit); | 10717 return PrepareSlowElementsForSort(limit); |
10147 } | 10718 } |
10148 // Convert to fast elements. | 10719 // Convert to fast elements. |
10149 | 10720 |
10150 Object* obj; | 10721 Object* obj; |
10151 { MaybeObject* maybe_obj = map()->GetFastElementsMap(); | 10722 { MaybeObject* maybe_obj = GetElementsTransitionMap(FAST_ELEMENTS); |
10152 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 10723 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
10153 } | 10724 } |
10154 Map* new_map = Map::cast(obj); | 10725 Map* new_map = Map::cast(obj); |
10155 | 10726 |
10156 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED; | 10727 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED; |
10157 Object* new_array; | 10728 Object* new_array; |
10158 { MaybeObject* maybe_new_array = | 10729 { MaybeObject* maybe_new_array = |
10159 heap->AllocateFixedArray(dict->NumberOfElements(), tenure); | 10730 heap->AllocateFixedArray(dict->NumberOfElements(), tenure); |
10160 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array; | 10731 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array; |
10161 } | 10732 } |
10162 FixedArray* fast_elements = FixedArray::cast(new_array); | 10733 FixedArray* fast_elements = FixedArray::cast(new_array); |
10163 dict->CopyValuesTo(fast_elements); | 10734 dict->CopyValuesTo(fast_elements); |
10164 | 10735 |
10165 set_map(new_map); | 10736 set_map(new_map); |
10166 set_elements(fast_elements); | 10737 set_elements(fast_elements); |
| 10738 } else if (HasExternalArrayElements()) { |
| 10739 // External arrays cannot have holes or undefined elements. |
| 10740 return Smi::FromInt(ExternalArray::cast(elements())->length()); |
10167 } else if (!HasFastDoubleElements()) { | 10741 } else if (!HasFastDoubleElements()) { |
10168 Object* obj; | 10742 Object* obj; |
10169 { MaybeObject* maybe_obj = EnsureWritableFastElements(); | 10743 { MaybeObject* maybe_obj = EnsureWritableFastElements(); |
10170 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 10744 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
10171 } | 10745 } |
10172 } | 10746 } |
10173 ASSERT(HasFastElements() || HasFastDoubleElements()); | 10747 ASSERT(HasFastTypeElements() || HasFastDoubleElements()); |
10174 | 10748 |
10175 // Collect holes at the end, undefined before that and the rest at the | 10749 // Collect holes at the end, undefined before that and the rest at the |
10176 // start, and return the number of non-hole, non-undefined values. | 10750 // start, and return the number of non-hole, non-undefined values. |
10177 | 10751 |
10178 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements()); | 10752 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements()); |
10179 uint32_t elements_length = static_cast<uint32_t>(elements_base->length()); | 10753 uint32_t elements_length = static_cast<uint32_t>(elements_base->length()); |
10180 if (limit > elements_length) { | 10754 if (limit > elements_length) { |
10181 limit = elements_length ; | 10755 limit = elements_length ; |
10182 } | 10756 } |
10183 if (limit == 0) { | 10757 if (limit == 0) { |
(...skipping 1103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11287 ASSERT(obj->IsJSObject()); | 11861 ASSERT(obj->IsJSObject()); |
11288 | 11862 |
11289 descriptors->SetNextEnumerationIndex(NextEnumerationIndex()); | 11863 descriptors->SetNextEnumerationIndex(NextEnumerationIndex()); |
11290 // Check that it really works. | 11864 // Check that it really works. |
11291 ASSERT(obj->HasFastProperties()); | 11865 ASSERT(obj->HasFastProperties()); |
11292 | 11866 |
11293 return obj; | 11867 return obj; |
11294 } | 11868 } |
11295 | 11869 |
11296 | 11870 |
11297 Object* ObjectHashTable::Lookup(JSObject* key) { | 11871 Object* ObjectHashTable::Lookup(JSReceiver* key) { |
11298 // If the object does not have an identity hash, it was never used as a key. | 11872 // If the object does not have an identity hash, it was never used as a key. |
11299 MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::OMIT_CREATION); | 11873 MaybeObject* maybe_hash = key->GetIdentityHash(OMIT_CREATION); |
11300 if (maybe_hash->IsFailure()) return GetHeap()->undefined_value(); | 11874 if (maybe_hash->IsFailure()) return GetHeap()->undefined_value(); |
11301 int entry = FindEntry(key); | 11875 int entry = FindEntry(key); |
11302 if (entry == kNotFound) return GetHeap()->undefined_value(); | 11876 if (entry == kNotFound) return GetHeap()->undefined_value(); |
11303 return get(EntryToIndex(entry) + 1); | 11877 return get(EntryToIndex(entry) + 1); |
11304 } | 11878 } |
11305 | 11879 |
11306 | 11880 |
11307 MaybeObject* ObjectHashTable::Put(JSObject* key, Object* value) { | 11881 MaybeObject* ObjectHashTable::Put(JSReceiver* key, Object* value) { |
11308 // Make sure the key object has an identity hash code. | 11882 // Make sure the key object has an identity hash code. |
11309 int hash; | 11883 int hash; |
11310 { MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::ALLOW_CREATION); | 11884 { MaybeObject* maybe_hash = key->GetIdentityHash(ALLOW_CREATION); |
11311 if (maybe_hash->IsFailure()) return maybe_hash; | 11885 if (maybe_hash->IsFailure()) return maybe_hash; |
11312 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value(); | 11886 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value(); |
11313 } | 11887 } |
11314 int entry = FindEntry(key); | 11888 int entry = FindEntry(key); |
11315 | 11889 |
11316 // Check whether to perform removal operation. | 11890 // Check whether to perform removal operation. |
11317 if (value->IsUndefined()) { | 11891 if (value->IsUndefined()) { |
11318 if (entry == kNotFound) return this; | 11892 if (entry == kNotFound) return this; |
11319 RemoveEntry(entry); | 11893 RemoveEntry(entry); |
11320 return Shrink(key); | 11894 return Shrink(key); |
11321 } | 11895 } |
11322 | 11896 |
11323 // Key is already in table, just overwrite value. | 11897 // Key is already in table, just overwrite value. |
11324 if (entry != kNotFound) { | 11898 if (entry != kNotFound) { |
11325 set(EntryToIndex(entry) + 1, value); | 11899 set(EntryToIndex(entry) + 1, value); |
11326 return this; | 11900 return this; |
11327 } | 11901 } |
11328 | 11902 |
11329 // Check whether the hash table should be extended. | 11903 // Check whether the hash table should be extended. |
11330 Object* obj; | 11904 Object* obj; |
11331 { MaybeObject* maybe_obj = EnsureCapacity(1, key); | 11905 { MaybeObject* maybe_obj = EnsureCapacity(1, key); |
11332 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 11906 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
11333 } | 11907 } |
11334 ObjectHashTable* table = ObjectHashTable::cast(obj); | 11908 ObjectHashTable* table = ObjectHashTable::cast(obj); |
11335 table->AddEntry(table->FindInsertionEntry(hash), key, value); | 11909 table->AddEntry(table->FindInsertionEntry(hash), key, value); |
11336 return table; | 11910 return table; |
11337 } | 11911 } |
11338 | 11912 |
11339 | 11913 |
11340 void ObjectHashTable::AddEntry(int entry, JSObject* key, Object* value) { | 11914 void ObjectHashTable::AddEntry(int entry, JSReceiver* key, Object* value) { |
11341 set(EntryToIndex(entry), key); | 11915 set(EntryToIndex(entry), key); |
11342 set(EntryToIndex(entry) + 1, value); | 11916 set(EntryToIndex(entry) + 1, value); |
11343 ElementAdded(); | 11917 ElementAdded(); |
11344 } | 11918 } |
11345 | 11919 |
11346 | 11920 |
11347 void ObjectHashTable::RemoveEntry(int entry, Heap* heap) { | 11921 void ObjectHashTable::RemoveEntry(int entry, Heap* heap) { |
11348 set_null(heap, EntryToIndex(entry)); | 11922 set_null(heap, EntryToIndex(entry)); |
11349 set_null(heap, EntryToIndex(entry) + 1); | 11923 set_null(heap, EntryToIndex(entry) + 1); |
11350 ElementRemoved(); | 11924 ElementRemoved(); |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11598 if (break_point_objects()->IsUndefined()) return 0; | 12172 if (break_point_objects()->IsUndefined()) return 0; |
11599 // Single break point. | 12173 // Single break point. |
11600 if (!break_point_objects()->IsFixedArray()) return 1; | 12174 if (!break_point_objects()->IsFixedArray()) return 1; |
11601 // Multiple break points. | 12175 // Multiple break points. |
11602 return FixedArray::cast(break_point_objects())->length(); | 12176 return FixedArray::cast(break_point_objects())->length(); |
11603 } | 12177 } |
11604 #endif | 12178 #endif |
11605 | 12179 |
11606 | 12180 |
11607 } } // namespace v8::internal | 12181 } } // namespace v8::internal |
OLD | NEW |