| 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 |