vendor/v8/src/objects.cc in mustang-0.0.1 vs vendor/v8/src/objects.cc in mustang-0.1.0

- old
+ new

@@ -49,11 +49,10 @@ #ifdef ENABLE_DISASSEMBLER #include "disasm.h" #include "disassembler.h" #endif - namespace v8 { namespace internal { // Getters and setters are stored in a fixed array property. These are // constants for their indices. @@ -62,11 +61,12 @@ MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor, Object* value) { Object* result; - { MaybeObject* maybe_result = Heap::AllocateJSObject(constructor); + { MaybeObject* maybe_result = + constructor->GetHeap()->AllocateJSObject(constructor); if (!maybe_result->ToObject(&result)) return maybe_result; } JSValue::cast(result)->set_value(value); return result; } @@ -84,57 +84,78 @@ return this; } MaybeObject* Object::ToObject() { - Context* global_context = Top::context()->global_context(); if (IsJSObject()) { return this; } else if (IsNumber()) { + Isolate* isolate = Isolate::Current(); + Context* global_context = isolate->context()->global_context(); return CreateJSValue(global_context->number_function(), this); } else if (IsBoolean()) { + Isolate* isolate = HeapObject::cast(this)->GetIsolate(); + Context* global_context = isolate->context()->global_context(); return CreateJSValue(global_context->boolean_function(), this); } else if (IsString()) { + Isolate* isolate = HeapObject::cast(this)->GetIsolate(); + Context* global_context = isolate->context()->global_context(); return CreateJSValue(global_context->string_function(), this); } // Throw a type error. return Failure::InternalError(); } Object* Object::ToBoolean() { - if (IsTrue()) return Heap::true_value(); - if (IsFalse()) return Heap::false_value(); + if (IsTrue()) return this; + if (IsFalse()) return this; if (IsSmi()) { - return Heap::ToBoolean(Smi::cast(this)->value() != 0); + return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0); } - if (IsUndefined() || IsNull()) return Heap::false_value(); + HeapObject* heap_object = HeapObject::cast(this); + if (heap_object->IsUndefined() || heap_object->IsNull()) { + return heap_object->GetHeap()->false_value(); + } // Undetectable object is false - if (IsUndetectableObject()) { - return Heap::false_value(); + if (heap_object->IsUndetectableObject()) { + return heap_object->GetHeap()->false_value(); } - if (IsString()) { - return Heap::ToBoolean(String::cast(this)->length() != 0); + if (heap_object->IsString()) { + return heap_object->GetHeap()->ToBoolean( + String::cast(this)->length() != 0); } - if (IsHeapNumber()) { + if (heap_object->IsHeapNumber()) { return HeapNumber::cast(this)->HeapNumberToBoolean(); } - return Heap::true_value(); + return heap_object->GetHeap()->true_value(); } void Object::Lookup(String* name, LookupResult* result) { - if (IsJSObject()) return JSObject::cast(this)->Lookup(name, result); Object* holder = NULL; - Context* global_context = Top::context()->global_context(); - if (IsString()) { - holder = global_context->string_function()->instance_prototype(); - } else if (IsNumber()) { + if (IsSmi()) { + Heap* heap = Isolate::Current()->heap(); + Context* global_context = heap->isolate()->context()->global_context(); holder = global_context->number_function()->instance_prototype(); - } else if (IsBoolean()) { - holder = global_context->boolean_function()->instance_prototype(); + } else { + HeapObject* heap_object = HeapObject::cast(this); + if (heap_object->IsJSObject()) { + return JSObject::cast(this)->Lookup(name, result); + } + Heap* heap = heap_object->GetHeap(); + if (heap_object->IsString()) { + Context* global_context = heap->isolate()->context()->global_context(); + holder = global_context->string_function()->instance_prototype(); + } else if (heap_object->IsHeapNumber()) { + Context* global_context = heap->isolate()->context()->global_context(); + holder = global_context->number_function()->instance_prototype(); + } else if (heap_object->IsBoolean()) { + Context* global_context = heap->isolate()->context()->global_context(); + holder = global_context->boolean_function()->instance_prototype(); + } } ASSERT(holder != NULL); // Cannot handle null or undefined. JSObject::cast(holder)->Lookup(name, result); } @@ -152,18 +173,19 @@ MaybeObject* Object::GetPropertyWithCallback(Object* receiver, Object* structure, String* name, Object* holder) { + Isolate* isolate = name->GetIsolate(); // To accommodate both the old and the new api we switch on the // data structure used to store the callbacks. Eventually proxy // callbacks should be phased out. if (structure->IsProxy()) { AccessorDescriptor* callback = reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy()); MaybeObject* value = (callback->getter)(receiver, callback->data); - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); return value; } // api style callbacks. if (structure->IsAccessorInfo()) { @@ -172,21 +194,23 @@ v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); HandleScope scope; JSObject* self = JSObject::cast(receiver); JSObject* holder_handle = JSObject::cast(holder); Handle<String> key(name); - LOG(ApiNamedPropertyAccess("load", self, name)); - CustomArguments args(data->data(), self, holder_handle); + LOG(isolate, ApiNamedPropertyAccess("load", self, name)); + CustomArguments args(isolate, data->data(), self, holder_handle); v8::AccessorInfo info(args.end()); v8::Handle<v8::Value> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); result = call_fun(v8::Utils::ToLocal(key), info); } - RETURN_IF_SCHEDULED_EXCEPTION(); - if (result.IsEmpty()) return Heap::undefined_value(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); + if (result.IsEmpty()) { + return isolate->heap()->undefined_value(); + } return *v8::Utils::OpenHandle(*result); } // __defineGetter__ callback if (structure->IsFixedArray()) { @@ -194,11 +218,11 @@ if (getter->IsJSFunction()) { return Object::GetPropertyWithDefinedGetter(receiver, JSFunction::cast(getter)); } // Getter is not a function. - return Heap::undefined_value(); + return isolate->heap()->undefined_value(); } UNREACHABLE(); return NULL; } @@ -208,13 +232,14 @@ JSFunction* getter) { HandleScope scope; Handle<JSFunction> fun(JSFunction::cast(getter)); Handle<Object> self(receiver); #ifdef ENABLE_DEBUGGER_SUPPORT + Debug* debug = fun->GetHeap()->isolate()->debug(); // Handle stepping into a getter if step into is active. - if (Debug::StepInActive()) { - Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false); + if (debug->StepInActive()) { + debug->HandleStepIn(fun, Handle<Object>::null(), 0, false); } #endif bool has_pending_exception; Handle<Object> result = Execution::Call(fun, self, 0, NULL, &has_pending_exception); @@ -279,12 +304,13 @@ } } // No accessible property found. *attributes = ABSENT; - Top::ReportFailedAccessCheck(this, v8::ACCESS_GET); - return Heap::undefined_value(); + Heap* heap = name->GetHeap(); + heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET); + return heap->undefined_value(); } PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck( Object* receiver, @@ -342,11 +368,11 @@ default: UNREACHABLE(); } } - Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); + GetHeap()->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); return ABSENT; } Object* JSObject::GetNormalizedProperty(LookupResult* result) { @@ -380,16 +406,14 @@ ASSERT(!HasFastProperties()); int entry = property_dictionary()->FindEntry(name); if (entry == StringDictionary::kNotFound) { Object* store_value = value; if (IsGlobalObject()) { - { MaybeObject* maybe_store_value = - Heap::AllocateJSGlobalPropertyCell(value); - if (!maybe_store_value->ToObject(&store_value)) { - return maybe_store_value; - } - } + Heap* heap = name->GetHeap(); + MaybeObject* maybe_store_value = + heap->AllocateJSGlobalPropertyCell(value); + if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value; } Object* dict; { MaybeObject* maybe_dict = property_dictionary()->Add(name, store_value, details); if (!maybe_dict->ToObject(&dict)) return maybe_dict; @@ -421,11 +445,11 @@ if (entry != StringDictionary::kNotFound) { // If we have a global object set the cell to the hole. if (IsGlobalObject()) { PropertyDetails details = dictionary->DetailsAt(entry); if (details.IsDontDelete()) { - if (mode != FORCE_DELETION) return Heap::false_value(); + if (mode != FORCE_DELETION) return GetHeap()->false_value(); // When forced to delete global properties, we have to make a // map change to invalidate any ICs that think they can load // from the DontDelete cell without checking if it contains // the hole value. Object* new_map; @@ -434,17 +458,17 @@ } set_map(Map::cast(new_map)); } JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(dictionary->ValueAt(entry)); - cell->set_value(Heap::the_hole_value()); + cell->set_value(cell->heap()->the_hole_value()); dictionary->DetailsAtPut(entry, details.AsDeleted()); } else { return dictionary->DeleteProperty(entry, mode); } } - return Heap::true_value(); + return GetHeap()->true_value(); } bool JSObject::IsDirty() { Object* cons_obj = map()->constructor(); @@ -466,26 +490,27 @@ String* name, PropertyAttributes* attributes) { // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; + Heap* heap = name->GetHeap(); // Traverse the prototype chain from the current object (this) to // the holder and check for access rights. This avoid traversing the // objects more than once in case of interceptors, because the // holder will always be the interceptor holder and the search may // only continue with a current object just after the interceptor // holder in the prototype chain. - Object* last = result->IsProperty() ? result->holder() : Heap::null_value(); + Object* last = result->IsProperty() ? result->holder() : heap->null_value(); for (Object* current = this; true; current = current->GetPrototype()) { if (current->IsAccessCheckNeeded()) { // Check if we're allowed to read from the current object. Note // that even though we may not actually end up loading the named // property from the current object, we still check that we have // access to it. JSObject* checked = JSObject::cast(current); - if (!Top::MayNamedAccess(checked, name, v8::ACCESS_GET)) { + if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) { return checked->GetPropertyWithFailedAccessCheck(receiver, result, name, attributes); } @@ -496,24 +521,24 @@ if (current == last) break; } if (!result->IsProperty()) { *attributes = ABSENT; - return Heap::undefined_value(); + return heap->undefined_value(); } *attributes = result->GetAttributes(); Object* value; JSObject* holder = result->holder(); switch (result->type()) { case NORMAL: value = holder->GetNormalizedProperty(result); ASSERT(!value->IsTheHole() || result->IsReadOnly()); - return value->IsTheHole() ? Heap::undefined_value() : value; + return value->IsTheHole() ? heap->undefined_value() : value; case FIELD: value = holder->FastPropertyAt(result->GetFieldIndex()); ASSERT(!value->IsTheHole() || result->IsReadOnly()); - return value->IsTheHole() ? Heap::undefined_value() : value; + return value->IsTheHole() ? heap->undefined_value() : value; case CONSTANT_FUNCTION: return result->GetConstantFunction(); case CALLBACKS: return GetPropertyWithCallback(receiver, result->GetCallbackObject(), @@ -529,43 +554,67 @@ } } MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) { - if (IsJSObject()) { - return JSObject::cast(this)->GetElementWithReceiver(receiver, index); - } - Object* holder = NULL; - Context* global_context = Top::context()->global_context(); - if (IsString()) { - holder = global_context->string_function()->instance_prototype(); - } else if (IsNumber()) { + if (IsSmi()) { + Context* global_context = Isolate::Current()->context()->global_context(); holder = global_context->number_function()->instance_prototype(); - } else if (IsBoolean()) { - holder = global_context->boolean_function()->instance_prototype(); } else { - // Undefined and null have no indexed properties. - ASSERT(IsUndefined() || IsNull()); - return Heap::undefined_value(); + HeapObject* heap_object = HeapObject::cast(this); + + if (heap_object->IsJSObject()) { + return JSObject::cast(this)->GetElementWithReceiver(receiver, index); + } + Heap* heap = heap_object->GetHeap(); + Isolate* isolate = heap->isolate(); + + Context* global_context = isolate->context()->global_context(); + if (heap_object->IsString()) { + holder = global_context->string_function()->instance_prototype(); + } else if (heap_object->IsHeapNumber()) { + holder = global_context->number_function()->instance_prototype(); + } else if (heap_object->IsBoolean()) { + holder = global_context->boolean_function()->instance_prototype(); + } else { + // Undefined and null have no indexed properties. + ASSERT(heap_object->IsUndefined() || heap_object->IsNull()); + return heap->undefined_value(); + } } return JSObject::cast(holder)->GetElementWithReceiver(receiver, index); } Object* Object::GetPrototype() { + if (IsSmi()) { + Heap* heap = Isolate::Current()->heap(); + Context* context = heap->isolate()->context()->global_context(); + return context->number_function()->instance_prototype(); + } + + HeapObject* heap_object = HeapObject::cast(this); + // The object is either a number, a string, a boolean, or a real JS object. - if (IsJSObject()) return JSObject::cast(this)->map()->prototype(); - Context* context = Top::context()->global_context(); + if (heap_object->IsJSObject()) { + return JSObject::cast(this)->map()->prototype(); + } + Heap* heap = heap_object->GetHeap(); + Context* context = heap->isolate()->context()->global_context(); - if (IsNumber()) return context->number_function()->instance_prototype(); - if (IsString()) return context->string_function()->instance_prototype(); - if (IsBoolean()) { + if (heap_object->IsHeapNumber()) { + return context->number_function()->instance_prototype(); + } + if (heap_object->IsString()) { + return context->string_function()->instance_prototype(); + } + if (heap_object->IsBoolean()) { return context->boolean_function()->instance_prototype(); } else { - return Heap::null_value(); + return heap->null_value(); } } void Object::ShortPrint(FILE* out) { @@ -635,28 +684,29 @@ #ifdef DEBUG // Do not attempt to flatten in debug mode when allocation is not // allowed. This is to avoid an assertion failure when allocating. // Flattening strings is the only case where we always allow // allocation because no GC is performed if the allocation fails. - if (!Heap::IsAllocationAllowed()) return this; + if (!HEAP->IsAllocationAllowed()) return this; #endif + Heap* heap = GetHeap(); switch (StringShape(this).representation_tag()) { case kConsStringTag: { ConsString* cs = ConsString::cast(this); if (cs->second()->length() == 0) { return cs->first(); } // There's little point in putting the flat string in new space if the // cons string is in old space. It can never get GCed until there is // an old space GC. - PretenureFlag tenure = Heap::InNewSpace(this) ? pretenure : TENURED; + PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED; int len = length(); Object* object; String* result; if (IsAsciiRepresentation()) { - { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(len, tenure); + { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure); if (!maybe_object->ToObject(&object)) return maybe_object; } result = String::cast(object); String* first = cs->first(); int first_length = first->length(); @@ -667,11 +717,11 @@ dest + first_length, 0, len - first_length); } else { { MaybeObject* maybe_object = - Heap::AllocateRawTwoByteString(len, tenure); + heap->AllocateRawTwoByteString(len, tenure); if (!maybe_object->ToObject(&object)) return maybe_object; } result = String::cast(object); uc16* dest = SeqTwoByteString::cast(result)->GetChars(); String* first = cs->first(); @@ -682,11 +732,11 @@ dest + first_length, 0, len - first_length); } cs->set_first(result); - cs->set_second(Heap::empty_string()); + cs->set_second(heap->empty_string()); return result; } default: return this; } @@ -706,11 +756,11 @@ ASSERT(memcmp(smart_chars.start(), resource->data(), resource->length() * sizeof(smart_chars[0])) == 0); } #endif // DEBUG - + Heap* heap = GetHeap(); int size = this->Size(); // Byte size of the original string. if (size < ExternalString::kSize) { // The string is too small to fit an external String in its place. This can // only happen for zero length strings. return false; @@ -722,29 +772,29 @@ int hash_field = this->hash_field(); // Morph the object to an external string by adjusting the map and // reinitializing the fields. this->set_map(is_ascii ? - Heap::external_string_with_ascii_data_map() : - Heap::external_string_map()); + heap->external_string_with_ascii_data_map() : + heap->external_string_map()); ExternalTwoByteString* self = ExternalTwoByteString::cast(this); self->set_length(length); self->set_hash_field(hash_field); self->set_resource(resource); // Additionally make the object into an external symbol if the original string // was a symbol to start with. if (is_symbol) { self->Hash(); // Force regeneration of the hash value. // Now morph this external string into a external symbol. this->set_map(is_ascii ? - Heap::external_symbol_with_ascii_data_map() : - Heap::external_symbol_map()); + heap->external_symbol_with_ascii_data_map() : + heap->external_symbol_map()); } // Fill the remainder of the string with dead wood. int new_size = this->Size(); // Byte size of the external String object. - Heap::CreateFillerObjectAt(this->address() + new_size, size - new_size); + heap->CreateFillerObjectAt(this->address() + new_size, size - new_size); return true; } bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) { @@ -757,11 +807,11 @@ ASSERT(memcmp(smart_chars.start(), resource->data(), resource->length() * sizeof(smart_chars[0])) == 0); } #endif // DEBUG - + Heap* heap = GetHeap(); int size = this->Size(); // Byte size of the original string. if (size < ExternalString::kSize) { // The string is too small to fit an external String in its place. This can // only happen for zero length strings. return false; @@ -771,26 +821,26 @@ int length = this->length(); int hash_field = this->hash_field(); // Morph the object to an external string by adjusting the map and // reinitializing the fields. - this->set_map(Heap::external_ascii_string_map()); + this->set_map(heap->external_ascii_string_map()); ExternalAsciiString* self = ExternalAsciiString::cast(this); self->set_length(length); self->set_hash_field(hash_field); self->set_resource(resource); // Additionally make the object into an external symbol if the original string // was a symbol to start with. if (is_symbol) { self->Hash(); // Force regeneration of the hash value. // Now morph this external string into a external symbol. - this->set_map(Heap::external_ascii_symbol_map()); + this->set_map(heap->external_ascii_symbol_map()); } // Fill the remainder of the string with dead wood. int new_size = this->Size(); // Byte size of the external String object. - Heap::CreateFillerObjectAt(this->address() + new_size, size - new_size); + heap->CreateFillerObjectAt(this->address() + new_size, size - new_size); return true; } void String::StringShortPrint(StringStream* accumulator) { @@ -885,19 +935,21 @@ break; } // All other JSObjects are rather similar to each other (JSObject, // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue). default: { - Object* constructor = map()->constructor(); + Map* map_of_this = map(); + Heap* heap = map_of_this->heap(); + Object* constructor = map_of_this->constructor(); bool printed = false; if (constructor->IsHeapObject() && - !Heap::Contains(HeapObject::cast(constructor))) { + !heap->Contains(HeapObject::cast(constructor))) { accumulator->Add("!!!INVALID CONSTRUCTOR!!!"); } else { bool global_object = IsJSGlobalProxy(); if (constructor->IsJSFunction()) { - if (!Heap::Contains(JSFunction::cast(constructor)->shared())) { + if (!heap->Contains(JSFunction::cast(constructor)->shared())) { accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!"); } else { Object* constructor_name = JSFunction::cast(constructor)->shared()->name(); if (constructor_name->IsString()) { @@ -928,16 +980,17 @@ } } void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { - // if (!Heap::InNewSpace(this)) PrintF("*", this); - if (!Heap::Contains(this)) { + // if (!HEAP->InNewSpace(this)) PrintF("*", this); + Heap* heap = GetHeap(); + if (!heap->Contains(this)) { accumulator->Add("!!!INVALID POINTER!!!"); return; } - if (!Heap::Contains(map())) { + if (!heap->Contains(map())) { accumulator->Add("!!!INVALID MAP!!!"); return; } accumulator->Add("%p ", this); @@ -958,12 +1011,13 @@ accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length()); break; case BYTE_ARRAY_TYPE: accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length()); break; - case PIXEL_ARRAY_TYPE: - accumulator->Add("<PixelArray[%u]>", PixelArray::cast(this)->length()); + case EXTERNAL_PIXEL_ARRAY_TYPE: + accumulator->Add("<ExternalPixelArray[%u]>", + ExternalPixelArray::cast(this)->length()); break; case EXTERNAL_BYTE_ARRAY_TYPE: accumulator->Add("<ExternalByteArray[%u]>", ExternalByteArray::cast(this)->length()); break; @@ -1110,11 +1164,11 @@ JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v); break; case HEAP_NUMBER_TYPE: case FILLER_TYPE: case BYTE_ARRAY_TYPE: - case PIXEL_ARRAY_TYPE: + case EXTERNAL_PIXEL_ARRAY_TYPE: case EXTERNAL_BYTE_ARRAY_TYPE: case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: case EXTERNAL_SHORT_ARRAY_TYPE: case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: case EXTERNAL_INT_ARRAY_TYPE: @@ -1147,18 +1201,18 @@ #endif u.d = value(); if (u.bits.exp == 2047) { // Detect NaN for IEEE double precision floating point. if ((u.bits.man_low | u.bits.man_high) != 0) - return Heap::false_value(); + return GetHeap()->false_value(); } if (u.bits.exp == 0) { // Detect +0, and -0 for IEEE double precision floating point. if ((u.bits.man_low | u.bits.man_high) == 0) - return Heap::false_value(); + return GetHeap()->false_value(); } - return Heap::true_value(); + return GetHeap()->true_value(); } void HeapNumber::HeapNumberPrint(FILE* out) { PrintF(out, "%.16g", Number()); @@ -1178,18 +1232,18 @@ } String* JSObject::class_name() { if (IsJSFunction()) { - return Heap::function_class_symbol(); + return GetHeap()->function_class_symbol(); } if (map()->constructor()->IsJSFunction()) { JSFunction* constructor = JSFunction::cast(map()->constructor()); return String::cast(constructor->shared()->instance_class_name()); } // If the constructor is not present, return "Object". - return Heap::Object_symbol(); + return GetHeap()->Object_symbol(); } String* JSObject::constructor_name() { if (map()->constructor()->IsJSFunction()) { @@ -1200,11 +1254,11 @@ if (inferred_name->length() > 0) return inferred_name; Object* proto = GetPrototype(); if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name(); } // If the constructor is not present, return "Object". - return Heap::Object_symbol(); + return GetHeap()->Object_symbol(); } MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, String* name, @@ -1230,13 +1284,14 @@ PropertyAttributes attributes) { ASSERT(!IsJSGlobalProxy()); // Normalize the object if the name is an actual string (not the // hidden symbols) and is not a real identifier. + Isolate* isolate = GetHeap()->isolate(); StringInputBuffer buffer(name); - if (!ScannerConstants::IsIdentifier(&buffer) - && name != Heap::hidden_symbol()) { + if (!isolate->scanner_constants()->IsIdentifier(&buffer) + && name != isolate->heap()->hidden_symbol()) { Object* obj; { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } @@ -1255,15 +1310,25 @@ if (!maybe_new_descriptors->ToObject(&new_descriptors)) { return maybe_new_descriptors; } } - // Only allow map transition if the object's map is NOT equal to the - // global object_function's map and there is not a transition for name. + // Only allow map transition if the object isn't the global object and there + // is not a transition for the name, or there's a transition for the name but + // it's unrelated to properties. + int descriptor_index = old_descriptors->Search(name); + + // External array transitions are stored in the descriptor for property "", + // which is not a identifier and should have forced a switch to slow + // properties above. + ASSERT(descriptor_index == DescriptorArray::kNotFound || + old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION); + bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound || + old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION; bool allow_map_transition = - !old_descriptors->Contains(name) && - (Top::context()->global_context()->object_function()->map() != map()); + can_insert_transition && + (isolate->context()->global_context()->object_function()->map() != map()); ASSERT(index < map()->inobject_properties() || (index - map()->inobject_properties()) < properties()->length() || map()->unused_property_fields() == 0); // Allocate a new map for the object. @@ -1313,11 +1378,11 @@ MaybeObject* JSObject::AddConstantFunctionProperty( String* name, JSFunction* function, PropertyAttributes attributes) { - ASSERT(!Heap::InNewSpace(function)); + ASSERT(!GetHeap()->InNewSpace(function)); // Allocate new instance descriptors with (name, function) added ConstantFunctionDescriptor d(name, function, attributes); Object* new_descriptors; { MaybeObject* maybe_new_descriptors = @@ -1338,11 +1403,13 @@ Map* old_map = map(); set_map(Map::cast(new_map)); // If the old map is the global object map (from new Object()), // then transitions are not added to it, so we are done. - if (old_map == Top::context()->global_context()->object_function()->map()) { + Heap* heap = old_map->heap(); + if (old_map == heap->isolate()->context()->global_context()-> + object_function()->map()) { return function; } // Do not add CONSTANT_TRANSITIONS to global objects if (IsGlobalObject()) { @@ -1389,12 +1456,13 @@ PropertyDetails details = PropertyDetails(attributes, NORMAL, index); dict->SetNextEnumerationIndex(index + 1); dict->SetEntry(entry, name, store_value, details); return value; } + Heap* heap = GetHeap(); { MaybeObject* maybe_store_value = - Heap::AllocateJSGlobalPropertyCell(value); + heap->AllocateJSGlobalPropertyCell(value); if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value; } JSGlobalPropertyCell::cast(store_value)->set_value(value); } PropertyDetails details = PropertyDetails(attributes, NORMAL); @@ -1407,22 +1475,30 @@ } MaybeObject* JSObject::AddProperty(String* name, Object* value, - PropertyAttributes attributes) { + PropertyAttributes attributes, + StrictModeFlag strict_mode) { ASSERT(!IsJSGlobalProxy()); - if (!map()->is_extensible()) { - Handle<Object> args[1] = {Handle<String>(name)}; - return Top::Throw(*Factory::NewTypeError("object_not_extensible", - HandleVector(args, 1))); + Map* map_of_this = map(); + Heap* heap = map_of_this->heap(); + if (!map_of_this->is_extensible()) { + if (strict_mode == kNonStrictMode) { + return heap->undefined_value(); + } else { + Handle<Object> args[1] = {Handle<String>(name)}; + return heap->isolate()->Throw( + *FACTORY->NewTypeError("object_not_extensible", + HandleVector(args, 1))); + } } if (HasFastProperties()) { // Ensure the descriptor array does not get too big. - if (map()->instance_descriptors()->number_of_descriptors() < + if (map_of_this->instance_descriptors()->number_of_descriptors() < DescriptorArray::kMaxNumberOfDescriptors) { - if (value->IsJSFunction() && !Heap::InNewSpace(value)) { + if (value->IsJSFunction() && !heap->InNewSpace(value)) { return AddConstantFunctionProperty(name, JSFunction::cast(value), attributes); } else { return AddFastProperty(name, value, attributes); @@ -1442,21 +1518,22 @@ MaybeObject* JSObject::SetPropertyPostInterceptor( String* name, Object* value, - PropertyAttributes attributes) { + PropertyAttributes attributes, + StrictModeFlag strict_mode) { // Check local property, ignore interceptor. LookupResult result; LocalLookupRealNamedProperty(name, &result); if (result.IsFound()) { // An existing property, a map transition or a null descriptor was // found. Use set property to handle all these cases. - return SetProperty(&result, name, value, attributes); + return SetProperty(&result, name, value, attributes, strict_mode); } // Add a new real property. - return AddProperty(name, value, attributes); + return AddProperty(name, value, attributes, strict_mode); } MaybeObject* JSObject::ReplaceSlowProperty(String* name, Object* value, @@ -1489,11 +1566,12 @@ // after this point. Later stuff is optional. if (!HasFastProperties()) { return result; } // Do not add transitions to the map of "new Object()". - if (map() == Top::context()->global_context()->object_function()->map()) { + if (map() == old_map->heap()->isolate()->context()->global_context()-> + object_function()->map()) { return result; } MapTransitionDescriptor transition(name, map(), @@ -1574,73 +1652,79 @@ MaybeObject* JSObject::SetPropertyWithInterceptor( String* name, Object* value, - PropertyAttributes attributes) { - HandleScope scope; + PropertyAttributes attributes, + StrictModeFlag strict_mode) { + Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); Handle<JSObject> this_handle(this); Handle<String> name_handle(name); - Handle<Object> value_handle(value); + Handle<Object> value_handle(value, isolate); Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); if (!interceptor->setter()->IsUndefined()) { - LOG(ApiNamedPropertyAccess("interceptor-named-set", this, name)); - CustomArguments args(interceptor->data(), this, this); + LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name)); + CustomArguments args(isolate, interceptor->data(), this, this); v8::AccessorInfo info(args.end()); v8::NamedPropertySetter setter = v8::ToCData<v8::NamedPropertySetter>(interceptor->setter()); v8::Handle<v8::Value> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); Handle<Object> value_unhole(value->IsTheHole() ? - Heap::undefined_value() : - value); + isolate->heap()->undefined_value() : + value, + isolate); result = setter(v8::Utils::ToLocal(name_handle), v8::Utils::ToLocal(value_unhole), info); } - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); if (!result.IsEmpty()) return *value_handle; } MaybeObject* raw_result = this_handle->SetPropertyPostInterceptor(*name_handle, *value_handle, - attributes); - RETURN_IF_SCHEDULED_EXCEPTION(); + attributes, + strict_mode); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); return raw_result; } MaybeObject* JSObject::SetProperty(String* name, Object* value, - PropertyAttributes attributes) { + PropertyAttributes attributes, + StrictModeFlag strict_mode) { LookupResult result; LocalLookup(name, &result); - return SetProperty(&result, name, value, attributes); + return SetProperty(&result, name, value, attributes, strict_mode); } MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, String* name, Object* value, JSObject* holder) { - HandleScope scope; + Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); // We should never get here to initialize a const with the hole // value since a const declaration would conflict with the setter. ASSERT(!value->IsTheHole()); - Handle<Object> value_handle(value); + Handle<Object> value_handle(value, isolate); // To accommodate both the old and the new api we switch on the // data structure used to store the callbacks. Eventually proxy // callbacks should be phased out. if (structure->IsProxy()) { AccessorDescriptor* callback = reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy()); MaybeObject* obj = (callback->setter)(this, value, callback->data); - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); if (obj->IsFailure()) return obj; return *value_handle; } if (structure->IsAccessorInfo()) { @@ -1648,51 +1732,54 @@ AccessorInfo* data = AccessorInfo::cast(structure); Object* call_obj = data->setter(); v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj); if (call_fun == NULL) return value; Handle<String> key(name); - LOG(ApiNamedPropertyAccess("store", this, name)); - CustomArguments args(data->data(), this, JSObject::cast(holder)); + LOG(isolate, ApiNamedPropertyAccess("store", this, name)); + CustomArguments args(isolate, data->data(), this, JSObject::cast(holder)); v8::AccessorInfo info(args.end()); { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); call_fun(v8::Utils::ToLocal(key), v8::Utils::ToLocal(value_handle), info); } - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); return *value_handle; } if (structure->IsFixedArray()) { Object* setter = FixedArray::cast(structure)->get(kSetterIndex); if (setter->IsJSFunction()) { return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); } else { Handle<String> key(name); - Handle<Object> holder_handle(holder); + Handle<Object> holder_handle(holder, isolate); Handle<Object> args[2] = { key, holder_handle }; - return Top::Throw(*Factory::NewTypeError("no_setter_in_callback", - HandleVector(args, 2))); + return isolate->Throw( + *isolate->factory()->NewTypeError("no_setter_in_callback", + HandleVector(args, 2))); } } UNREACHABLE(); return NULL; } MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter, Object* value) { - Handle<Object> value_handle(value); - Handle<JSFunction> fun(JSFunction::cast(setter)); - Handle<JSObject> self(this); + Isolate* isolate = GetIsolate(); + Handle<Object> value_handle(value, isolate); + Handle<JSFunction> fun(JSFunction::cast(setter), isolate); + Handle<JSObject> self(this, isolate); #ifdef ENABLE_DEBUGGER_SUPPORT + Debug* debug = isolate->debug(); // Handle stepping into a setter if step into is active. - if (Debug::StepInActive()) { - Debug::HandleStepIn(fun, Handle<Object>::null(), 0, false); + if (debug->StepInActive()) { + debug->HandleStepIn(fun, Handle<Object>::null(), 0, false); } #endif bool has_pending_exception; Object** argv[] = { value_handle.location() }; Execution::Call(fun, self, 1, argv, &has_pending_exception); @@ -1702,12 +1789,13 @@ } void JSObject::LookupCallbackSetterInPrototypes(String* name, LookupResult* result) { + Heap* heap = GetHeap(); for (Object* pt = GetPrototype(); - pt != Heap::null_value(); + pt != heap->null_value(); pt = pt->GetPrototype()) { JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result); if (result->IsProperty()) { if (result->IsReadOnly()) { result->NotFound(); @@ -1723,12 +1811,13 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index, Object* value, bool* found) { + Heap* heap = GetHeap(); for (Object* pt = GetPrototype(); - pt != Heap::null_value(); + pt != heap->null_value(); pt = pt->GetPrototype()) { if (!JSObject::cast(pt)->HasDictionaryElements()) { continue; } NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); @@ -1741,11 +1830,11 @@ dictionary->ValueAt(entry), index, value, JSObject::cast(pt)); } } } *found = false; - return Heap::the_hole_value(); + return heap->the_hole_value(); } void JSObject::LookupInDescriptor(String* name, LookupResult* result) { DescriptorArray* descriptors = map()->instance_descriptors(); @@ -1760,23 +1849,97 @@ void Map::LookupInDescriptors(JSObject* holder, String* name, LookupResult* result) { DescriptorArray* descriptors = instance_descriptors(); - int number = DescriptorLookupCache::Lookup(descriptors, name); + DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache(); + int number = cache->Lookup(descriptors, name); if (number == DescriptorLookupCache::kAbsent) { number = descriptors->Search(name); - DescriptorLookupCache::Update(descriptors, name, number); + cache->Update(descriptors, name, number); } if (number != DescriptorArray::kNotFound) { result->DescriptorResult(holder, descriptors->GetDetails(number), number); } else { result->NotFound(); } } +MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type, + bool safe_to_add_transition) { + Heap* current_heap = heap(); + DescriptorArray* descriptors = instance_descriptors(); + String* external_array_sentinel_name = current_heap->empty_symbol(); + + if (safe_to_add_transition) { + // It's only safe to manipulate the descriptor array if it would be + // safe to add a transition. + + ASSERT(!is_shared()); // no transitions can be added to shared maps. + // Check if the external array transition already exists. + DescriptorLookupCache* cache = + current_heap->isolate()->descriptor_lookup_cache(); + int index = cache->Lookup(descriptors, external_array_sentinel_name); + if (index == DescriptorLookupCache::kAbsent) { + index = descriptors->Search(external_array_sentinel_name); + cache->Update(descriptors, + external_array_sentinel_name, + index); + } + + // If the transition already exists, check the type. If there is a match, + // return it. + if (index != DescriptorArray::kNotFound) { + PropertyDetails details(PropertyDetails(descriptors->GetDetails(index))); + if (details.type() == EXTERNAL_ARRAY_TRANSITION && + details.array_type() == array_type) { + return descriptors->GetValue(index); + } else { + safe_to_add_transition = false; + } + } + } + + // No transition to an existing external array map. Make a new one. + Object* obj; + { MaybeObject* maybe_map = CopyDropTransitions(); + if (!maybe_map->ToObject(&obj)) return maybe_map; + } + Map* new_map = Map::cast(obj); + + new_map->set_has_fast_elements(false); + new_map->set_has_external_array_elements(true); + GetIsolate()->counters()->map_to_external_array_elements()->Increment(); + + // Only remember the map transition if the object's map is NOT equal to the + // global object_function's map and there is not an already existing + // non-matching external array transition. + bool allow_map_transition = + safe_to_add_transition && + (GetIsolate()->context()->global_context()->object_function()->map() != + map()); + if (allow_map_transition) { + // Allocate new instance descriptors for the old map with map transition. + ExternalArrayTransitionDescriptor desc(external_array_sentinel_name, + Map::cast(new_map), + array_type); + Object* new_descriptors; + MaybeObject* maybe_new_descriptors = descriptors->CopyInsert( + &desc, + KEEP_TRANSITIONS); + if (!maybe_new_descriptors->ToObject(&new_descriptors)) { + return maybe_new_descriptors; + } + descriptors = DescriptorArray::cast(new_descriptors); + set_instance_descriptors(descriptors); + } + + return new_map; +} + + void JSObject::LocalLookupRealNamedProperty(String* name, LookupResult* result) { if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); if (proto->IsNull()) return result->NotFound(); @@ -1831,12 +1994,13 @@ } void JSObject::LookupRealNamedPropertyInPrototypes(String* name, LookupResult* result) { + Heap* heap = GetHeap(); for (Object* pt = GetPrototype(); - pt != Heap::null_value(); + pt != heap->null_value(); pt = JSObject::cast(pt)->GetPrototype()) { JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result); if (result->IsProperty() && (result->type() != INTERCEPTOR)) return; } result->NotFound(); @@ -1886,46 +2050,50 @@ } } HandleScope scope; Handle<Object> value_handle(value); - Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); + Heap* heap = GetHeap(); + heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); return *value_handle; } MaybeObject* JSObject::SetProperty(LookupResult* result, String* name, Object* value, - PropertyAttributes attributes) { + PropertyAttributes attributes, + StrictModeFlag strict_mode) { + Heap* heap = GetHeap(); // Make sure that the top context does not change when doing callbacks or // interceptor calls. AssertNoContextChange ncc; // Optimization for 2-byte strings often used as keys in a decompression // dictionary. We make these short keys into symbols to avoid constantly // reallocating them. if (!name->IsSymbol() && name->length() <= 2) { Object* symbol_version; - { MaybeObject* maybe_symbol_version = Heap::LookupSymbol(name); + { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name); if (maybe_symbol_version->ToObject(&symbol_version)) { name = String::cast(symbol_version); } } } // Check access rights if needed. if (IsAccessCheckNeeded() - && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { + && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) { return SetPropertyWithFailedAccessCheck(result, name, value, true); } if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); if (proto->IsNull()) return value; ASSERT(proto->IsJSGlobalObject()); - return JSObject::cast(proto)->SetProperty(result, name, value, attributes); + return JSObject::cast(proto)->SetProperty( + result, name, value, attributes, strict_mode); } if (!result->IsProperty() && !IsJSContextExtensionObject()) { // We could not find a local property so let's check whether there is an // accessor that wants to handle the property. @@ -1938,13 +2106,24 @@ accessor_result.holder()); } } if (!result->IsFound()) { // Neither properties nor transitions found. - return AddProperty(name, value, attributes); + return AddProperty(name, value, attributes, strict_mode); } - if (result->IsReadOnly() && result->IsProperty()) return value; + if (result->IsReadOnly() && result->IsProperty()) { + if (strict_mode == kStrictMode) { + HandleScope scope; + Handle<String> key(name); + Handle<Object> holder(this); + Handle<Object> args[2] = { key, holder }; + return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError( + "strict_read_only_property", HandleVector(args, 2))); + } else { + return value; + } + } // This is a real property that is not read-only, or it is a // transition or null descriptor and there are no setters in the prototypes. switch (result->type()) { case NORMAL: return SetNormalizedProperty(result, value); @@ -1968,31 +2147,32 @@ return SetPropertyWithCallback(result->GetCallbackObject(), name, value, result->holder()); case INTERCEPTOR: - return SetPropertyWithInterceptor(name, value, attributes); + return SetPropertyWithInterceptor(name, value, attributes, strict_mode); case CONSTANT_TRANSITION: { // If the same constant function is being added we can simply // transition to the target map. Map* target_map = result->GetTransitionMap(); DescriptorArray* target_descriptors = target_map->instance_descriptors(); int number = target_descriptors->SearchWithCache(name); ASSERT(number != DescriptorArray::kNotFound); ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION); JSFunction* function = JSFunction::cast(target_descriptors->GetValue(number)); - ASSERT(!Heap::InNewSpace(function)); + ASSERT(!HEAP->InNewSpace(function)); if (value == function) { set_map(target_map); return value; } // Otherwise, replace with a MAP_TRANSITION to a new map with a // FIELD, even if the value is a constant function. return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); } case NULL_DESCRIPTOR: + case EXTERNAL_ARRAY_TRANSITION: return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); default: UNREACHABLE(); } UNREACHABLE(); @@ -2008,19 +2188,22 @@ // should be. MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( String* name, Object* value, PropertyAttributes attributes) { + // Make sure that the top context does not change when doing callbacks or // interceptor calls. AssertNoContextChange ncc; LookupResult result; LocalLookup(name, &result); // Check access rights if needed. - if (IsAccessCheckNeeded() - && !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { - return SetPropertyWithFailedAccessCheck(&result, name, value, false); + if (IsAccessCheckNeeded()) { + Heap* heap = GetHeap(); + if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) { + return SetPropertyWithFailedAccessCheck(&result, name, value, false); + } } if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); if (proto->IsNull()) return value; @@ -2032,11 +2215,11 @@ } // Check for accessor in prototype chain removed here in clone. if (!result.IsFound()) { // Neither properties nor transitions found. - return AddProperty(name, value, attributes); + return AddProperty(name, value, attributes, kNonStrictMode); } PropertyDetails details = PropertyDetails(attributes, NORMAL); // Check of IsReadOnly removed from here in clone. @@ -2066,10 +2249,11 @@ case CONSTANT_TRANSITION: // Replace with a MAP_TRANSITION to a new map with a FIELD, even // if the value is a function. return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); case NULL_DESCRIPTOR: + case EXTERNAL_ARRAY_TRANSITION: return ConvertDescriptorToFieldAndMapTransition(name, value, attributes); default: UNREACHABLE(); } UNREACHABLE(); @@ -2087,11 +2271,11 @@ if (result.IsProperty()) return result.GetAttributes(); if (continue_search) { // Continue searching via the prototype chain. Object* pt = GetPrototype(); - if (pt != Heap::null_value()) { + if (!pt->IsNull()) { return JSObject::cast(pt)-> GetPropertyAttributeWithReceiver(receiver, name); } } return ABSENT; @@ -2100,43 +2284,47 @@ PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor( JSObject* receiver, String* name, bool continue_search) { + Isolate* isolate = GetIsolate(); + // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; - HandleScope scope; + HandleScope scope(isolate); Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); Handle<JSObject> receiver_handle(receiver); Handle<JSObject> holder_handle(this); Handle<String> name_handle(name); - CustomArguments args(interceptor->data(), receiver, this); + CustomArguments args(isolate, interceptor->data(), receiver, this); v8::AccessorInfo info(args.end()); if (!interceptor->query()->IsUndefined()) { v8::NamedPropertyQuery query = v8::ToCData<v8::NamedPropertyQuery>(interceptor->query()); - LOG(ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name)); + LOG(isolate, + ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name)); v8::Handle<v8::Integer> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); result = query(v8::Utils::ToLocal(name_handle), info); } if (!result.IsEmpty()) { ASSERT(result->IsInt32()); return static_cast<PropertyAttributes>(result->Int32Value()); } } else if (!interceptor->getter()->IsUndefined()) { v8::NamedPropertyGetter getter = v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter()); - LOG(ApiNamedPropertyAccess("interceptor-named-get-has", this, name)); + LOG(isolate, + ApiNamedPropertyAccess("interceptor-named-get-has", this, name)); v8::Handle<v8::Value> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); result = getter(v8::Utils::ToLocal(name_handle), info); } if (!result.IsEmpty()) return DONT_ENUM; } return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle, @@ -2163,16 +2351,18 @@ PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver, LookupResult* result, String* name, bool continue_search) { // Check access rights if needed. - if (IsAccessCheckNeeded() && - !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) { - return GetPropertyAttributeWithFailedAccessCheck(receiver, - result, - name, - continue_search); + if (IsAccessCheckNeeded()) { + Heap* heap = GetHeap(); + if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) { + return GetPropertyAttributeWithFailedAccessCheck(receiver, + result, + name, + continue_search); + } } if (result->IsProperty()) { switch (result->type()) { case NORMAL: // fall through case FIELD: @@ -2204,10 +2394,11 @@ } MaybeObject* NormalizedMapCache::Get(JSObject* obj, PropertyNormalizationMode mode) { + Isolate* isolate = obj->GetIsolate(); Map* fast = obj->map(); int index = Hash(fast) % kEntries; Object* result = get(index); if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) { #ifdef DEBUG @@ -2230,11 +2421,11 @@ { MaybeObject* maybe_result = fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); if (!maybe_result->ToObject(&result)) return maybe_result; } set(index, result); - Counters::normalized_maps.Increment(); + isolate->counters()->normalized_maps()->Increment(); return result; } @@ -2290,11 +2481,11 @@ Object* obj; { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, UNIQUE_NORMALIZED_MAP); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } - Counters::normalized_maps.Increment(); + GetIsolate()->counters()->normalized_maps()->Increment(); set_map(Map::cast(obj)); } return map()->UpdateCodeCache(name, code); } @@ -2304,16 +2495,17 @@ int expected_additional_properties) { if (!HasFastProperties()) return this; // The global object is always normalized. ASSERT(!IsGlobalObject()); - // JSGlobalProxy must never be normalized ASSERT(!IsJSGlobalProxy()); + Map* map_of_this = map(); + // Allocate new content. - int property_count = map()->NumberOfDescribedProperties(); + int property_count = map_of_this->NumberOfDescribedProperties(); if (expected_additional_properties > 0) { property_count += expected_additional_properties; } else { property_count += 2; // Make space for two more properties. } @@ -2322,11 +2514,11 @@ StringDictionary::Allocate(property_count); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } StringDictionary* dictionary = StringDictionary::cast(obj); - DescriptorArray* descs = map()->instance_descriptors(); + DescriptorArray* descs = map_of_this->instance_descriptors(); for (int i = 0; i < descs->number_of_descriptors(); i++) { PropertyDetails details = descs->GetDetails(i); switch (details.type()) { case CONSTANT_FUNCTION: { PropertyDetails d = @@ -2372,35 +2564,39 @@ default: UNREACHABLE(); } } + Heap* current_heap = map_of_this->heap(); + // Copy the next enumeration index from instance descriptor. - int index = map()->instance_descriptors()->NextEnumerationIndex(); + int index = map_of_this->instance_descriptors()->NextEnumerationIndex(); dictionary->SetNextEnumerationIndex(index); - { MaybeObject* maybe_obj = Top::context()->global_context()-> - normalized_map_cache()->Get(this, mode); + { MaybeObject* maybe_obj = + current_heap->isolate()->context()->global_context()-> + normalized_map_cache()->Get(this, mode); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } Map* new_map = Map::cast(obj); // We have now successfully allocated all the necessary objects. // Changes can now be made with the guarantee that all of them take effect. // Resize the object in the heap if necessary. int new_instance_size = new_map->instance_size(); - int instance_size_delta = map()->instance_size() - new_instance_size; + int instance_size_delta = map_of_this->instance_size() - new_instance_size; ASSERT(instance_size_delta >= 0); - Heap::CreateFillerObjectAt(this->address() + new_instance_size, - instance_size_delta); + current_heap->CreateFillerObjectAt(this->address() + new_instance_size, + instance_size_delta); set_map(new_map); + new_map->set_instance_descriptors(current_heap->empty_descriptor_array()); set_properties(dictionary); - Counters::props_to_dictionary.Increment(); + current_heap->isolate()->counters()->props_to_dictionary()->Increment(); #ifdef DEBUG if (FLAG_trace_normalization) { PrintF("Object properties have been normalized:\n"); Print(); @@ -2417,16 +2613,17 @@ TransformPropertiesToFastFor(this, unused_property_fields); } MaybeObject* JSObject::NormalizeElements() { - ASSERT(!HasPixelElements() && !HasExternalArrayElements()); + ASSERT(!HasExternalArrayElements()); if (HasDictionaryElements()) return this; - ASSERT(map()->has_fast_elements()); + Map* old_map = map(); + ASSERT(old_map->has_fast_elements()); Object* obj; - { MaybeObject* maybe_obj = map()->GetSlowElementsMap(); + { MaybeObject* maybe_obj = old_map->GetSlowElementsMap(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } Map* new_map = Map::cast(obj); // Get number of entries. @@ -2457,11 +2654,12 @@ // elements. Set the new map first to satify the elements type // assert in set_elements(). set_map(new_map); set_elements(dictionary); - Counters::elements_to_dictionary.Increment(); + new_map->heap()->isolate()->counters()->elements_to_dictionary()-> + Increment(); #ifdef DEBUG if (FLAG_trace_normalization) { PrintF("Object elements have been normalized:\n"); Print(); @@ -2475,11 +2673,11 @@ MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) { // Check local property, ignore interceptor. LookupResult result; LocalLookupRealNamedProperty(name, &result); - if (!result.IsProperty()) return Heap::true_value(); + if (!result.IsProperty()) return GetHeap()->true_value(); // Normalize object if needed. Object* obj; { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); if (!maybe_obj->ToObject(&obj)) return maybe_obj; @@ -2488,42 +2686,44 @@ return DeleteNormalizedProperty(name, mode); } MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) { - HandleScope scope; + Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); Handle<String> name_handle(name); Handle<JSObject> this_handle(this); if (!interceptor->deleter()->IsUndefined()) { v8::NamedPropertyDeleter deleter = v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter()); - LOG(ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name)); - CustomArguments args(interceptor->data(), this, this); + LOG(isolate, + ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name)); + CustomArguments args(isolate, interceptor->data(), this, this); v8::AccessorInfo info(args.end()); v8::Handle<v8::Boolean> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); result = deleter(v8::Utils::ToLocal(name_handle), info); } - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); if (!result.IsEmpty()) { ASSERT(result->IsBoolean()); return *v8::Utils::OpenHandle(*result); } } MaybeObject* raw_result = this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION); - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); return raw_result; } MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index, DeleteMode mode) { - ASSERT(!HasPixelElements() && !HasExternalArrayElements()); + ASSERT(!HasExternalArrayElements()); switch (GetElementsKind()) { case FAST_ELEMENTS: { Object* obj; { MaybeObject* maybe_obj = EnsureWritableFastElements(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; @@ -2546,56 +2746,60 @@ } default: UNREACHABLE(); break; } - return Heap::true_value(); + return GetHeap()->true_value(); } MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) { + Isolate* isolate = GetIsolate(); + Heap* heap = isolate->heap(); // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; - HandleScope scope; + HandleScope scope(isolate); Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); - if (interceptor->deleter()->IsUndefined()) return Heap::false_value(); + if (interceptor->deleter()->IsUndefined()) return heap->false_value(); v8::IndexedPropertyDeleter deleter = v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter()); Handle<JSObject> this_handle(this); - LOG(ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index)); - CustomArguments args(interceptor->data(), this, this); + LOG(isolate, + ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index)); + CustomArguments args(isolate, interceptor->data(), this, this); v8::AccessorInfo info(args.end()); v8::Handle<v8::Boolean> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); result = deleter(index, info); } - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); if (!result.IsEmpty()) { ASSERT(result->IsBoolean()); return *v8::Utils::OpenHandle(*result); } MaybeObject* raw_result = this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION); - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); return raw_result; } MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { + Isolate* isolate = GetIsolate(); // Check access rights if needed. if (IsAccessCheckNeeded() && - !Top::MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE); - return Heap::false_value(); + !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { + isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); + return isolate->heap()->false_value(); } if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); - if (proto->IsNull()) return Heap::false_value(); + if (proto->IsNull()) return isolate->heap()->false_value(); ASSERT(proto->IsJSGlobalObject()); return JSGlobalObject::cast(proto)->DeleteElement(index, mode); } if (HasIndexedInterceptor()) { @@ -2618,11 +2822,11 @@ if (index < length) { FixedArray::cast(elements())->set_the_hole(index); } break; } - case PIXEL_ELEMENTS: + case EXTERNAL_PIXEL_ELEMENTS: case EXTERNAL_BYTE_ELEMENTS: case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case EXTERNAL_SHORT_ELEMENTS: case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case EXTERNAL_INT_ELEMENTS: @@ -2634,66 +2838,68 @@ case DICTIONARY_ELEMENTS: { NumberDictionary* dictionary = element_dictionary(); int entry = dictionary->FindEntry(index); if (entry != NumberDictionary::kNotFound) { Object* result = dictionary->DeleteProperty(entry, mode); - if (mode == STRICT_DELETION && result == Heap::false_value()) { + if (mode == STRICT_DELETION && result == + isolate->heap()->false_value()) { // In strict mode, deleting a non-configurable property throws // exception. dictionary->DeleteProperty will return false_value() // if a non-configurable property is being deleted. HandleScope scope; - Handle<Object> i = Factory::NewNumberFromUint(index); + Handle<Object> i = isolate->factory()->NewNumberFromUint(index); Handle<Object> args[2] = { i, Handle<Object>(this) }; - return Top::Throw(*Factory::NewTypeError("strict_delete_property", - HandleVector(args, 2))); + return isolate->Throw(*isolate->factory()->NewTypeError( + "strict_delete_property", HandleVector(args, 2))); } } break; } default: UNREACHABLE(); break; } - return Heap::true_value(); + return isolate->heap()->true_value(); } MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { + Isolate* isolate = GetIsolate(); // ECMA-262, 3rd, 8.6.2.5 ASSERT(name->IsString()); // Check access rights if needed. if (IsAccessCheckNeeded() && - !Top::MayNamedAccess(this, name, v8::ACCESS_DELETE)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_DELETE); - return Heap::false_value(); + !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) { + isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); + return isolate->heap()->false_value(); } if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); - if (proto->IsNull()) return Heap::false_value(); + if (proto->IsNull()) return isolate->heap()->false_value(); ASSERT(proto->IsJSGlobalObject()); return JSGlobalObject::cast(proto)->DeleteProperty(name, mode); } uint32_t index = 0; if (name->AsArrayIndex(&index)) { return DeleteElement(index, mode); } else { LookupResult result; LocalLookup(name, &result); - if (!result.IsProperty()) return Heap::true_value(); + if (!result.IsProperty()) return isolate->heap()->true_value(); // Ignore attributes if forcing a deletion. if (result.IsDontDelete() && mode != FORCE_DELETION) { if (mode == STRICT_DELETION) { // Deleting a non-configurable property in strict mode. - HandleScope scope; + HandleScope scope(isolate); Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) }; - return Top::Throw(*Factory::NewTypeError("strict_delete_property", - HandleVector(args, 2))); + return isolate->Throw(*isolate->factory()->NewTypeError( + "strict_delete_property", HandleVector(args, 2))); } - return Heap::false_value(); + return isolate->heap()->false_value(); } // Check for interceptor. if (result.type() == INTERCEPTOR) { // Skip interceptor if forcing a deletion. if (mode == FORCE_DELETION) { @@ -2713,31 +2919,33 @@ } // Check whether this object references another object. bool JSObject::ReferencesObject(Object* obj) { + Map* map_of_this = map(); + Heap* heap = map_of_this->heap(); AssertNoAllocation no_alloc; // Is the object the constructor for this object? - if (map()->constructor() == obj) { + if (map_of_this->constructor() == obj) { return true; } // Is the object the prototype for this object? - if (map()->prototype() == obj) { + if (map_of_this->prototype() == obj) { return true; } // Check if the object is among the named properties. Object* key = SlowReverseLookup(obj); - if (key != Heap::undefined_value()) { + if (!key->IsUndefined()) { return true; } // Check if the object is among the indexed properties. switch (GetElementsKind()) { - case PIXEL_ELEMENTS: + case EXTERNAL_PIXEL_ELEMENTS: case EXTERNAL_BYTE_ELEMENTS: case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case EXTERNAL_SHORT_ELEMENTS: case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case EXTERNAL_INT_ELEMENTS: @@ -2758,11 +2966,11 @@ } break; } case DICTIONARY_ELEMENTS: { key = element_dictionary()->SlowReverseLookup(obj); - if (key != Heap::undefined_value()) { + if (!key->IsUndefined()) { return true; } break; } default: @@ -2772,11 +2980,12 @@ // For functions check the context. if (IsJSFunction()) { // Get the constructor function for arguments array. JSObject* arguments_boilerplate = - Top::context()->global_context()->arguments_boilerplate(); + heap->isolate()->context()->global_context()-> + arguments_boilerplate(); JSFunction* arguments_function = JSFunction::cast(arguments_boilerplate->map()->constructor()); // Get the context and don't check if it is the global context. JSFunction* f = JSFunction::cast(this); @@ -2811,14 +3020,17 @@ return false; } MaybeObject* JSObject::PreventExtensions() { + Isolate* isolate = GetIsolate(); if (IsAccessCheckNeeded() && - !Top::MayNamedAccess(this, Heap::undefined_value(), v8::ACCESS_KEYS)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_KEYS); - return Heap::false_value(); + !isolate->MayNamedAccess(this, + isolate->heap()->undefined_value(), + v8::ACCESS_KEYS)) { + isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS); + return isolate->heap()->false_value(); } if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); if (proto->IsNull()) return this; @@ -2853,12 +3065,13 @@ // - This object and all prototypes has an enum cache (which means that it has // no interceptors and needs no access checks). // - This object has no elements. // - No prototype has enumerable properties/elements. bool JSObject::IsSimpleEnum() { + Heap* heap = GetHeap(); for (Object* o = this; - o != Heap::null_value(); + o != heap->null_value(); o = JSObject::cast(o)->GetPrototype()) { JSObject* curr = JSObject::cast(o); if (!curr->map()->instance_descriptors()->HasEnumCache()) return false; ASSERT(!curr->HasNamedInterceptor()); ASSERT(!curr->HasIndexedInterceptor()); @@ -2920,10 +3133,12 @@ void JSObject::LocalLookup(String* name, LookupResult* result) { ASSERT(name->IsString()); + Heap* heap = GetHeap(); + if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); if (proto->IsNull()) return result->NotFound(); ASSERT(proto->IsJSGlobalObject()); return JSObject::cast(proto)->LocalLookup(name, result); @@ -2934,88 +3149,92 @@ if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) { result->DisallowCaching(); } // Check __proto__ before interceptor. - if (name->Equals(Heap::Proto_symbol()) && !IsJSContextExtensionObject()) { + if (name->Equals(heap->Proto_symbol()) && + !IsJSContextExtensionObject()) { result->ConstantResult(this); return; } // Check for lookup interceptor except when bootstrapping. - if (HasNamedInterceptor() && !Bootstrapper::IsActive()) { + if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) { result->InterceptorResult(this); return; } LocalLookupRealNamedProperty(name, result); } void JSObject::Lookup(String* name, LookupResult* result) { // Ecma-262 3rd 8.6.2.4 + Heap* heap = GetHeap(); for (Object* current = this; - current != Heap::null_value(); + current != heap->null_value(); current = JSObject::cast(current)->GetPrototype()) { JSObject::cast(current)->LocalLookup(name, result); if (result->IsProperty()) return; } result->NotFound(); } // Search object and it's prototype chain for callback properties. void JSObject::LookupCallback(String* name, LookupResult* result) { + Heap* heap = GetHeap(); for (Object* current = this; - current != Heap::null_value(); + current != heap->null_value(); current = JSObject::cast(current)->GetPrototype()) { JSObject::cast(current)->LocalLookupRealNamedProperty(name, result); if (result->IsProperty() && result->type() == CALLBACKS) return; } result->NotFound(); } MaybeObject* JSObject::DefineGetterSetter(String* name, PropertyAttributes attributes) { + Heap* heap = GetHeap(); // Make sure that the top context does not change when doing callbacks or // interceptor calls. AssertNoContextChange ncc; // Try to flatten before operating on the string. name->TryFlatten(); if (!CanSetCallback(name)) { - return Heap::undefined_value(); + return heap->undefined_value(); } uint32_t index = 0; bool is_element = name->AsArrayIndex(&index); if (is_element) { switch (GetElementsKind()) { case FAST_ELEMENTS: break; - case PIXEL_ELEMENTS: + case EXTERNAL_PIXEL_ELEMENTS: case EXTERNAL_BYTE_ELEMENTS: case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case EXTERNAL_SHORT_ELEMENTS: case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case EXTERNAL_INT_ELEMENTS: case EXTERNAL_UNSIGNED_INT_ELEMENTS: case EXTERNAL_FLOAT_ELEMENTS: // Ignore getters and setters on pixel and external array // elements. - return Heap::undefined_value(); + return heap->undefined_value(); case DICTIONARY_ELEMENTS: { // Lookup the index. NumberDictionary* dictionary = element_dictionary(); int entry = dictionary->FindEntry(index); if (entry != NumberDictionary::kNotFound) { Object* result = dictionary->ValueAt(entry); PropertyDetails details = dictionary->DetailsAt(entry); - if (details.IsReadOnly()) return Heap::undefined_value(); + if (details.IsReadOnly()) return heap->undefined_value(); if (details.type() == CALLBACKS) { if (result->IsFixedArray()) { return result; } // Otherwise allow to override it. @@ -3030,11 +3249,11 @@ } else { // Lookup the name. LookupResult result; LocalLookup(name, &result); if (result.IsProperty()) { - if (result.IsReadOnly()) return Heap::undefined_value(); + if (result.IsReadOnly()) return heap->undefined_value(); if (result.type() == CALLBACKS) { Object* obj = result.GetCallbackObject(); // Need to preserve old getters/setters. if (obj->IsFixedArray()) { // Use set to update attributes. @@ -3044,11 +3263,11 @@ } } // Allocate the fixed array to hold getter and setter. Object* structure; - { MaybeObject* maybe_structure = Heap::AllocateFixedArray(2, TENURED); + { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED); if (!maybe_structure->ToObject(&structure)) return maybe_structure; } if (is_element) { return SetElementCallback(index, structure, attributes); @@ -3058,11 +3277,11 @@ } bool JSObject::CanSetCallback(String* name) { ASSERT(!IsAccessCheckNeeded() - || Top::MayNamedAccess(this, name, v8::ACCESS_SET)); + || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET)); // Check if there is an API defined callback object which prohibits // callback overwriting in this object or it's prototype chain. // This mechanism is needed for instance in a browser setting, where // certain accessors such as window.location should not be allowed @@ -3155,15 +3374,16 @@ MaybeObject* JSObject::DefineAccessor(String* name, bool is_getter, Object* fun, PropertyAttributes attributes) { ASSERT(fun->IsJSFunction() || fun->IsUndefined()); + Isolate* isolate = GetIsolate(); // Check access rights if needed. if (IsAccessCheckNeeded() && - !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); - return Heap::undefined_value(); + !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { + isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); + return isolate->heap()->undefined_value(); } if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); if (proto->IsNull()) return this; @@ -3181,16 +3401,17 @@ return this; } MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { + Isolate* isolate = GetIsolate(); String* name = String::cast(info->name()); // Check access rights if needed. if (IsAccessCheckNeeded() && - !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); - return Heap::undefined_value(); + !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { + isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); + return isolate->heap()->undefined_value(); } if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); if (proto->IsNull()) return this; @@ -3204,34 +3425,34 @@ // Try to flatten before operating on the string. name->TryFlatten(); if (!CanSetCallback(name)) { - return Heap::undefined_value(); + return isolate->heap()->undefined_value(); } uint32_t index = 0; bool is_element = name->AsArrayIndex(&index); if (is_element) { - if (IsJSArray()) return Heap::undefined_value(); + if (IsJSArray()) return isolate->heap()->undefined_value(); // Accessors overwrite previous callbacks (cf. with getters/setters). switch (GetElementsKind()) { case FAST_ELEMENTS: break; - case PIXEL_ELEMENTS: + case EXTERNAL_PIXEL_ELEMENTS: case EXTERNAL_BYTE_ELEMENTS: case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case EXTERNAL_SHORT_ELEMENTS: case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case EXTERNAL_INT_ELEMENTS: case EXTERNAL_UNSIGNED_INT_ELEMENTS: case EXTERNAL_FLOAT_ELEMENTS: // Ignore getters and setters on pixel and external array // elements. - return Heap::undefined_value(); + return isolate->heap()->undefined_value(); case DICTIONARY_ELEMENTS: break; default: UNREACHABLE(); break; @@ -3247,11 +3468,11 @@ LookupResult result; LocalLookup(name, &result); // ES5 forbids turning a property into an accessor if it's not // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5). if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) { - return Heap::undefined_value(); + return isolate->heap()->undefined_value(); } Object* ok; { MaybeObject* maybe_ok = SetPropertyCallback(name, info, info->property_attributes()); if (!maybe_ok->ToObject(&ok)) return maybe_ok; @@ -3261,27 +3482,29 @@ return this; } Object* JSObject::LookupAccessor(String* name, bool is_getter) { + Heap* heap = GetHeap(); + // Make sure that the top context does not change when doing callbacks or // interceptor calls. AssertNoContextChange ncc; // Check access rights if needed. if (IsAccessCheckNeeded() && - !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); - return Heap::undefined_value(); + !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) { + heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); + return heap->undefined_value(); } // Make the lookup and include prototypes. int accessor_index = is_getter ? kGetterIndex : kSetterIndex; uint32_t index = 0; if (name->AsArrayIndex(&index)) { for (Object* obj = this; - obj != Heap::null_value(); + obj != heap->null_value(); obj = JSObject::cast(obj)->GetPrototype()) { JSObject* js_object = JSObject::cast(obj); if (js_object->HasDictionaryElements()) { NumberDictionary* dictionary = js_object->element_dictionary(); int entry = dictionary->FindEntry(index); @@ -3296,26 +3519,26 @@ } } } } else { for (Object* obj = this; - obj != Heap::null_value(); + obj != heap->null_value(); obj = JSObject::cast(obj)->GetPrototype()) { LookupResult result; JSObject::cast(obj)->LocalLookup(name, &result); if (result.IsProperty()) { - if (result.IsReadOnly()) return Heap::undefined_value(); + if (result.IsReadOnly()) return heap->undefined_value(); if (result.type() == CALLBACKS) { Object* obj = result.GetCallbackObject(); if (obj->IsFixedArray()) { return FixedArray::cast(obj)->get(accessor_index); } } } } } - return Heap::undefined_value(); + return heap->undefined_value(); } Object* JSObject::SlowReverseLookup(Object* value) { if (HasFastProperties()) { @@ -3329,31 +3552,33 @@ if (descs->GetConstantFunction(i) == value) { return descs->GetKey(i); } } } - return Heap::undefined_value(); + return GetHeap()->undefined_value(); } else { return property_dictionary()->SlowReverseLookup(value); } } MaybeObject* Map::CopyDropDescriptors() { + Heap* heap = GetHeap(); Object* result; { MaybeObject* maybe_result = - Heap::AllocateMap(instance_type(), instance_size()); + heap->AllocateMap(instance_type(), instance_size()); if (!maybe_result->ToObject(&result)) return maybe_result; } Map::cast(result)->set_prototype(prototype()); Map::cast(result)->set_constructor(constructor()); // Don't copy descriptors, so map transitions always remain a forest. // If we retained the same descriptors we would have two maps // pointing to the same transition which is bad because the garbage // collector relies on being able to reverse pointers from transitions // to maps. If properties need to be retained use CopyDropTransitions. - Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array()); + Map::cast(result)->set_instance_descriptors( + heap->empty_descriptor_array()); // Please note instance_type and instance_size are set when allocated. Map::cast(result)->set_inobject_properties(inobject_properties()); Map::cast(result)->set_unused_property_fields(unused_property_fields()); // If the map has pre-allocated properties always start out with a descriptor @@ -3372,11 +3597,11 @@ pre_allocated_property_fields()); } Map::cast(result)->set_bit_field(bit_field()); Map::cast(result)->set_bit_field2(bit_field2()); Map::cast(result)->set_is_shared(false); - Map::cast(result)->ClearCodeCache(); + Map::cast(result)->ClearCodeCache(heap); return result; } MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, @@ -3386,11 +3611,11 @@ new_instance_size -= inobject_properties() * kPointerSize; } Object* result; { MaybeObject* maybe_result = - Heap::AllocateMap(instance_type(), new_instance_size); + GetHeap()->AllocateMap(instance_type(), new_instance_size); if (!maybe_result->ToObject(&result)) return maybe_result; } if (mode != CLEAR_INOBJECT_PROPERTIES) { Map::cast(result)->set_inobject_properties(inobject_properties()); @@ -3431,11 +3656,11 @@ MaybeObject* Map::UpdateCodeCache(String* name, Code* code) { // Allocate the code cache if not present. if (code_cache()->IsFixedArray()) { Object* result; - { MaybeObject* maybe_result = Heap::AllocateCodeCache(); + { MaybeObject* maybe_result = code->heap()->AllocateCodeCache(); if (!maybe_result->ToObject(&result)) return maybe_result; } set_code_cache(result); } @@ -3447,11 +3672,11 @@ Object* Map::FindInCodeCache(String* name, Code::Flags flags) { // Do a lookup if a code cache exists. if (!code_cache()->IsFixedArray()) { return CodeCache::cast(code_cache())->Lookup(name, flags); } else { - return Heap::undefined_value(); + return GetHeap()->undefined_value(); } } int Map::IndexInCodeCache(Object* name, Code* code) { @@ -3471,16 +3696,17 @@ } void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { Map* current = this; - while (current != Heap::meta_map()) { + Map* meta_map = heap()->meta_map(); + while (current != meta_map) { DescriptorArray* d = reinterpret_cast<DescriptorArray*>( *RawField(current, Map::kInstanceDescriptorsOffset)); - if (d == Heap::empty_descriptor_array()) { + if (d == heap()->empty_descriptor_array()) { Map* prev = current->map(); - current->set_map(Heap::meta_map()); + current->set_map(meta_map); callback(current, data); current = prev; continue; } @@ -3501,13 +3727,13 @@ map_done = false; break; } } if (!map_done) continue; - *map_or_index_field = Heap::fixed_array_map(); + *map_or_index_field = heap()->fixed_array_map(); Map* prev = current->map(); - current->set_map(Heap::meta_map()); + current->set_map(meta_map); callback(current, data); current = prev; } } @@ -3630,20 +3856,20 @@ if (code->flags() == flags) { return code; } } } - return Heap::undefined_value(); + return GetHeap()->undefined_value(); } Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) { if (!normal_type_cache()->IsUndefined()) { CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache()); return cache->Lookup(name, flags); } else { - return Heap::undefined_value(); + return GetHeap()->undefined_value(); } } int CodeCache::GetIndex(Object* name, Code* code) { @@ -3721,11 +3947,11 @@ } MUST_USE_RESULT MaybeObject* AsObject() { ASSERT(code_ != NULL); Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateFixedArray(2); + { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* pair = FixedArray::cast(obj); pair->set(0, name_); pair->set(1, code_); @@ -3740,11 +3966,11 @@ Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) { CodeCacheHashTableKey key(name, flags); int entry = FindEntry(&key); - if (entry == kNotFound) return Heap::undefined_value(); + if (entry == kNotFound) return GetHeap()->undefined_value(); return get(EntryToIndex(entry) + 1); } MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) { @@ -3777,12 +4003,13 @@ } void CodeCacheHashTable::RemoveByIndex(int index) { ASSERT(index >= 0); - set(EntryToIndex(index), Heap::null_value()); - set(EntryToIndex(index) + 1, Heap::null_value()); + Heap* heap = GetHeap(); + set(EntryToIndex(index), heap->null_value()); + set(EntryToIndex(index) + 1, heap->null_value()); ElementRemoved(); } static bool HasKey(FixedArray* array, Object* key) { @@ -3798,21 +4025,21 @@ return false; } MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { - ASSERT(!array->HasPixelElements() && !array->HasExternalArrayElements()); + ASSERT(!array->HasExternalArrayElements()); switch (array->GetElementsKind()) { case JSObject::FAST_ELEMENTS: return UnionOfKeys(FixedArray::cast(array->elements())); case JSObject::DICTIONARY_ELEMENTS: { NumberDictionary* dict = array->element_dictionary(); int size = dict->NumberOfElements(); // Allocate a temporary fixed array. Object* object; - { MaybeObject* maybe_object = Heap::AllocateFixedArray(size); + { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size); if (!maybe_object->ToObject(&object)) return maybe_object; } FixedArray* key_array = FixedArray::cast(object); int capacity = dict->Capacity(); @@ -3828,11 +4055,11 @@ } default: UNREACHABLE(); } UNREACHABLE(); - return Heap::null_value(); // Failure case needs to "return" a value. + return GetHeap()->null_value(); // Failure case needs to "return" a value. } MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) { int len0 = length(); @@ -3858,11 +4085,11 @@ if (extra == 0) return this; // Allocate the result Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateFixedArray(len0 + extra); + { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } // Fill in the content AssertNoAllocation no_gc; FixedArray* result = FixedArray::cast(obj); @@ -3887,13 +4114,14 @@ return result; } MaybeObject* FixedArray::CopySize(int new_length) { - if (new_length == 0) return Heap::empty_fixed_array(); + Heap* heap = GetHeap(); + if (new_length == 0) return heap->empty_fixed_array(); Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateFixedArray(new_length); + { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* result = FixedArray::cast(obj); // Copy the content AssertNoAllocation no_gc; @@ -3927,25 +4155,26 @@ } #endif MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) { + Heap* heap = Isolate::Current()->heap(); if (number_of_descriptors == 0) { - return Heap::empty_descriptor_array(); + return heap->empty_descriptor_array(); } // Allocate the array of keys. Object* array; { MaybeObject* maybe_array = - Heap::AllocateFixedArray(ToKeyIndex(number_of_descriptors)); + heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors)); if (!maybe_array->ToObject(&array)) return maybe_array; } // Do not use DescriptorArray::cast on incomplete object. FixedArray* result = FixedArray::cast(array); // Allocate the content array and set it in the descriptor array. { MaybeObject* maybe_array = - Heap::AllocateFixedArray(number_of_descriptors << 1); + heap->AllocateFixedArray(number_of_descriptors << 1); if (!maybe_array->ToObject(&array)) return maybe_array; } result->set(kContentArrayIndex, array); result->set(kEnumerationIndexIndex, Smi::FromInt(PropertyDetails::kInitialIndex)); @@ -4210,19 +4439,19 @@ MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count, PretenureFlag pretenure) { ASSERT(deopt_entry_count > 0); - return Heap::AllocateFixedArray(LengthFor(deopt_entry_count), + return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count), pretenure); } MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points, PretenureFlag pretenure) { - if (number_of_deopt_points == 0) return Heap::empty_fixed_array(); - return Heap::AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points), + if (number_of_deopt_points == 0) return HEAP->empty_fixed_array(); + return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points), pretenure); } #ifdef DEBUG @@ -4236,27 +4465,26 @@ return GetContentArray()->IsEqualTo(other->GetContentArray()); } #endif -static StaticResource<StringInputBuffer> string_input_buffer; - - bool String::LooksValid() { - if (!Heap::Contains(this)) return false; + if (!Isolate::Current()->heap()->Contains(this)) return false; return true; } int String::Utf8Length() { if (IsAsciiRepresentation()) return length(); // Attempt to flatten before accessing the string. It probably // doesn't make Utf8Length faster, but it is very likely that // the string will be accessed later (for example by WriteUtf8) // so it's still a good idea. + Heap* heap = GetHeap(); TryFlatten(); - Access<StringInputBuffer> buffer(&string_input_buffer); + Access<StringInputBuffer> buffer( + heap->isolate()->objects_string_input_buffer()); buffer->Reset(0, this); int result = 0; while (buffer->has_more()) result += unibrow::Utf8::Length(buffer->GetNext()); return result; @@ -4318,20 +4546,21 @@ SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls, RobustnessFlag robust_flag, int offset, int length, int* length_return) { - ASSERT(NativeAllocationChecker::allocation_allowed()); if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { return SmartPointer<char>(NULL); } + Heap* heap = GetHeap(); // Negative length means the to the end of the string. if (length < 0) length = kMaxInt - offset; // Compute the size of the UTF-8 string. Start at the specified offset. - Access<StringInputBuffer> buffer(&string_input_buffer); + Access<StringInputBuffer> buffer( + heap->isolate()->objects_string_input_buffer()); buffer->Reset(offset, this); int character_position = offset; int utf8_bytes = 0; while (buffer->has_more()) { uint16_t character = buffer->GetNext(); @@ -4396,17 +4625,17 @@ return NULL; } SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) { - ASSERT(NativeAllocationChecker::allocation_allowed()); - if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) { return SmartPointer<uc16>(); } + Heap* heap = GetHeap(); - Access<StringInputBuffer> buffer(&string_input_buffer); + Access<StringInputBuffer> buffer( + heap->isolate()->objects_string_input_buffer()); buffer->Reset(this); uc16* result = NewArray<uc16>(length() + 1); int i = 0; @@ -4685,39 +4914,39 @@ UNREACHABLE(); return 0; } -Relocatable* Relocatable::top_ = NULL; - - void Relocatable::PostGarbageCollectionProcessing() { - Relocatable* current = top_; + Isolate* isolate = Isolate::Current(); + Relocatable* current = isolate->relocatable_top(); while (current != NULL) { current->PostGarbageCollection(); current = current->prev_; } } // Reserve space for statics needing saving and restoring. int Relocatable::ArchiveSpacePerThread() { - return sizeof(top_); + return sizeof(Isolate::Current()->relocatable_top()); } // Archive statics that are thread local. char* Relocatable::ArchiveState(char* to) { - *reinterpret_cast<Relocatable**>(to) = top_; - top_ = NULL; + Isolate* isolate = Isolate::Current(); + *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top(); + isolate->set_relocatable_top(NULL); return to + ArchiveSpacePerThread(); } // Restore statics that are thread local. char* Relocatable::RestoreState(char* from) { - top_ = *reinterpret_cast<Relocatable**>(from); + Isolate* isolate = Isolate::Current(); + isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from)); return from + ArchiveSpacePerThread(); } char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) { @@ -4726,11 +4955,12 @@ return thread_storage + ArchiveSpacePerThread(); } void Relocatable::Iterate(ObjectVisitor* v) { - Iterate(v, top_); + Isolate* isolate = Isolate::Current(); + Iterate(v, isolate->relocatable_top()); } void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) { Relocatable* current = top; @@ -4739,19 +4969,21 @@ current = current->prev_; } } -FlatStringReader::FlatStringReader(Handle<String> str) - : str_(str.location()), +FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str) + : Relocatable(isolate), + str_(str.location()), length_(str->length()) { PostGarbageCollection(); } -FlatStringReader::FlatStringReader(Vector<const char> input) - : str_(0), +FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input) + : Relocatable(isolate), + str_(0), is_ascii_(true), length_(input.length()), start_(input.start()) { } @@ -5077,33 +5309,30 @@ } return true; } -static StringInputBuffer string_compare_buffer_b; - - template <typename IteratorA> -static inline bool CompareStringContentsPartial(IteratorA* ia, String* b) { +static inline bool CompareStringContentsPartial(Isolate* isolate, + IteratorA* ia, + String* b) { if (b->IsFlat()) { if (b->IsAsciiRepresentation()) { VectorIterator<char> ib(b->ToAsciiVector()); return CompareStringContents(ia, &ib); } else { VectorIterator<uc16> ib(b->ToUC16Vector()); return CompareStringContents(ia, &ib); } } else { - string_compare_buffer_b.Reset(0, b); - return CompareStringContents(ia, &string_compare_buffer_b); + isolate->objects_string_compare_buffer_b()->Reset(0, b); + return CompareStringContents(ia, + isolate->objects_string_compare_buffer_b()); } } -static StringInputBuffer string_compare_buffer_a; - - bool String::SlowEquals(String* other) { // Fast check: negative check with lengths. int len = length(); if (len != other->length()) return false; if (len == 0) return true; @@ -5127,10 +5356,11 @@ const char* str2 = SeqAsciiString::cast(rhs)->GetChars(); return CompareRawStringContents(Vector<const char>(str1, len), Vector<const char>(str2, len)); } + Isolate* isolate = GetIsolate(); if (lhs->IsFlat()) { if (lhs->IsAsciiRepresentation()) { Vector<const char> vec1 = lhs->ToAsciiVector(); if (rhs->IsFlat()) { if (rhs->IsAsciiRepresentation()) { @@ -5141,12 +5371,13 @@ VectorIterator<uc16> ib(rhs->ToUC16Vector()); return CompareStringContents(&buf1, &ib); } } else { VectorIterator<char> buf1(vec1); - string_compare_buffer_b.Reset(0, rhs); - return CompareStringContents(&buf1, &string_compare_buffer_b); + isolate->objects_string_compare_buffer_b()->Reset(0, rhs); + return CompareStringContents(&buf1, + isolate->objects_string_compare_buffer_b()); } } else { Vector<const uc16> vec1 = lhs->ToUC16Vector(); if (rhs->IsFlat()) { if (rhs->IsAsciiRepresentation()) { @@ -5157,41 +5388,45 @@ Vector<const uc16> vec2(rhs->ToUC16Vector()); return CompareRawStringContents(vec1, vec2); } } else { VectorIterator<uc16> buf1(vec1); - string_compare_buffer_b.Reset(0, rhs); - return CompareStringContents(&buf1, &string_compare_buffer_b); + isolate->objects_string_compare_buffer_b()->Reset(0, rhs); + return CompareStringContents(&buf1, + isolate->objects_string_compare_buffer_b()); } } } else { - string_compare_buffer_a.Reset(0, lhs); - return CompareStringContentsPartial(&string_compare_buffer_a, rhs); + isolate->objects_string_compare_buffer_a()->Reset(0, lhs); + return CompareStringContentsPartial(isolate, + isolate->objects_string_compare_buffer_a(), rhs); } } bool String::MarkAsUndetectable() { if (StringShape(this).IsSymbol()) return false; Map* map = this->map(); - if (map == Heap::string_map()) { - this->set_map(Heap::undetectable_string_map()); + Heap* heap = map->heap(); + if (map == heap->string_map()) { + this->set_map(heap->undetectable_string_map()); return true; - } else if (map == Heap::ascii_string_map()) { - this->set_map(Heap::undetectable_ascii_string_map()); + } else if (map == heap->ascii_string_map()) { + this->set_map(heap->undetectable_ascii_string_map()); return true; } // Rest cannot be marked as undetectable return false; } bool String::IsEqualTo(Vector<const char> str) { + Isolate* isolate = GetIsolate(); int slen = length(); Access<ScannerConstants::Utf8Decoder> - decoder(ScannerConstants::utf8_decoder()); + decoder(isolate->scanner_constants()->utf8_decoder()); decoder->Reset(str.start(), str.length()); int i; for (i = 0; i < slen && decoder->has_more(); i++) { uc32 r = decoder->GetNext(); if (Get(i) != r) return false; @@ -5218,26 +5453,10 @@ } return true; } -template <typename schar> -static inline uint32_t HashSequentialString(const schar* chars, int length) { - StringHasher hasher(length); - if (!hasher.has_trivial_hash()) { - int i; - for (i = 0; hasher.is_array_index() && (i < length); i++) { - hasher.AddCharacter(chars[i]); - } - for (; i < length; i++) { - hasher.AddCharacterNoIndex(chars[i]); - } - } - return hasher.GetHashField(); -} - - uint32_t String::ComputeAndSetHash() { // Should only be called if hash code has not yet been computed. ASSERT(!HasHashCode()); const int len = length(); @@ -5365,12 +5584,13 @@ return hasher.GetHashField(); } MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) { + Heap* heap = GetHeap(); if (start == 0 && end == length()) return this; - MaybeObject* result = Heap::AllocateSubString(this, start, end, pretenure); + MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure); return result; } void String::PrintOn(FILE* file) { @@ -5383,10 +5603,11 @@ void Map::CreateBackPointers() { DescriptorArray* descriptors = instance_descriptors(); for (int i = 0; i < descriptors->number_of_descriptors(); i++) { if (descriptors->GetType(i) == MAP_TRANSITION || + descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION || descriptors->GetType(i) == CONSTANT_TRANSITION) { // Get target. Map* target = Map::cast(descriptors->GetValue(i)); #ifdef DEBUG // Verify target. @@ -5406,16 +5627,16 @@ } } } -void Map::ClearNonLiveTransitions(Object* real_prototype) { +void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { // Live DescriptorArray objects will be marked, so we must use // low-level accessors to get and modify their data. DescriptorArray* d = reinterpret_cast<DescriptorArray*>( *RawField(this, Map::kInstanceDescriptorsOffset)); - if (d == Heap::raw_unchecked_empty_descriptor_array()) return; + if (d == heap->raw_unchecked_empty_descriptor_array()) return; Smi* NullDescriptorDetails = PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); FixedArray* contents = reinterpret_cast<FixedArray*>( d->get(DescriptorArray::kContentArrayIndex)); ASSERT(contents->length() >= 2); @@ -5425,17 +5646,18 @@ // Also drop the back pointer for that map transition, so that this // map is not reached again by following a back pointer from a // non-live object. PropertyDetails details(Smi::cast(contents->get(i + 1))); if (details.type() == MAP_TRANSITION || + details.type() == EXTERNAL_ARRAY_TRANSITION || details.type() == CONSTANT_TRANSITION) { Map* target = reinterpret_cast<Map*>(contents->get(i)); ASSERT(target->IsHeapObject()); if (!target->IsMarked()) { ASSERT(target->IsMap()); contents->set_unchecked(i + 1, NullDescriptorDetails); - contents->set_null_unchecked(i); + contents->set_null_unchecked(heap, i); ASSERT(target->prototype() == this || target->prototype() == real_prototype); // Getter prototype() is read-only, set_prototype() has side effects. *RawField(target, Map::kPrototypeOffset) = real_prototype; } @@ -5455,11 +5677,12 @@ void JSFunction::MarkForLazyRecompilation() { ASSERT(is_compiled() && !IsOptimized()); ASSERT(shared()->allows_lazy_compilation() || code()->optimizable()); - ReplaceCode(Builtins::builtin(Builtins::LazyRecompile)); + Builtins* builtins = GetIsolate()->builtins(); + ReplaceCode(builtins->builtin(Builtins::kLazyRecompile)); } uint32_t JSFunction::SourceHash() { uint32_t hash = 0; @@ -5474,32 +5697,34 @@ } bool JSFunction::IsInlineable() { if (IsBuiltin()) return false; + SharedFunctionInfo* shared_info = shared(); // Check that the function has a script associated with it. - if (!shared()->script()->IsScript()) return false; - Code* code = shared()->code(); + if (!shared_info->script()->IsScript()) return false; + if (shared_info->optimization_disabled()) return false; + Code* code = shared_info->code(); if (code->kind() == Code::OPTIMIZED_FUNCTION) return true; // If we never ran this (unlikely) then lets try to optimize it. if (code->kind() != Code::FUNCTION) return true; return code->optimizable(); } Object* JSFunction::SetInstancePrototype(Object* value) { ASSERT(value->IsJSObject()); - + Heap* heap = GetHeap(); if (has_initial_map()) { initial_map()->set_prototype(value); } else { // Put the value in the initial map field until an initial map is // needed. At that point, a new initial map is created and the // prototype is put into the initial map where it belongs. set_prototype_or_initial_map(value); } - Heap::ClearInstanceofCache(); + heap->ClearInstanceofCache(); return value; } MaybeObject* JSFunction::SetPrototype(Object* value) { @@ -5512,31 +5737,47 @@ // See ECMA-262 13.2.2. if (!value->IsJSObject()) { // Copy the map so this does not affect unrelated functions. // Remove map transitions because they point to maps with a // different prototype. - Object* new_map; + Object* new_object; { MaybeObject* maybe_new_map = map()->CopyDropTransitions(); - if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; + if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map; } - set_map(Map::cast(new_map)); - map()->set_constructor(value); - map()->set_non_instance_prototype(true); + Map* new_map = Map::cast(new_object); + Heap* heap = new_map->heap(); + set_map(new_map); + new_map->set_constructor(value); + new_map->set_non_instance_prototype(true); construct_prototype = - Top::context()->global_context()->initial_object_prototype(); + heap->isolate()->context()->global_context()-> + initial_object_prototype(); } else { map()->set_non_instance_prototype(false); } return SetInstancePrototype(construct_prototype); } Object* JSFunction::RemovePrototype() { - ASSERT(map() == context()->global_context()->function_map()); - set_map(context()->global_context()->function_without_prototype_map()); - set_prototype_or_initial_map(Heap::the_hole_value()); + Context* global_context = context()->global_context(); + Map* no_prototype_map = shared()->strict_mode() + ? global_context->strict_mode_function_without_prototype_map() + : global_context->function_without_prototype_map(); + + if (map() == no_prototype_map) { + // Be idempotent. + return this; + } + + ASSERT(!shared()->strict_mode() || + map() == global_context->strict_mode_function_map()); + ASSERT(shared()->strict_mode() || map() == global_context->function_map()); + + set_map(no_prototype_map); + set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value()); return this; } Object* JSFunction::SetInstanceClassName(String* name) { @@ -5554,17 +5795,21 @@ Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) { return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex)); } -MaybeObject* Oddball::Initialize(const char* to_string, Object* to_number) { +MaybeObject* Oddball::Initialize(const char* to_string, + Object* to_number, + byte kind) { Object* symbol; - { MaybeObject* maybe_symbol = Heap::LookupAsciiSymbol(to_string); + { MaybeObject* maybe_symbol = + Isolate::Current()->heap()->LookupAsciiSymbol(to_string); if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol; } set_to_string(String::cast(symbol)); set_to_number(to_number); + set_kind(kind); return this; } String* SharedFunctionInfo::DebugName() { @@ -5579,14 +5824,15 @@ !reinterpret_cast<Script*>(script())->source()->IsUndefined(); } Object* SharedFunctionInfo::GetSourceCode() { - if (!HasSourceCode()) return Heap::undefined_value(); - HandleScope scope; + Isolate* isolate = GetIsolate(); + if (!HasSourceCode()) return isolate->heap()->undefined_value(); + HandleScope scope(isolate); Object* source = Script::cast(script())->source(); - return *SubString(Handle<String>(String::cast(source)), + return *SubString(Handle<String>(String::cast(source), isolate), start_position(), end_position()); } int SharedFunctionInfo::SourceSize() { @@ -5622,14 +5868,16 @@ if (!prototype->IsJSObject()) { ASSERT(prototype->IsNull()); return true; } + Heap* heap = GetHeap(); + // Traverse the proposed prototype chain looking for setters for properties of // the same names as are set by the inline constructor. for (Object* obj = prototype; - obj != Heap::null_value(); + obj != heap->null_value(); obj = obj->GetPrototype()) { JSObject* js_object = JSObject::cast(obj); for (int i = 0; i < this_property_assignments_count(); i++) { LookupResult result; String* name = GetThisPropertyAssignmentName(i); @@ -5661,14 +5909,15 @@ set_this_property_assignments_count(assignments->length() / 3); } void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() { + Heap* heap = GetHeap(); set_compiler_hints(BooleanBit::set(compiler_hints(), kHasOnlySimpleThisPropertyAssignments, false)); - set_this_property_assignments(Heap::undefined_value()); + set_this_property_assignments(heap->undefined_value()); set_this_property_assignments_count(0); } String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) { @@ -5809,13 +6058,14 @@ // by GC, keep it. if (construction_count() == 0) { set_construction_count(kGenerousAllocationCount); } set_initial_map(map); - ASSERT_EQ(Builtins::builtin(Builtins::JSConstructStubGeneric), + Builtins* builtins = map->heap()->isolate()->builtins(); + ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric), construct_stub()); - set_construct_stub(Builtins::builtin(Builtins::JSConstructStubCountdown)); + set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown)); } // Called from GC, hence reinterpret_cast and unchecked accessors. void SharedFunctionInfo::DetachInitialMap() { @@ -5828,14 +6078,15 @@ // Undo state changes made by StartInobjectTracking (except the // construction_count). This way if the initial map does not survive the GC // then StartInobjectTracking will be called again the next time the // constructor is called. The countdown will continue and (possibly after // several more GCs) CompleteInobjectSlackTracking will eventually be called. - set_initial_map(Heap::raw_unchecked_undefined_value()); - ASSERT_EQ(Builtins::builtin(Builtins::JSConstructStubCountdown), + set_initial_map(map->heap()->raw_unchecked_undefined_value()); + Builtins* builtins = map->heap()->isolate()->builtins(); + ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), *RawField(this, kConstructStubOffset)); - set_construct_stub(Builtins::builtin(Builtins::JSConstructStubGeneric)); + set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); // It is safe to clear the flag: it will be set again if the map is live. set_live_objects_may_exist(false); } @@ -5844,13 +6095,14 @@ map->set_bit_field2( map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo)); // Resume inobject slack tracking. set_initial_map(map); - ASSERT_EQ(Builtins::builtin(Builtins::JSConstructStubGeneric), + Builtins* builtins = map->heap()->isolate()->builtins(); + ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric), *RawField(this, kConstructStubOffset)); - set_construct_stub(Builtins::builtin(Builtins::JSConstructStubCountdown)); + set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown)); // The map survived the gc, so there may be objects referencing it. set_live_objects_may_exist(true); } @@ -5875,14 +6127,16 @@ void SharedFunctionInfo::CompleteInobjectSlackTracking() { ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress()); Map* map = Map::cast(initial_map()); - set_initial_map(Heap::undefined_value()); - ASSERT_EQ(Builtins::builtin(Builtins::JSConstructStubCountdown), + Heap* heap = map->heap(); + set_initial_map(heap->undefined_value()); + Builtins* builtins = heap->isolate()->builtins(); + ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), construct_stub()); - set_construct_stub(Builtins::builtin(Builtins::JSConstructStubGeneric)); + set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); int slack = map->unused_property_fields(); map->TraverseTransitionTree(&GetMinInobjectSlack, &slack); if (slack != 0) { // Resize the initial map and all maps in its transition tree. @@ -5935,12 +6189,11 @@ CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target. } void Code::InvalidateRelocation() { - HandleScope scope; - set_relocation_info(Heap::empty_byte_array()); + set_relocation_info(heap()->empty_byte_array()); } void Code::Relocate(intptr_t delta) { for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) { @@ -6230,12 +6483,14 @@ case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION"; case STUB: return "STUB"; case BUILTIN: return "BUILTIN"; case LOAD_IC: return "LOAD_IC"; case KEYED_LOAD_IC: return "KEYED_LOAD_IC"; + case KEYED_EXTERNAL_ARRAY_LOAD_IC: return "KEYED_EXTERNAL_ARRAY_LOAD_IC"; case STORE_IC: return "STORE_IC"; case KEYED_STORE_IC: return "KEYED_STORE_IC"; + case KEYED_EXTERNAL_ARRAY_STORE_IC: return "KEYED_EXTERNAL_ARRAY_STORE_IC"; case CALL_IC: return "CALL_IC"; case KEYED_CALL_IC: return "KEYED_CALL_IC"; case BINARY_OP_IC: return "BINARY_OP_IC"; case TYPE_RECORDING_BINARY_OP_IC: return "TYPE_RECORDING_BINARY_OP_IC"; case COMPARE_IC: return "COMPARE_IC"; @@ -6266,10 +6521,11 @@ case FIELD: return "FIELD"; case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION"; case CALLBACKS: return "CALLBACKS"; case INTERCEPTOR: return "INTERCEPTOR"; case MAP_TRANSITION: return "MAP_TRANSITION"; + case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION"; case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION"; case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR"; } UNREACHABLE(); return NULL; @@ -6283,11 +6539,12 @@ if (extra == STRING_INDEX_OUT_OF_BOUNDS) { name = "STRING_INDEX_OUT_OF_BOUNDS"; } break; case STORE_IC: - if (extra == StoreIC::kStoreICStrict) { + case KEYED_STORE_IC: + if (extra == kStrictMode) { name = "STRICT"; } break; default: break; @@ -6379,15 +6636,16 @@ #endif // ENABLE_DISASSEMBLER MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, int length) { + Heap* heap = GetHeap(); // We should never end in here with a pixel or external array. - ASSERT(!HasPixelElements() && !HasExternalArrayElements()); + ASSERT(!HasExternalArrayElements()); Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateFixedArrayWithHoles(capacity); + { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* elems = FixedArray::cast(obj); { MaybeObject* maybe_obj = map()->GetFastElementsMap(); @@ -6434,11 +6692,11 @@ } MaybeObject* JSObject::SetSlowElements(Object* len) { // We should never end in here with a pixel or external array. - ASSERT(!HasPixelElements() && !HasExternalArrayElements()); + ASSERT(!HasExternalArrayElements()); uint32_t new_length = static_cast<uint32_t>(len->Number()); switch (GetElementsKind()) { case FAST_ELEMENTS: { @@ -6470,18 +6728,19 @@ return this; } MaybeObject* JSArray::Initialize(int capacity) { + Heap* heap = GetHeap(); ASSERT(capacity >= 0); set_length(Smi::FromInt(0)); FixedArray* new_elements; if (capacity == 0) { - new_elements = Heap::empty_fixed_array(); + new_elements = heap->empty_fixed_array(); } else { Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateFixedArrayWithHoles(capacity); + { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } new_elements = FixedArray::cast(obj); } set_elements(new_elements); @@ -6492,28 +6751,22 @@ void JSArray::Expand(int required_size) { Handle<JSArray> self(this); Handle<FixedArray> old_backing(FixedArray::cast(elements())); int old_size = old_backing->length(); int new_size = required_size > old_size ? required_size : old_size; - Handle<FixedArray> new_backing = Factory::NewFixedArray(new_size); + Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size); // Can't use this any more now because we may have had a GC! for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i)); self->SetContent(*new_backing); } -// Computes the new capacity when expanding the elements of a JSObject. -static int NewElementsCapacity(int old_capacity) { - // (old_capacity + 50%) + 16 - return old_capacity + (old_capacity >> 1) + 16; -} - - -static Failure* ArrayLengthRangeError() { +static Failure* ArrayLengthRangeError(Heap* heap) { HandleScope scope; - return Top::Throw(*Factory::NewRangeError("invalid_array_length", - HandleVector<Object>(NULL, 0))); + return heap->isolate()->Throw( + *FACTORY->NewRangeError("invalid_array_length", + HandleVector<Object>(NULL, 0))); } MaybeObject* JSObject::SetElementsLength(Object* len) { // We should never end in here with a pixel or external array. @@ -6521,11 +6774,11 @@ MaybeObject* maybe_smi_length = len->ToSmi(); Object* smi_length = Smi::FromInt(0); if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) { const int value = Smi::cast(smi_length)->value(); - if (value < 0) return ArrayLengthRangeError(); + if (value < 0) return ArrayLengthRangeError(GetHeap()); switch (GetElementsKind()) { case FAST_ELEMENTS: { int old_capacity = FixedArray::cast(elements())->length(); if (value <= old_capacity) { if (IsJSArray()) { @@ -6587,18 +6840,18 @@ if (len->IsNumber()) { uint32_t length; if (len->ToArrayIndex(&length)) { return SetSlowElements(len); } else { - return ArrayLengthRangeError(); + return ArrayLengthRangeError(GetHeap()); } } // len is not a number so make the array size one and // set only element to len. Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateFixedArray(1); + { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray::cast(obj)->set(0, len); if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); set_elements(FixedArray::cast(obj)); @@ -6606,24 +6859,25 @@ } MaybeObject* JSObject::SetPrototype(Object* value, bool skip_hidden_prototypes) { + Heap* heap = GetHeap(); // Silently ignore the change if value is not a JSObject or null. // SpiderMonkey behaves this way. if (!value->IsJSObject() && !value->IsNull()) return value; // Before we can set the prototype we need to be sure // prototype cycles are prevented. // It is sufficient to validate that the receiver is not in the new prototype // chain. - for (Object* pt = value; pt != Heap::null_value(); pt = pt->GetPrototype()) { + for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) { if (JSObject::cast(pt) == this) { // Cycle detected. HandleScope scope; - return Top::Throw(*Factory::NewError("cyclic_proto", - HandleVector<Object>(NULL, 0))); + return heap->isolate()->Throw( + *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0))); } } JSObject* real_receiver = this; @@ -6644,11 +6898,11 @@ if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; } Map::cast(new_map)->set_prototype(value); real_receiver->set_map(Map::cast(new_map)); - Heap::ClearInstanceofCache(); + heap->ClearInstanceofCache(); return value; } @@ -6663,12 +6917,12 @@ !FixedArray::cast(elements())->get(index)->IsTheHole()) { return true; } break; } - case PIXEL_ELEMENTS: { - PixelArray* pixels = PixelArray::cast(elements()); + case EXTERNAL_PIXEL_ELEMENTS: { + ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); if (index < static_cast<uint32_t>(pixels->length())) { return true; } break; } @@ -6699,61 +6953,66 @@ // Handle [] on String objects. if (this->IsStringObjectWithCharacterAt(index)) return true; Object* pt = GetPrototype(); - if (pt == Heap::null_value()) return false; + if (pt->IsNull()) return false; return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); } bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) { + Isolate* isolate = GetIsolate(); // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; - HandleScope scope; + HandleScope scope(isolate); Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); Handle<JSObject> receiver_handle(receiver); Handle<JSObject> holder_handle(this); - CustomArguments args(interceptor->data(), receiver, this); + CustomArguments args(isolate, interceptor->data(), receiver, this); v8::AccessorInfo info(args.end()); if (!interceptor->query()->IsUndefined()) { v8::IndexedPropertyQuery query = v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query()); - LOG(ApiIndexedPropertyAccess("interceptor-indexed-has", this, index)); + LOG(isolate, + ApiIndexedPropertyAccess("interceptor-indexed-has", this, index)); v8::Handle<v8::Integer> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); result = query(index, info); } if (!result.IsEmpty()) { ASSERT(result->IsInt32()); return true; // absence of property is signaled by empty handle. } } else if (!interceptor->getter()->IsUndefined()) { v8::IndexedPropertyGetter getter = v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); - LOG(ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index)); + LOG(isolate, + ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index)); v8::Handle<v8::Value> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); result = getter(index, info); } if (!result.IsEmpty()) return true; } return holder_handle->HasElementPostInterceptor(*receiver_handle, index); } JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) { // Check access rights if needed. - if (IsAccessCheckNeeded() && - !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); - return UNDEFINED_ELEMENT; + if (IsAccessCheckNeeded()) { + Heap* heap = GetHeap(); + if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { + heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); + return UNDEFINED_ELEMENT; + } } if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); if (proto->IsNull()) return UNDEFINED_ELEMENT; @@ -6782,12 +7041,12 @@ !FixedArray::cast(elements())->get(index)->IsTheHole()) { return FAST_ELEMENT; } break; } - case PIXEL_ELEMENTS: { - PixelArray* pixels = PixelArray::cast(elements()); + case EXTERNAL_PIXEL_ELEMENTS: { + ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT; break; } case EXTERNAL_BYTE_ELEMENTS: case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: @@ -6816,14 +7075,16 @@ } bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) { // Check access rights if needed. - if (IsAccessCheckNeeded() && - !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); - return false; + if (IsAccessCheckNeeded()) { + Heap* heap = GetHeap(); + if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { + heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); + return false; + } } // Check for lookup interceptor if (HasIndexedInterceptor()) { return HasElementWithInterceptor(receiver, index); @@ -6837,12 +7098,12 @@ static_cast<uint32_t>(FixedArray::cast(elements())->length()); if ((index < length) && !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; break; } - case PIXEL_ELEMENTS: { - PixelArray* pixels = PixelArray::cast(elements()); + case EXTERNAL_PIXEL_ELEMENTS: { + ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); if (index < static_cast<uint32_t>(pixels->length())) { return true; } break; } @@ -6873,76 +7134,81 @@ // Handle [] on String objects. if (this->IsStringObjectWithCharacterAt(index)) return true; Object* pt = GetPrototype(); - if (pt == Heap::null_value()) return false; + if (pt->IsNull()) return false; return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); } MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index, Object* value, + StrictModeFlag strict_mode, bool check_prototype) { + Isolate* isolate = GetIsolate(); // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; - HandleScope scope; + HandleScope scope(isolate); Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); Handle<JSObject> this_handle(this); - Handle<Object> value_handle(value); + Handle<Object> value_handle(value, isolate); if (!interceptor->setter()->IsUndefined()) { v8::IndexedPropertySetter setter = v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter()); - LOG(ApiIndexedPropertyAccess("interceptor-indexed-set", this, index)); - CustomArguments args(interceptor->data(), this, this); + LOG(isolate, + ApiIndexedPropertyAccess("interceptor-indexed-set", this, index)); + CustomArguments args(isolate, interceptor->data(), this, this); v8::AccessorInfo info(args.end()); v8::Handle<v8::Value> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); result = setter(index, v8::Utils::ToLocal(value_handle), info); } - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); if (!result.IsEmpty()) return *value_handle; } MaybeObject* raw_result = this_handle->SetElementWithoutInterceptor(index, *value_handle, + strict_mode, check_prototype); - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); return raw_result; } MaybeObject* JSObject::GetElementWithCallback(Object* receiver, Object* structure, uint32_t index, Object* holder) { + Isolate* isolate = GetIsolate(); ASSERT(!structure->IsProxy()); // api style callbacks. if (structure->IsAccessorInfo()) { AccessorInfo* data = AccessorInfo::cast(structure); Object* fun_obj = data->getter(); v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); - HandleScope scope; + HandleScope scope(isolate); Handle<JSObject> self(JSObject::cast(receiver)); Handle<JSObject> holder_handle(JSObject::cast(holder)); - Handle<Object> number = Factory::NewNumberFromUint(index); - Handle<String> key(Factory::NumberToString(number)); - LOG(ApiNamedPropertyAccess("load", *self, *key)); - CustomArguments args(data->data(), *self, *holder_handle); + Handle<Object> number = isolate->factory()->NewNumberFromUint(index); + Handle<String> key(isolate->factory()->NumberToString(number)); + LOG(isolate, ApiNamedPropertyAccess("load", *self, *key)); + CustomArguments args(isolate, data->data(), *self, *holder_handle); v8::AccessorInfo info(args.end()); v8::Handle<v8::Value> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); result = call_fun(v8::Utils::ToLocal(key), info); } - RETURN_IF_SCHEDULED_EXCEPTION(); - if (result.IsEmpty()) return Heap::undefined_value(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); + if (result.IsEmpty()) return isolate->heap()->undefined_value(); return *v8::Utils::OpenHandle(*result); } // __defineGetter__ callback if (structure->IsFixedArray()) { @@ -6950,11 +7216,11 @@ if (getter->IsJSFunction()) { return Object::GetPropertyWithDefinedGetter(receiver, JSFunction::cast(getter)); } // Getter is not a function. - return Heap::undefined_value(); + return isolate->heap()->undefined_value(); } UNREACHABLE(); return NULL; } @@ -6962,16 +7228,17 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure, uint32_t index, Object* value, JSObject* holder) { - HandleScope scope; + Isolate* isolate = GetIsolate(); + HandleScope scope(isolate); // We should never get here to initialize a const with the hole // value since a const declaration would conflict with the setter. ASSERT(!value->IsTheHole()); - Handle<Object> value_handle(value); + Handle<Object> value_handle(value, isolate); // To accommodate both the old and the new api we switch on the // data structure used to store the callbacks. Eventually proxy // callbacks should be phased out. ASSERT(!structure->IsProxy()); @@ -6980,36 +7247,37 @@ // api style callbacks AccessorInfo* data = AccessorInfo::cast(structure); Object* call_obj = data->setter(); v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj); if (call_fun == NULL) return value; - Handle<Object> number = Factory::NewNumberFromUint(index); - Handle<String> key(Factory::NumberToString(number)); - LOG(ApiNamedPropertyAccess("store", this, *key)); - CustomArguments args(data->data(), this, JSObject::cast(holder)); + Handle<Object> number = isolate->factory()->NewNumberFromUint(index); + Handle<String> key(isolate->factory()->NumberToString(number)); + LOG(isolate, ApiNamedPropertyAccess("store", this, *key)); + CustomArguments args(isolate, data->data(), this, JSObject::cast(holder)); v8::AccessorInfo info(args.end()); { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); call_fun(v8::Utils::ToLocal(key), v8::Utils::ToLocal(value_handle), info); } - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); return *value_handle; } if (structure->IsFixedArray()) { Object* setter = FixedArray::cast(structure)->get(kSetterIndex); if (setter->IsJSFunction()) { return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); } else { - Handle<Object> holder_handle(holder); - Handle<Object> key(Factory::NewNumberFromUint(index)); + Handle<Object> holder_handle(holder, isolate); + Handle<Object> key(isolate->factory()->NewNumberFromUint(index)); Handle<Object> args[2] = { key, holder_handle }; - return Top::Throw(*Factory::NewTypeError("no_setter_in_callback", - HandleVector(args, 2))); + return isolate->Throw( + *isolate->factory()->NewTypeError("no_setter_in_callback", + HandleVector(args, 2))); } } UNREACHABLE(); return NULL; @@ -7019,10 +7287,11 @@ // Adding n elements in fast case is O(n*n). // Note: revisit design to have dual undefined values to capture absent // elements. MaybeObject* JSObject::SetFastElement(uint32_t index, Object* value, + StrictModeFlag strict_mode, bool check_prototype) { ASSERT(HasFastElements()); Object* elms_obj; { MaybeObject* maybe_elms_obj = EnsureWritableFastElements(); @@ -7075,51 +7344,65 @@ Object* obj; { MaybeObject* maybe_obj = NormalizeElements(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } ASSERT(HasDictionaryElements()); - return SetElement(index, value, check_prototype); + return SetElement(index, value, strict_mode, check_prototype); } MaybeObject* JSObject::SetElement(uint32_t index, Object* value, + StrictModeFlag strict_mode, bool check_prototype) { // Check access rights if needed. - if (IsAccessCheckNeeded() && - !Top::MayIndexedAccess(this, index, v8::ACCESS_SET)) { - HandleScope scope; - Handle<Object> value_handle(value); - Top::ReportFailedAccessCheck(this, v8::ACCESS_SET); - return *value_handle; + if (IsAccessCheckNeeded()) { + Heap* heap = GetHeap(); + if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { + HandleScope scope; + Handle<Object> value_handle(value); + heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET); + return *value_handle; + } } if (IsJSGlobalProxy()) { Object* proto = GetPrototype(); if (proto->IsNull()) return value; ASSERT(proto->IsJSGlobalObject()); - return JSObject::cast(proto)->SetElement(index, value, check_prototype); + return JSObject::cast(proto)->SetElement(index, + value, + strict_mode, + check_prototype); } // Check for lookup interceptor if (HasIndexedInterceptor()) { - return SetElementWithInterceptor(index, value, check_prototype); + return SetElementWithInterceptor(index, + value, + strict_mode, + check_prototype); } - return SetElementWithoutInterceptor(index, value, check_prototype); + return SetElementWithoutInterceptor(index, + value, + strict_mode, + check_prototype); } MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value, + StrictModeFlag strict_mode, bool check_prototype) { + Isolate* isolate = GetIsolate(); switch (GetElementsKind()) { case FAST_ELEMENTS: // Fast case. - return SetFastElement(index, value, check_prototype); - case PIXEL_ELEMENTS: { - PixelArray* pixels = PixelArray::cast(elements()); + return SetFastElement(index, value, strict_mode, check_prototype); + case EXTERNAL_PIXEL_ELEMENTS: { + ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); return pixels->SetValue(index, value); } case EXTERNAL_BYTE_ELEMENTS: { ExternalByteArray* array = ExternalByteArray::cast(elements()); return array->SetValue(index, value); @@ -7162,28 +7445,44 @@ PropertyDetails details = dictionary->DetailsAt(entry); if (details.type() == CALLBACKS) { return SetElementWithCallback(element, index, value, this); } else { dictionary->UpdateMaxNumberKey(index); - dictionary->ValueAtPut(entry, value); + // If put fails instrict mode, throw exception. + if (!dictionary->ValueAtPut(entry, value) && + strict_mode == kStrictMode) { + Handle<Object> number(isolate->factory()->NewNumberFromUint(index)); + Handle<Object> holder(this); + Handle<Object> args[2] = { number, holder }; + return isolate->Throw( + *isolate->factory()->NewTypeError("strict_read_only_property", + HandleVector(args, 2))); + } } } else { // Index not already used. Look for an accessor in the prototype chain. if (check_prototype) { bool found; MaybeObject* result = + // Strict mode not needed. No-setter case already handled. SetElementWithCallbackSetterInPrototypes(index, value, &found); if (found) return result; } // When we set the is_extensible flag to false we always force // the element into dictionary mode (and force them to stay there). if (!map()->is_extensible()) { - Handle<Object> number(Factory::NewNumberFromUint(index)); - Handle<String> index_string(Factory::NumberToString(number)); - Handle<Object> args[1] = { index_string }; - return Top::Throw(*Factory::NewTypeError("object_not_extensible", - HandleVector(args, 1))); + if (strict_mode == kNonStrictMode) { + return isolate->heap()->undefined_value(); + } else { + Handle<Object> number(isolate->factory()->NewNumberFromUint(index)); + Handle<String> index_string( + isolate->factory()->NumberToString(number)); + Handle<Object> args[1] = { index_string }; + return isolate->Throw( + *isolate->factory()->NewTypeError("object_not_extensible", + HandleVector(args, 1))); + } } Object* result; { MaybeObject* maybe_result = dictionary->AtNumberPut(index, value); if (!maybe_result->ToObject(&result)) return maybe_result; } @@ -7232,11 +7531,11 @@ break; } // All possible cases have been handled above. Add a return to avoid the // complaints from the compiler. UNREACHABLE(); - return Heap::null_value(); + return isolate->heap()->null_value(); } MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, Object* value) { @@ -7245,11 +7544,11 @@ // Check to see if we need to update the length. For now, we make // sure that the length stays within 32-bits (unsigned). if (index >= old_len && index != 0xffffffff) { Object* len; { MaybeObject* maybe_len = - Heap::NumberFromDouble(static_cast<double>(index) + 1); + GetHeap()->NumberFromDouble(static_cast<double>(index) + 1); if (!maybe_len->ToObject(&len)) return maybe_len; } set_length(len); } return value; @@ -7267,20 +7566,22 @@ Object* value = elms->get(index); if (!value->IsTheHole()) return value; } break; } - case PIXEL_ELEMENTS: + case EXTERNAL_PIXEL_ELEMENTS: case EXTERNAL_BYTE_ELEMENTS: case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case EXTERNAL_SHORT_ELEMENTS: case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case EXTERNAL_INT_ELEMENTS: case EXTERNAL_UNSIGNED_INT_ELEMENTS: case EXTERNAL_FLOAT_ELEMENTS: { - MaybeObject* value = GetExternalElement(index); - if (!value->ToObjectUnchecked()->IsUndefined()) return value; + MaybeObject* maybe_value = GetExternalElement(index); + Object* value; + if (!maybe_value->ToObject(&value)) return maybe_value; + if (!value->IsUndefined()) return value; break; } case DICTIONARY_ELEMENTS: { NumberDictionary* dictionary = element_dictionary(); int entry = dictionary->FindEntry(index); @@ -7302,55 +7603,59 @@ break; } // Continue searching via the prototype chain. Object* pt = GetPrototype(); - if (pt == Heap::null_value()) return Heap::undefined_value(); + if (pt->IsNull()) return GetHeap()->undefined_value(); return pt->GetElementWithReceiver(receiver, index); } MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver, uint32_t index) { + Isolate* isolate = GetIsolate(); // Make sure that the top context does not change when doing // callbacks or interceptor calls. AssertNoContextChange ncc; - HandleScope scope; - Handle<InterceptorInfo> interceptor(GetIndexedInterceptor()); - Handle<Object> this_handle(receiver); - Handle<JSObject> holder_handle(this); + HandleScope scope(isolate); + Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate); + Handle<Object> this_handle(receiver, isolate); + Handle<JSObject> holder_handle(this, isolate); if (!interceptor->getter()->IsUndefined()) { v8::IndexedPropertyGetter getter = v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter()); - LOG(ApiIndexedPropertyAccess("interceptor-indexed-get", this, index)); - CustomArguments args(interceptor->data(), receiver, this); + LOG(isolate, + ApiIndexedPropertyAccess("interceptor-indexed-get", this, index)); + CustomArguments args(isolate, interceptor->data(), receiver, this); v8::AccessorInfo info(args.end()); v8::Handle<v8::Value> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); result = getter(index, info); } - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result); } MaybeObject* raw_result = holder_handle->GetElementPostInterceptor(*this_handle, index); - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); return raw_result; } MaybeObject* JSObject::GetElementWithReceiver(Object* receiver, uint32_t index) { // Check access rights if needed. - if (IsAccessCheckNeeded() && - !Top::MayIndexedAccess(this, index, v8::ACCESS_GET)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_GET); - return Heap::undefined_value(); + if (IsAccessCheckNeeded()) { + Heap* heap = GetHeap(); + if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) { + heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET); + return heap->undefined_value(); + } } if (HasIndexedInterceptor()) { return GetElementWithInterceptor(receiver, index); } @@ -7364,20 +7669,22 @@ Object* value = elms->get(index); if (!value->IsTheHole()) return value; } break; } - case PIXEL_ELEMENTS: + case EXTERNAL_PIXEL_ELEMENTS: case EXTERNAL_BYTE_ELEMENTS: case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case EXTERNAL_SHORT_ELEMENTS: case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case EXTERNAL_INT_ELEMENTS: case EXTERNAL_UNSIGNED_INT_ELEMENTS: case EXTERNAL_FLOAT_ELEMENTS: { - MaybeObject* value = GetExternalElement(index); - if (!value->ToObjectUnchecked()->IsUndefined()) return value; + MaybeObject* maybe_value = GetExternalElement(index); + Object* value; + if (!maybe_value->ToObject(&value)) return maybe_value; + if (!value->IsUndefined()) return value; break; } case DICTIONARY_ELEMENTS: { NumberDictionary* dictionary = element_dictionary(); int entry = dictionary->FindEntry(index); @@ -7395,21 +7702,22 @@ break; } } Object* pt = GetPrototype(); - if (pt == Heap::null_value()) return Heap::undefined_value(); + Heap* heap = GetHeap(); + if (pt == heap->null_value()) return heap->undefined_value(); return pt->GetElementWithReceiver(receiver, index); } MaybeObject* JSObject::GetExternalElement(uint32_t index) { // Get element works for both JSObject and JSArray since // JSArray::length cannot change. switch (GetElementsKind()) { - case PIXEL_ELEMENTS: { - PixelArray* pixels = PixelArray::cast(elements()); + case EXTERNAL_PIXEL_ELEMENTS: { + ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); if (index < static_cast<uint32_t>(pixels->length())) { uint8_t value = pixels->get(index); return Smi::FromInt(value); } break; @@ -7450,37 +7758,37 @@ } case EXTERNAL_INT_ELEMENTS: { ExternalIntArray* array = ExternalIntArray::cast(elements()); if (index < static_cast<uint32_t>(array->length())) { int32_t value = array->get(index); - return Heap::NumberFromInt32(value); + return GetHeap()->NumberFromInt32(value); } break; } case EXTERNAL_UNSIGNED_INT_ELEMENTS: { ExternalUnsignedIntArray* array = ExternalUnsignedIntArray::cast(elements()); if (index < static_cast<uint32_t>(array->length())) { uint32_t value = array->get(index); - return Heap::NumberFromUint32(value); + return GetHeap()->NumberFromUint32(value); } break; } case EXTERNAL_FLOAT_ELEMENTS: { ExternalFloatArray* array = ExternalFloatArray::cast(elements()); if (index < static_cast<uint32_t>(array->length())) { float value = array->get(index); - return Heap::AllocateHeapNumber(value); + return GetHeap()->AllocateHeapNumber(value); } break; } case FAST_ELEMENTS: case DICTIONARY_ELEMENTS: UNREACHABLE(); break; } - return Heap::undefined_value(); + return GetHeap()->undefined_value(); } bool JSObject::HasDenseElements() { int capacity = 0; @@ -7493,11 +7801,11 @@ for (int i = 0; i < capacity; i++) { if (!elms->get(i)->IsTheHole()) number_of_elements++; } break; } - case PIXEL_ELEMENTS: + case EXTERNAL_PIXEL_ELEMENTS: case EXTERNAL_BYTE_ELEMENTS: case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case EXTERNAL_SHORT_ELEMENTS: case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: case EXTERNAL_INT_ELEMENTS: @@ -7630,11 +7938,11 @@ return GetProperty(receiver, &result, name, attributes); } // Continue searching via the prototype chain. Object* pt = GetPrototype(); *attributes = ABSENT; - if (pt == Heap::null_value()) return Heap::undefined_value(); + if (pt->IsNull()) return GetHeap()->undefined_value(); return pt->GetPropertyWithReceiver(receiver, name, attributes); } MaybeObject* JSObject::GetLocalPropertyPostInterceptor( @@ -7645,72 +7953,78 @@ LookupResult result; LocalLookupRealNamedProperty(name, &result); if (result.IsProperty()) { return GetProperty(receiver, &result, name, attributes); } - return Heap::undefined_value(); + return GetHeap()->undefined_value(); } MaybeObject* JSObject::GetPropertyWithInterceptor( JSObject* receiver, String* name, PropertyAttributes* attributes) { + Isolate* isolate = GetIsolate(); InterceptorInfo* interceptor = GetNamedInterceptor(); - HandleScope scope; + HandleScope scope(isolate); Handle<JSObject> receiver_handle(receiver); Handle<JSObject> holder_handle(this); Handle<String> name_handle(name); if (!interceptor->getter()->IsUndefined()) { v8::NamedPropertyGetter getter = v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter()); - LOG(ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name)); - CustomArguments args(interceptor->data(), receiver, this); + LOG(isolate, + ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name)); + CustomArguments args(isolate, interceptor->data(), receiver, this); v8::AccessorInfo info(args.end()); v8::Handle<v8::Value> result; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(isolate, EXTERNAL); result = getter(v8::Utils::ToLocal(name_handle), info); } - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); if (!result.IsEmpty()) { *attributes = NONE; return *v8::Utils::OpenHandle(*result); } } MaybeObject* result = holder_handle->GetPropertyPostInterceptor( *receiver_handle, *name_handle, attributes); - RETURN_IF_SCHEDULED_EXCEPTION(); + RETURN_IF_SCHEDULED_EXCEPTION(isolate); return result; } bool JSObject::HasRealNamedProperty(String* key) { // Check access rights if needed. - if (IsAccessCheckNeeded() && - !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); - return false; + if (IsAccessCheckNeeded()) { + Heap* heap = GetHeap(); + if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) { + heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); + return false; + } } LookupResult result; LocalLookupRealNamedProperty(key, &result); return result.IsProperty() && (result.type() != INTERCEPTOR); } bool JSObject::HasRealElementProperty(uint32_t index) { // Check access rights if needed. - if (IsAccessCheckNeeded() && - !Top::MayIndexedAccess(this, index, v8::ACCESS_HAS)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); - return false; + if (IsAccessCheckNeeded()) { + Heap* heap = GetHeap(); + if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { + heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); + return false; + } } // Handle [] on String objects. if (this->IsStringObjectWithCharacterAt(index)) return true; @@ -7721,12 +8035,12 @@ Smi::cast(JSArray::cast(this)->length())->value()) : static_cast<uint32_t>(FixedArray::cast(elements())->length()); return (index < length) && !FixedArray::cast(elements())->get(index)->IsTheHole(); } - case PIXEL_ELEMENTS: { - PixelArray* pixels = PixelArray::cast(elements()); + case EXTERNAL_PIXEL_ELEMENTS: { + ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); return index < static_cast<uint32_t>(pixels->length()); } case EXTERNAL_BYTE_ELEMENTS: case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: case EXTERNAL_SHORT_ELEMENTS: @@ -7745,20 +8059,22 @@ UNREACHABLE(); break; } // All possibilities have been handled above already. UNREACHABLE(); - return Heap::null_value(); + return GetHeap()->null_value(); } bool JSObject::HasRealNamedCallbackProperty(String* key) { // Check access rights if needed. - if (IsAccessCheckNeeded() && - !Top::MayNamedAccess(this, key, v8::ACCESS_HAS)) { - Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); - return false; + if (IsAccessCheckNeeded()) { + Heap* heap = GetHeap(); + if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) { + heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); + return false; + } } LookupResult result; LocalLookupRealNamedProperty(key, &result); return result.IsProperty() && (result.type() == CALLBACKS); @@ -7953,12 +8269,12 @@ } } ASSERT(!storage || storage->length() >= counter); break; } - case PIXEL_ELEMENTS: { - int length = PixelArray::cast(elements())->length(); + case EXTERNAL_PIXEL_ELEMENTS: { + int length = ExternalPixelArray::cast(elements())->length(); while (counter < length) { if (storage != NULL) { storage->set(counter, Smi::FromInt(counter)); } counter++; @@ -8016,55 +8332,10 @@ return GetLocalElementKeys(storage, static_cast<PropertyAttributes>(DONT_ENUM)); } -bool NumberDictionaryShape::IsMatch(uint32_t key, Object* other) { - ASSERT(other->IsNumber()); - return key == static_cast<uint32_t>(other->Number()); -} - - -uint32_t NumberDictionaryShape::Hash(uint32_t key) { - return ComputeIntegerHash(key); -} - - -uint32_t NumberDictionaryShape::HashForObject(uint32_t key, Object* other) { - ASSERT(other->IsNumber()); - return ComputeIntegerHash(static_cast<uint32_t>(other->Number())); -} - - -MaybeObject* NumberDictionaryShape::AsObject(uint32_t key) { - return Heap::NumberFromUint32(key); -} - - -bool StringDictionaryShape::IsMatch(String* key, Object* other) { - // We know that all entries in a hash table had their hash keys created. - // Use that knowledge to have fast failure. - if (key->Hash() != String::cast(other)->Hash()) return false; - return key->Equals(String::cast(other)); -} - - -uint32_t StringDictionaryShape::Hash(String* key) { - return key->Hash(); -} - - -uint32_t StringDictionaryShape::HashForObject(String* key, Object* other) { - return String::cast(other)->Hash(); -} - - -MaybeObject* StringDictionaryShape::AsObject(String* key) { - return key; -} - - // StringKey simply carries a string object as key. class StringKey : public HashTableKey { public: explicit StringKey(String* string) : string_(string), @@ -8143,11 +8414,11 @@ return StringSharedHashHelper(source, shared, strict_mode); } MUST_USE_RESULT MaybeObject* AsObject() { Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateFixedArray(3); + { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* pair = FixedArray::cast(obj); pair->set(0, shared_); pair->set(1, source_); @@ -8227,11 +8498,12 @@ return String::cast(other)->Hash(); } MaybeObject* AsObject() { if (hash_field_ == 0) Hash(); - return Heap::AllocateSymbol(string_, chars_, hash_field_); + return Isolate::Current()->heap()->AllocateSymbol( + string_, chars_, hash_field_); } Vector<const char> string_; uint32_t hash_field_; int chars_; // Caches the number of characters when computing the hash code. @@ -8294,11 +8566,11 @@ return String::cast(string)->IsAsciiEqualTo(string_); } MaybeObject* AsObject() { if (hash_field_ == 0) Hash(); - return Heap::AllocateAsciiSymbol(string_, hash_field_); + return HEAP->AllocateAsciiSymbol(string_, hash_field_); } }; class TwoByteSymbolKey : public SequentialSymbolKey<uc16> { @@ -8310,19 +8582,20 @@ return String::cast(string)->IsTwoByteEqualTo(string_); } MaybeObject* AsObject() { if (hash_field_ == 0) Hash(); - return Heap::AllocateTwoByteSymbol(string_, hash_field_); + return HEAP->AllocateTwoByteSymbol(string_, hash_field_); } }; // SymbolKey carries a string/symbol object as key. class SymbolKey : public HashTableKey { public: - explicit SymbolKey(String* string) : string_(string) { } + explicit SymbolKey(String* string) + : string_(string) { } bool IsMatch(Object* string) { return String::cast(string)->Equals(string_); } @@ -8334,20 +8607,21 @@ MaybeObject* AsObject() { // Attempt to flatten the string, so that symbols will most often // be flat strings. string_ = string_->TryFlattenGetString(); + Heap* heap = string_->GetHeap(); // Transform string to symbol if possible. - Map* map = Heap::SymbolMapForString(string_); + Map* map = heap->SymbolMapForString(string_); if (map != NULL) { string_->set_map(map); ASSERT(string_->IsSymbol()); return string_; } // Otherwise allocate a new symbol. StringInputBuffer buffer(string_); - return Heap::AllocateInternalSymbol(&buffer, + return heap->AllocateInternalSymbol(&buffer, string_->length(), string_->hash_field()); } static uint32_t StringHash(Object* obj) { @@ -8382,39 +8656,22 @@ } else if (capacity > HashTable::kMaxCapacity) { return Failure::OutOfMemoryException(); } Object* obj; - { MaybeObject* maybe_obj = - Heap::AllocateHashTable(EntryToIndex(capacity), pretenure); + { MaybeObject* maybe_obj = Isolate::Current()->heap()-> + AllocateHashTable(EntryToIndex(capacity), pretenure); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } HashTable::cast(obj)->SetNumberOfElements(0); HashTable::cast(obj)->SetNumberOfDeletedElements(0); HashTable::cast(obj)->SetCapacity(capacity); return obj; } // Find entry for key otherwise return kNotFound. -template<typename Shape, typename Key> -int HashTable<Shape, Key>::FindEntry(Key key) { - uint32_t capacity = Capacity(); - uint32_t entry = FirstProbe(Shape::Hash(key), capacity); - uint32_t count = 1; - // EnsureCapacity will guarantee the hash table is never full. - while (true) { - Object* element = KeyAt(entry); - if (element->IsUndefined()) break; // Empty entry. - if (!element->IsNull() && Shape::IsMatch(key, element)) return entry; - entry = NextProbe(entry, count++, capacity); - } - return kNotFound; -} - - -// Find entry for key otherwise return kNotFound. int StringDictionary::FindEntry(String* key) { if (!key->IsSymbol()) { return HashTable<StringDictionaryShape, String*>::FindEntry(key); } @@ -8465,11 +8722,11 @@ if (nof + needed_free <= capacity) return this; } const int kMinCapacityForPretenure = 256; bool pretenure = - (capacity > kMinCapacityForPretenure) && !Heap::InNewSpace(this); + (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this); Object* obj; { MaybeObject* maybe_obj = Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } @@ -8606,11 +8863,11 @@ NumberDictionary* dict = element_dictionary(); HeapNumber* result_double = NULL; if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { // Allocate space for result before we start mutating the object. Object* new_double; - { MaybeObject* maybe_new_double = Heap::AllocateHeapNumber(0.0); + { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0); if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double; } result_double = HeapNumber::cast(new_double); } @@ -8666,17 +8923,18 @@ } } uint32_t result = pos; PropertyDetails no_details = PropertyDetails(NONE, NORMAL); + Heap* heap = GetHeap(); while (undefs > 0) { if (pos > static_cast<uint32_t>(Smi::kMaxValue)) { // Adding an entry with the key beyond smi-range requires // allocation. Bailout. return Smi::FromInt(-1); } - new_dict->AddNumberEntry(pos, Heap::undefined_value(), no_details)-> + new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)-> ToObjectUnchecked(); pos++; undefs--; } @@ -8695,12 +8953,14 @@ // Collects all defined (non-hole) and non-undefined (array) elements at // the start of the elements array. // If the object is in dictionary mode, it is converted to fast elements // mode. MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) { - ASSERT(!HasPixelElements() && !HasExternalArrayElements()); + ASSERT(!HasExternalArrayElements()); + Heap* heap = GetHeap(); + if (HasDictionaryElements()) { // Convert to fast elements containing only the existing properties. // Ordering is irrelevant, since we are going to sort anyway. NumberDictionary* dict = element_dictionary(); if (IsJSArray() || dict->requires_slow_elements() || @@ -8713,14 +8973,14 @@ { MaybeObject* maybe_obj = map()->GetFastElementsMap(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } Map* new_map = Map::cast(obj); - PretenureFlag tenure = Heap::InNewSpace(this) ? NOT_TENURED: TENURED; + PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED; Object* new_array; { MaybeObject* maybe_new_array = - Heap::AllocateFixedArray(dict->NumberOfElements(), tenure); + heap->AllocateFixedArray(dict->NumberOfElements(), tenure); if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array; } FixedArray* fast_elements = FixedArray::cast(new_array); dict->CopyValuesTo(fast_elements); @@ -8749,11 +9009,11 @@ HeapNumber* result_double = NULL; if (limit > static_cast<uint32_t>(Smi::kMaxValue)) { // Pessimistically allocate space for return value before // we start mutating the array. Object* new_double; - { MaybeObject* maybe_new_double = Heap::AllocateHeapNumber(0.0); + { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0); if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double; } result_double = HeapNumber::cast(new_double); } @@ -8807,11 +9067,11 @@ result_double->set_value(static_cast<double>(result)); return result_double; } -Object* PixelArray::SetValue(uint32_t index, Object* value) { +Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) { uint8_t clamped_value = 0; if (index < static_cast<uint32_t>(length())) { if (value->IsSmi()) { int int_value = Smi::cast(value)->value(); if (int_value < 0) { @@ -8843,11 +9103,12 @@ return Smi::FromInt(clamped_value); } template<typename ExternalArrayClass, typename ValueType> -static MaybeObject* ExternalArrayIntSetter(ExternalArrayClass* receiver, +static MaybeObject* ExternalArrayIntSetter(Heap* heap, + ExternalArrayClass* receiver, uint32_t index, Object* value) { ValueType cast_value = 0; if (index < static_cast<uint32_t>(receiver->length())) { if (value->IsSmi()) { @@ -8861,49 +9122,50 @@ // converted to a number type further up in the call chain. ASSERT(value->IsUndefined()); } receiver->set(index, cast_value); } - return Heap::NumberFromInt32(cast_value); + return heap->NumberFromInt32(cast_value); } MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) { return ExternalArrayIntSetter<ExternalByteArray, int8_t> - (this, index, value); + (GetHeap(), this, index, value); } MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index, Object* value) { return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t> - (this, index, value); + (GetHeap(), this, index, value); } MaybeObject* ExternalShortArray::SetValue(uint32_t index, Object* value) { return ExternalArrayIntSetter<ExternalShortArray, int16_t> - (this, index, value); + (GetHeap(), this, index, value); } MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index, Object* value) { return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t> - (this, index, value); + (GetHeap(), this, index, value); } MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) { return ExternalArrayIntSetter<ExternalIntArray, int32_t> - (this, index, value); + (GetHeap(), this, index, value); } MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) { uint32_t cast_value = 0; + Heap* heap = GetHeap(); if (index < static_cast<uint32_t>(length())) { if (value->IsSmi()) { int int_value = Smi::cast(value)->value(); cast_value = static_cast<uint32_t>(int_value); } else if (value->IsHeapNumber()) { @@ -8914,16 +9176,17 @@ // converted to a number type further up in the call chain. ASSERT(value->IsUndefined()); } set(index, cast_value); } - return Heap::NumberFromUint32(cast_value); + return heap->NumberFromUint32(cast_value); } MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) { float cast_value = 0; + Heap* heap = GetHeap(); if (index < static_cast<uint32_t>(length())) { if (value->IsSmi()) { int int_value = Smi::cast(value)->value(); cast_value = static_cast<float>(int_value); } else if (value->IsHeapNumber()) { @@ -8934,11 +9197,11 @@ // converted to a number type further up in the call chain. ASSERT(value->IsUndefined()); } set(index, cast_value); } - return Heap::AllocateHeapNumber(cast_value); + return heap->AllocateHeapNumber(cast_value); } JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) { ASSERT(!HasFastProperties()); @@ -8949,13 +9212,14 @@ MaybeObject* GlobalObject::EnsurePropertyCell(String* name) { ASSERT(!HasFastProperties()); int entry = property_dictionary()->FindEntry(name); if (entry == StringDictionary::kNotFound) { + Heap* heap = GetHeap(); Object* cell; { MaybeObject* maybe_cell = - Heap::AllocateJSGlobalPropertyCell(Heap::the_hole_value()); + heap->AllocateJSGlobalPropertyCell(heap->the_hole_value()); if (!maybe_cell->ToObject(&cell)) return maybe_cell; } PropertyDetails details(NONE, NORMAL); details = details.AsDeleted(); Object* dictionary; @@ -9125,30 +9389,30 @@ Object* CompilationCacheTable::Lookup(String* src) { StringKey key(src); int entry = FindEntry(&key); - if (entry == kNotFound) return Heap::undefined_value(); + if (entry == kNotFound) return GetHeap()->undefined_value(); return get(EntryToIndex(entry) + 1); } Object* CompilationCacheTable::LookupEval(String* src, Context* context, StrictModeFlag strict_mode) { StringSharedKey key(src, context->closure()->shared(), strict_mode); int entry = FindEntry(&key); - if (entry == kNotFound) return Heap::undefined_value(); + if (entry == kNotFound) return GetHeap()->undefined_value(); return get(EntryToIndex(entry) + 1); } Object* CompilationCacheTable::LookupRegExp(String* src, JSRegExp::Flags flags) { RegExpKey key(src, flags); int entry = FindEntry(&key); - if (entry == kNotFound) return Heap::undefined_value(); + if (entry == kNotFound) return GetHeap()->undefined_value(); return get(EntryToIndex(entry) + 1); } MaybeObject* CompilationCacheTable::Put(String* src, Object* value) { @@ -9215,16 +9479,17 @@ return cache; } void CompilationCacheTable::Remove(Object* value) { + Object* null_value = GetHeap()->null_value(); for (int entry = 0, size = Capacity(); entry < size; entry++) { int entry_index = EntryToIndex(entry); int value_index = entry_index + 1; if (get(value_index) == value) { - fast_set(this, entry_index, Heap::null_value()); - fast_set(this, value_index, Heap::null_value()); + fast_set(this, entry_index, null_value); + fast_set(this, value_index, null_value); ElementRemoved(); } } return; } @@ -9265,11 +9530,11 @@ Object* MapCache::Lookup(FixedArray* array) { SymbolsKey key(array); int entry = FindEntry(&key); - if (entry == kNotFound) return Heap::undefined_value(); + if (entry == kNotFound) return GetHeap()->undefined_value(); return get(EntryToIndex(entry) + 1); } MaybeObject* MapCache::Put(FixedArray* array, Map* value) { @@ -9302,24 +9567,25 @@ } template<typename Shape, typename Key> MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() { + Heap* heap = Dictionary<Shape, Key>::GetHeap(); int length = HashTable<Shape, Key>::NumberOfElements(); // Allocate and initialize iteration order array. Object* obj; - { MaybeObject* maybe_obj = Heap::AllocateFixedArray(length); + { MaybeObject* maybe_obj = heap->AllocateFixedArray(length); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* iteration_order = FixedArray::cast(obj); for (int i = 0; i < length; i++) { iteration_order->set(i, Smi::FromInt(i)); } // Allocate array with enumeration order. - { MaybeObject* maybe_obj = Heap::AllocateFixedArray(length); + { MaybeObject* maybe_obj = heap->AllocateFixedArray(length); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } FixedArray* enumeration_order = FixedArray::cast(obj); // Fill the enumeration order array with property details. @@ -9376,12 +9642,13 @@ void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) { // Do nothing if the interval [from, to) is empty. if (from >= to) return; + Heap* heap = GetHeap(); int removed_entries = 0; - Object* sentinel = Heap::null_value(); + Object* sentinel = heap->null_value(); int capacity = Capacity(); for (int i = 0; i < capacity; i++) { Object* key = KeyAt(i); if (key->IsNumber()) { uint32_t number = static_cast<uint32_t>(key->Number()); @@ -9398,18 +9665,19 @@ template<typename Shape, typename Key> Object* Dictionary<Shape, Key>::DeleteProperty(int entry, JSObject::DeleteMode mode) { + Heap* heap = Dictionary<Shape, Key>::GetHeap(); PropertyDetails details = DetailsAt(entry); // Ignore attributes if forcing a deletion. if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) { - return Heap::false_value(); + return heap->false_value(); } - SetEntry(entry, Heap::null_value(), Heap::null_value(), Smi::FromInt(0)); + SetEntry(entry, heap->null_value(), heap->null_value(), Smi::FromInt(0)); HashTable<Shape, Key>::ElementRemoved(); - return Heap::true_value(); + return heap->true_value(); } template<typename Shape, typename Key> MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) { @@ -9629,11 +9897,12 @@ e = JSGlobalPropertyCell::cast(e)->value(); } if (e == value) return k; } } - return Heap::undefined_value(); + Heap* heap = Dictionary<Shape, Key>::GetHeap(); + return heap->undefined_value(); } MaybeObject* StringDictionary::TransformPropertiesToFastFor( JSObject* obj, int unused_property_fields) { @@ -9654,21 +9923,23 @@ } int instance_descriptor_length = 0; int number_of_fields = 0; + Heap* heap = GetHeap(); + // Compute the length of the instance descriptor. int capacity = Capacity(); for (int i = 0; i < capacity; i++) { Object* k = KeyAt(i); if (IsKey(k)) { Object* value = ValueAt(i); PropertyType type = DetailsAt(i).type(); ASSERT(type != FIELD); instance_descriptor_length++; if (type == NORMAL && - (!value->IsJSFunction() || Heap::InNewSpace(value))) { + (!value->IsJSFunction() || heap->InNewSpace(value))) { number_of_fields += 1; } } } @@ -9692,11 +9963,11 @@ } // Allocate the fixed array for the fields. Object* fields; { MaybeObject* maybe_fields = - Heap::AllocateFixedArray(number_of_allocated_fields); + heap->AllocateFixedArray(number_of_allocated_fields); if (!maybe_fields->ToObject(&fields)) return maybe_fields; } // Fill in the instance descriptor and the fields. int next_descriptor = 0; @@ -9705,17 +9976,17 @@ Object* k = KeyAt(i); if (IsKey(k)) { Object* value = ValueAt(i); // Ensure the key is a symbol before writing into the instance descriptor. Object* key; - { MaybeObject* maybe_key = Heap::LookupSymbol(String::cast(k)); + { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k)); if (!maybe_key->ToObject(&key)) return maybe_key; } PropertyDetails details = DetailsAt(i); PropertyType type = details.type(); - if (value->IsJSFunction() && !Heap::InNewSpace(value)) { + if (value->IsJSFunction() && !heap->InNewSpace(value)) { ConstantFunctionDescriptor d(String::cast(key), JSFunction::cast(value), details.attributes(), details.index()); descriptors->Set(next_descriptor++, &d); @@ -9786,11 +10057,11 @@ Object* DebugInfo::GetBreakPointInfo(int code_position) { // Find the index of the break point info object for this code position. int index = GetBreakPointInfoIndex(code_position); // Return the break point info object if any. - if (index == kNoBreakPointInfo) return Heap::undefined_value(); + if (index == kNoBreakPointInfo) return GetHeap()->undefined_value(); return BreakPointInfo::cast(break_points()->get(index)); } // Clear a break point at the specified code position. @@ -9808,10 +10079,11 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int code_position, int source_position, int statement_position, Handle<Object> break_point_object) { + Isolate* isolate = Isolate::Current(); Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position)); if (!break_point_info->IsUndefined()) { BreakPointInfo::SetBreakPoint( Handle<BreakPointInfo>::cast(break_point_info), break_point_object); @@ -9830,39 +10102,41 @@ if (index == kNoBreakPointInfo) { // No free slot - extend break point info array. Handle<FixedArray> old_break_points = Handle<FixedArray>(FixedArray::cast(debug_info->break_points())); Handle<FixedArray> new_break_points = - Factory::NewFixedArray(old_break_points->length() + - Debug::kEstimatedNofBreakPointsInFunction); + isolate->factory()->NewFixedArray( + old_break_points->length() + + Debug::kEstimatedNofBreakPointsInFunction); debug_info->set_break_points(*new_break_points); for (int i = 0; i < old_break_points->length(); i++) { new_break_points->set(i, old_break_points->get(i)); } index = old_break_points->length(); } ASSERT(index != kNoBreakPointInfo); // Allocate new BreakPointInfo object and set the break point. - Handle<BreakPointInfo> new_break_point_info = - Handle<BreakPointInfo>::cast(Factory::NewStruct(BREAK_POINT_INFO_TYPE)); + Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast( + isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE)); new_break_point_info->set_code_position(Smi::FromInt(code_position)); new_break_point_info->set_source_position(Smi::FromInt(source_position)); new_break_point_info-> set_statement_position(Smi::FromInt(statement_position)); - new_break_point_info->set_break_point_objects(Heap::undefined_value()); + new_break_point_info->set_break_point_objects( + isolate->heap()->undefined_value()); BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object); debug_info->break_points()->set(index, *new_break_point_info); } // Get the break point objects for a code position. Object* DebugInfo::GetBreakPointObjects(int code_position) { Object* break_point_info = GetBreakPointInfo(code_position); if (break_point_info->IsUndefined()) { - return Heap::undefined_value(); + return GetHeap()->undefined_value(); } return BreakPointInfo::cast(break_point_info)->break_point_objects(); } @@ -9881,11 +10155,12 @@ } Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info, Handle<Object> break_point_object) { - if (debug_info->break_points()->IsUndefined()) return Heap::undefined_value(); + Heap* heap = debug_info->GetHeap(); + if (debug_info->break_points()->IsUndefined()) return heap->undefined_value(); for (int i = 0; i < debug_info->break_points()->length(); i++) { if (!debug_info->break_points()->get(i)->IsUndefined()) { Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(BreakPointInfo::cast( debug_info->break_points()->get(i))); @@ -9893,11 +10168,11 @@ break_point_object)) { return *break_point_info; } } } - return Heap::undefined_value(); + return heap->undefined_value(); } // Find the index of the break point info object for the specified code // position. @@ -9917,26 +10192,28 @@ // Remove the specified break point object. void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info, Handle<Object> break_point_object) { + Isolate* isolate = Isolate::Current(); // If there are no break points just ignore. if (break_point_info->break_point_objects()->IsUndefined()) return; // If there is a single break point clear it if it is the same. if (!break_point_info->break_point_objects()->IsFixedArray()) { if (break_point_info->break_point_objects() == *break_point_object) { - break_point_info->set_break_point_objects(Heap::undefined_value()); + break_point_info->set_break_point_objects( + isolate->heap()->undefined_value()); } return; } // If there are multiple break points shrink the array ASSERT(break_point_info->break_point_objects()->IsFixedArray()); Handle<FixedArray> old_array = Handle<FixedArray>( FixedArray::cast(break_point_info->break_point_objects())); Handle<FixedArray> new_array = - Factory::NewFixedArray(old_array->length() - 1); + isolate->factory()->NewFixedArray(old_array->length() - 1); int found_count = 0; for (int i = 0; i < old_array->length(); i++) { if (old_array->get(i) == *break_point_object) { ASSERT(found_count == 0); found_count++; @@ -9959,21 +10236,21 @@ } // If the break point object is the same as before just ignore. if (break_point_info->break_point_objects() == *break_point_object) return; // If there was one break point object before replace with array. if (!break_point_info->break_point_objects()->IsFixedArray()) { - Handle<FixedArray> array = Factory::NewFixedArray(2); + Handle<FixedArray> array = FACTORY->NewFixedArray(2); array->set(0, break_point_info->break_point_objects()); array->set(1, *break_point_object); break_point_info->set_break_point_objects(*array); return; } // If there was more than one break point before extend array. Handle<FixedArray> old_array = Handle<FixedArray>( FixedArray::cast(break_point_info->break_point_objects())); Handle<FixedArray> new_array = - Factory::NewFixedArray(old_array->length() + 1); + FACTORY->NewFixedArray(old_array->length() + 1); for (int i = 0; i < old_array->length(); i++) { // If the break point was there before just ignore. if (old_array->get(i) == *break_point_object) return; new_array->set(i, old_array->get(i)); }