Roll V8 back to 3.6
Roll back to V8 3.6 to fix x86 build, we don't have ucontext.h.
This reverts commits:
5d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0b
c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9
592a9fc1d8ea420377a2e7efd0600e20b058be2b
Bug: 5688872
Change-Id: Ic961bb5e65b778e98bbfb71cce71d99fa949e995
diff --git a/src/objects.cc b/src/objects.cc
index 64d85a0..88ebbf4 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -1,4 +1,4 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -33,16 +33,13 @@
#include "codegen.h"
#include "debug.h"
#include "deoptimizer.h"
-#include "date.h"
#include "elements.h"
#include "execution.h"
#include "full-codegen.h"
#include "hydrogen.h"
#include "objects-inl.h"
#include "objects-visiting.h"
-#include "objects-visiting-inl.h"
#include "macro-assembler.h"
-#include "mark-compact.h"
#include "safepoint-table.h"
#include "string-stream.h"
#include "utils.h"
@@ -56,11 +53,10 @@
namespace v8 {
namespace internal {
-void PrintElementsKind(FILE* out, ElementsKind kind) {
- ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
- PrintF(out, "%s", accessor->name());
-}
-
+// Getters and setters are stored in a fixed array property. These are
+// constants for their indices.
+const int kGetterIndex = 0;
+const int kSetterIndex = 1;
MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
Object* value) {
@@ -136,27 +132,34 @@
void Object::Lookup(String* name, LookupResult* result) {
Object* holder = NULL;
- if (IsJSReceiver()) {
- holder = this;
- } else {
+ if (IsSmi()) {
Context* global_context = Isolate::Current()->context()->global_context();
- if (IsNumber()) {
- holder = global_context->number_function()->instance_prototype();
- } else if (IsString()) {
+ holder = global_context->number_function()->instance_prototype();
+ } else {
+ HeapObject* heap_object = HeapObject::cast(this);
+ if (heap_object->IsJSObject()) {
+ return JSObject::cast(this)->Lookup(name, result);
+ } else if (heap_object->IsJSProxy()) {
+ return result->HandlerResult();
+ }
+ Context* global_context = Isolate::Current()->context()->global_context();
+ if (heap_object->IsString()) {
holder = global_context->string_function()->instance_prototype();
- } else if (IsBoolean()) {
+ } else if (heap_object->IsHeapNumber()) {
+ holder = global_context->number_function()->instance_prototype();
+ } else if (heap_object->IsBoolean()) {
holder = global_context->boolean_function()->instance_prototype();
}
}
ASSERT(holder != NULL); // Cannot handle null or undefined.
- JSReceiver::cast(holder)->Lookup(name, result);
+ JSObject::cast(holder)->Lookup(name, result);
}
MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
String* name,
PropertyAttributes* attributes) {
- LookupResult result(name->GetIsolate());
+ LookupResult result;
Lookup(name, &result);
MaybeObject* value = GetProperty(receiver, &result, name, attributes);
ASSERT(*attributes <= ABSENT);
@@ -164,9 +167,10 @@
}
-MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
- Object* structure,
- String* name) {
+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 foreign
@@ -174,7 +178,7 @@
if (structure->IsForeign()) {
AccessorDescriptor* callback =
reinterpret_cast<AccessorDescriptor*>(
- Foreign::cast(structure)->foreign_address());
+ Foreign::cast(structure)->address());
MaybeObject* value = (callback->getter)(receiver, callback->data);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return value;
@@ -187,9 +191,10 @@
v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
HandleScope scope(isolate);
JSObject* self = JSObject::cast(receiver);
+ JSObject* holder_handle = JSObject::cast(holder);
Handle<String> key(name);
LOG(isolate, ApiNamedPropertyAccess("load", self, name));
- CustomArguments args(isolate, data->data(), self, this);
+ CustomArguments args(isolate, data->data(), self, holder_handle);
v8::AccessorInfo info(args.end());
v8::Handle<v8::Value> result;
{
@@ -205,11 +210,11 @@
}
// __defineGetter__ callback
- if (structure->IsAccessorPair()) {
- Object* getter = AccessorPair::cast(structure)->getter();
- if (getter->IsSpecFunction()) {
- // TODO(rossberg): nicer would be to cast to some JSCallable here...
- return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
+ if (structure->IsFixedArray()) {
+ Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
+ if (getter->IsJSFunction()) {
+ return Object::GetPropertyWithDefinedGetter(receiver,
+ JSFunction::cast(getter));
}
// Getter is not a function.
return isolate->heap()->undefined_value();
@@ -220,75 +225,50 @@
}
-MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
- String* name_raw) {
- Isolate* isolate = GetIsolate();
+MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw,
+ String* name_raw,
+ Object* handler_raw) {
+ Isolate* isolate = name_raw->GetIsolate();
HandleScope scope(isolate);
Handle<Object> receiver(receiver_raw);
Handle<Object> name(name_raw);
+ Handle<Object> handler(handler_raw);
- Handle<Object> args[] = { receiver, name };
- Handle<Object> result = CallTrap(
- "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
+ // Extract trap function.
+ Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("get");
+ Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
if (isolate->has_pending_exception()) return Failure::Exception();
+ if (trap->IsUndefined()) {
+ // Get the derived `get' property.
+ trap = isolate->derived_get_trap();
+ }
+
+ // Call trap function.
+ Object** args[] = { receiver.location(), name.location() };
+ bool has_exception;
+ Handle<Object> result =
+ Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
+ if (has_exception) return Failure::Exception();
return *result;
}
-Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
- Isolate* isolate = object->IsHeapObject()
- ? Handle<HeapObject>::cast(object)->GetIsolate()
- : Isolate::Current();
- CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
-}
-
-
-MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
- uint32_t index) {
- String* name;
- MaybeObject* maybe = GetHeap()->Uint32ToString(index);
- if (!maybe->To<String>(&name)) return maybe;
- return GetPropertyWithHandler(receiver, name);
-}
-
-
-MaybeObject* JSProxy::SetElementWithHandler(uint32_t index,
- Object* value,
- StrictModeFlag strict_mode) {
- String* name;
- MaybeObject* maybe = GetHeap()->Uint32ToString(index);
- if (!maybe->To<String>(&name)) return maybe;
- return SetPropertyWithHandler(name, value, NONE, strict_mode);
-}
-
-
-bool JSProxy::HasElementWithHandler(uint32_t index) {
- String* name;
- MaybeObject* maybe = GetHeap()->Uint32ToString(index);
- if (!maybe->To<String>(&name)) return maybe;
- return HasPropertyWithHandler(name);
-}
-
-
MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
- JSReceiver* getter) {
+ JSFunction* getter) {
HandleScope scope;
- Handle<JSReceiver> fun(getter);
+ 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.
- // TODO(rossberg): should this apply to getters that are function proxies?
- if (debug->StepInActive() && fun->IsJSFunction()) {
- debug->HandleStepIn(
- Handle<JSFunction>::cast(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, true);
+ Execution::Call(fun, self, 0, NULL, &has_pending_exception);
// Check for pending exception and return the result.
if (has_pending_exception) return Failure::Exception();
return *result;
@@ -310,8 +290,10 @@
AccessorInfo* info = AccessorInfo::cast(obj);
if (info->all_can_read()) {
*attributes = result->GetAttributes();
- return result->holder()->GetPropertyWithCallback(
- receiver, result->GetCallbackObject(), name);
+ return GetPropertyWithCallback(receiver,
+ result->GetCallbackObject(),
+ name,
+ result->holder());
}
}
break;
@@ -320,7 +302,7 @@
case FIELD:
case CONSTANT_FUNCTION: {
// Search ALL_CAN_READ accessors in prototype chain.
- LookupResult r(GetIsolate());
+ LookupResult r;
result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
if (r.IsProperty()) {
return GetPropertyWithFailedAccessCheck(receiver,
@@ -333,7 +315,7 @@
case INTERCEPTOR: {
// If the object has an interceptor, try real named properties.
// No access check in GetPropertyAttributeWithInterceptor.
- LookupResult r(GetIsolate());
+ LookupResult r;
result->holder()->LookupRealNamedProperty(name, &r);
if (r.IsProperty()) {
return GetPropertyWithFailedAccessCheck(receiver,
@@ -380,7 +362,7 @@
case CONSTANT_FUNCTION: {
if (!continue_search) break;
// Search ALL_CAN_READ accessors in prototype chain.
- LookupResult r(GetIsolate());
+ LookupResult r;
result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
if (r.IsProperty()) {
return GetPropertyAttributeWithFailedAccessCheck(receiver,
@@ -394,7 +376,7 @@
case INTERCEPTOR: {
// If the object has an interceptor, try real named properties.
// No access check in GetPropertyAttributeWithInterceptor.
- LookupResult r(GetIsolate());
+ LookupResult r;
if (continue_search) {
result->holder()->LookupRealNamedProperty(name, &r);
} else {
@@ -414,7 +396,7 @@
}
}
- GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ GetHeap()->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return ABSENT;
}
@@ -444,16 +426,6 @@
}
-Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
- Handle<String> key,
- Handle<Object> value,
- PropertyDetails details) {
- CALL_HEAP_FUNCTION(object->GetIsolate(),
- object->SetNormalizedProperty(*key, *value, details),
- Object);
-}
-
-
MaybeObject* JSObject::SetNormalizedProperty(String* name,
Object* value,
PropertyDetails details) {
@@ -514,7 +486,7 @@
}
JSGlobalPropertyCell* cell =
JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
- cell->set_value(cell->GetHeap()->the_hole_value());
+ cell->set_value(cell->heap()->the_hole_value());
dictionary->DetailsAtPut(entry, details.AsDeleted());
} else {
Object* deleted = dictionary->DeleteProperty(entry, mode);
@@ -548,21 +520,6 @@
}
-Handle<Object> Object::GetProperty(Handle<Object> object,
- Handle<Object> receiver,
- LookupResult* result,
- Handle<String> key,
- PropertyAttributes* attributes) {
- Isolate* isolate = object->IsHeapObject()
- ? Handle<HeapObject>::cast(object)->GetIsolate()
- : Isolate::Current();
- CALL_HEAP_FUNCTION(
- isolate,
- object->GetProperty(*receiver, result, *key, attributes),
- Object);
-}
-
-
MaybeObject* Object::GetProperty(Object* receiver,
LookupResult* result,
String* name,
@@ -580,9 +537,7 @@
// holder in the prototype chain.
// Proxy handlers do not use the proxy's prototype, so we can skip this.
if (!result->IsHandler()) {
- Object* last = result->IsProperty()
- ? result->holder()
- : Object::cast(heap->null_value());
+ Object* last = result->IsProperty() ? result->holder() : heap->null_value();
ASSERT(this != this->GetPrototype());
for (Object* current = this; true; current = current->GetPrototype()) {
if (current->IsAccessCheckNeeded()) {
@@ -611,26 +566,30 @@
}
*attributes = result->GetAttributes();
Object* value;
+ JSObject* holder = result->holder();
switch (result->type()) {
case NORMAL:
- value = result->holder()->GetNormalizedProperty(result);
+ value = holder->GetNormalizedProperty(result);
ASSERT(!value->IsTheHole() || result->IsReadOnly());
return value->IsTheHole() ? heap->undefined_value() : value;
case FIELD:
- value = result->holder()->FastPropertyAt(result->GetFieldIndex());
+ value = holder->FastPropertyAt(result->GetFieldIndex());
ASSERT(!value->IsTheHole() || result->IsReadOnly());
return value->IsTheHole() ? heap->undefined_value() : value;
case CONSTANT_FUNCTION:
return result->GetConstantFunction();
case CALLBACKS:
- return result->holder()->GetPropertyWithCallback(
- receiver, result->GetCallbackObject(), name);
- case HANDLER:
- return result->proxy()->GetPropertyWithHandler(receiver, name);
+ return GetPropertyWithCallback(receiver,
+ result->GetCallbackObject(),
+ name,
+ holder);
+ case HANDLER: {
+ JSProxy* proxy = JSProxy::cast(this);
+ return GetPropertyWithHandler(receiver, name, proxy->handler());
+ }
case INTERCEPTOR: {
JSObject* recvr = JSObject::cast(receiver);
- return result->holder()->GetPropertyWithInterceptor(
- recvr, name, attributes);
+ return holder->GetPropertyWithInterceptor(recvr, name, attributes);
}
case MAP_TRANSITION:
case ELEMENTS_TRANSITION:
@@ -654,21 +613,28 @@
for (holder = this;
holder != heap->null_value();
holder = holder->GetPrototype()) {
- if (!holder->IsJSObject()) {
- Isolate* isolate = heap->isolate();
- Context* global_context = isolate->context()->global_context();
- if (holder->IsNumber()) {
- holder = global_context->number_function()->instance_prototype();
- } else if (holder->IsString()) {
- holder = global_context->string_function()->instance_prototype();
- } else if (holder->IsBoolean()) {
- holder = global_context->boolean_function()->instance_prototype();
- } else if (holder->IsJSProxy()) {
- return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
- } else {
- // Undefined and null have no indexed properties.
- ASSERT(holder->IsUndefined() || holder->IsNull());
- return heap->undefined_value();
+ if (holder->IsSmi()) {
+ Context* global_context = Isolate::Current()->context()->global_context();
+ holder = global_context->number_function()->instance_prototype();
+ } else {
+ HeapObject* heap_object = HeapObject::cast(holder);
+ if (!heap_object->IsJSObject()) {
+ 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 if (heap_object->IsJSProxy()) {
+ // TODO(rossberg): do something
+ return heap->undefined_value(); // For now...
+ } else {
+ // Undefined and null have no indexed properties.
+ ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
+ return heap->undefined_value();
+ }
}
}
@@ -692,7 +658,10 @@
if (js_object->elements() != heap->empty_fixed_array()) {
MaybeObject* result = js_object->GetElementsAccessor()->Get(
- receiver, js_object, index);
+ js_object->elements(),
+ index,
+ js_object,
+ receiver);
if (result != heap->the_hole_value()) return result;
}
}
@@ -732,49 +701,6 @@
}
-MaybeObject* Object::GetHash(CreationFlag flag) {
- // The object is either a number, a string, an odd-ball,
- // a real JS object, or a Harmony proxy.
- if (IsNumber()) {
- uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
- return Smi::FromInt(hash & Smi::kMaxValue);
- }
- if (IsString()) {
- uint32_t hash = String::cast(this)->Hash();
- return Smi::FromInt(hash);
- }
- if (IsOddball()) {
- uint32_t hash = Oddball::cast(this)->to_string()->Hash();
- return Smi::FromInt(hash);
- }
- if (IsJSReceiver()) {
- return JSReceiver::cast(this)->GetIdentityHash(flag);
- }
-
- UNREACHABLE();
- return Smi::FromInt(0);
-}
-
-
-bool Object::SameValue(Object* other) {
- if (other == this) return true;
- if (!IsHeapObject() || !other->IsHeapObject()) return false;
-
- // The object is either a number, a string, an odd-ball,
- // a real JS object, or a Harmony proxy.
- if (IsNumber() && other->IsNumber()) {
- double this_value = Number();
- double other_value = other->Number();
- return (this_value == other_value) ||
- (isnan(this_value) && isnan(other_value));
- }
- if (IsString() && other->IsString()) {
- return String::cast(this)->Equals(String::cast(other));
- }
- return false;
-}
-
-
void Object::ShortPrint(FILE* out) {
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
@@ -892,7 +818,7 @@
len - first_length);
}
cs->set_first(result);
- cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
+ cs->set_second(heap->empty_string());
return result;
}
default:
@@ -918,40 +844,39 @@
#endif // DEBUG
Heap* heap = GetHeap();
int size = this->Size(); // Byte size of the original string.
- if (size < ExternalString::kShortSize) {
+ 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;
}
+ ASSERT(size >= ExternalString::kSize);
bool is_ascii = this->IsAsciiRepresentation();
bool is_symbol = this->IsSymbol();
+ 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.
- if (size >= ExternalString::kSize) {
- this->set_map_no_write_barrier(
- is_symbol
- ? (is_ascii ? heap->external_symbol_with_ascii_data_map()
- : heap->external_symbol_map())
- : (is_ascii ? heap->external_string_with_ascii_data_map()
- : heap->external_string_map()));
- } else {
- this->set_map_no_write_barrier(
- is_symbol
- ? (is_ascii ? heap->short_external_symbol_with_ascii_data_map()
- : heap->short_external_symbol_map())
- : (is_ascii ? heap->short_external_string_with_ascii_data_map()
- : heap->short_external_string_map()));
- }
+ this->set_map(is_ascii ?
+ 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);
- if (is_symbol) self->Hash(); // Force regeneration of the hash value.
+ // 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());
+ }
// 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);
- if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
- MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
- new_size - size);
- }
return true;
}
@@ -970,33 +895,34 @@
#endif // DEBUG
Heap* heap = GetHeap();
int size = this->Size(); // Byte size of the original string.
- if (size < ExternalString::kShortSize) {
+ 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;
}
+ ASSERT(size >= ExternalString::kSize);
bool is_symbol = this->IsSymbol();
+ 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. Use short version if space is limited.
- if (size >= ExternalString::kSize) {
- this->set_map_no_write_barrier(
- is_symbol ? heap->external_ascii_symbol_map()
- : heap->external_ascii_string_map());
- } else {
- this->set_map_no_write_barrier(
- is_symbol ? heap->short_external_ascii_symbol_map()
- : heap->short_external_ascii_string_map());
- }
+ // reinitializing the fields.
+ 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);
- if (is_symbol) self->Hash(); // Force regeneration of the hash value.
+ // 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());
+ }
// 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);
- if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
- MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
- new_size - size);
- }
return true;
}
@@ -1068,11 +994,12 @@
switch (map()->instance_type()) {
case JS_ARRAY_TYPE: {
double length = JSArray::cast(this)->length()->Number();
- accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
+ accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
break;
}
case JS_WEAK_MAP_TYPE: {
- accumulator->Add("<JS WeakMap>");
+ int elements = JSWeakMap::cast(this)->table()->NumberOfElements();
+ accumulator->Add("<JS WeakMap[%d]>", elements);
break;
}
case JS_REGEXP_TYPE: {
@@ -1100,7 +1027,7 @@
// JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
default: {
Map* map_of_this = map();
- Heap* heap = GetHeap();
+ Heap* heap = map_of_this->heap();
Object* constructor = map_of_this->constructor();
bool printed = false;
if (constructor->IsHeapObject() &&
@@ -1122,6 +1049,7 @@
global_object ? "Global Object: " : "",
vowel ? "n" : "");
accumulator->Put(str);
+ accumulator->Put('>');
printed = true;
}
}
@@ -1142,28 +1070,8 @@
}
-void JSObject::PrintElementsTransition(
- FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
- ElementsKind to_kind, FixedArrayBase* to_elements) {
- if (from_kind != to_kind) {
- PrintF(file, "elements transition [");
- PrintElementsKind(file, from_kind);
- PrintF(file, " -> ");
- PrintElementsKind(file, to_kind);
- PrintF(file, "] in ");
- JavaScriptFrame::PrintTop(file, false, true);
- PrintF(file, " for ");
- ShortPrint(file);
- PrintF(file, " from ");
- from_elements->ShortPrint(file);
- PrintF(file, " to ");
- to_elements->ShortPrint(file);
- PrintF(file, "\n");
- }
-}
-
-
void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
+ // if (!HEAP->InNewSpace(this)) PrintF("*", this);
Heap* heap = GetHeap();
if (!heap->Contains(this)) {
accumulator->Add("!!!INVALID POINTER!!!");
@@ -1186,21 +1094,14 @@
}
switch (map()->instance_type()) {
case MAP_TYPE:
- accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
+ accumulator->Add("<Map>");
break;
case FIXED_ARRAY_TYPE:
accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
break;
- case FIXED_DOUBLE_ARRAY_TYPE:
- accumulator->Add("<FixedDoubleArray[%u]>",
- FixedDoubleArray::cast(this)->length());
- break;
case BYTE_ARRAY_TYPE:
accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
break;
- case FREE_SPACE_TYPE:
- accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
- break;
case EXTERNAL_PIXEL_ARRAY_TYPE:
accumulator->Add("<ExternalPixelArray[%u]>",
ExternalPixelArray::cast(this)->length());
@@ -1339,10 +1240,7 @@
case JS_OBJECT_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_VALUE_TYPE:
- case JS_DATE_TYPE:
case JS_ARRAY_TYPE:
- case JS_SET_TYPE:
- case JS_MAP_TYPE:
case JS_WEAK_MAP_TYPE:
case JS_REGEXP_TYPE:
case JS_GLOBAL_PROXY_TYPE:
@@ -1379,7 +1277,6 @@
case HEAP_NUMBER_TYPE:
case FILLER_TYPE:
case BYTE_ARRAY_TYPE:
- case FREE_SPACE_TYPE:
case EXTERNAL_PIXEL_ARRAY_TYPE:
case EXTERNAL_BYTE_ARRAY_TYPE:
case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
@@ -1611,6 +1508,8 @@
String* name,
JSFunction* function,
PropertyAttributes attributes) {
+ ASSERT(!GetHeap()->InNewSpace(function));
+
// Allocate new instance descriptors with (name, function) added
ConstantFunctionDescriptor d(name, function, attributes);
Object* new_descriptors;
@@ -1634,7 +1533,7 @@
// If the old map is the global object map (from new Object()),
// then transitions are not added to it, so we are done.
- Heap* heap = GetHeap();
+ Heap* heap = old_map->heap();
if (old_map == heap->isolate()->context()->global_context()->
object_function()->map()) {
return function;
@@ -1710,10 +1609,10 @@
StrictModeFlag strict_mode) {
ASSERT(!IsJSGlobalProxy());
Map* map_of_this = map();
- Heap* heap = GetHeap();
+ Heap* heap = map_of_this->heap();
if (!map_of_this->is_extensible()) {
if (strict_mode == kNonStrictMode) {
- return value;
+ return heap->undefined_value();
} else {
Handle<Object> args[1] = {Handle<String>(name)};
return heap->isolate()->Throw(
@@ -1725,7 +1624,7 @@
// Ensure the descriptor array does not get too big.
if (map_of_this->instance_descriptors()->number_of_descriptors() <
DescriptorArray::kMaxNumberOfDescriptors) {
- if (value->IsJSFunction()) {
+ if (value->IsJSFunction() && !heap->InNewSpace(value)) {
return AddConstantFunctionProperty(name,
JSFunction::cast(value),
attributes);
@@ -1752,21 +1651,13 @@
PropertyAttributes attributes,
StrictModeFlag strict_mode) {
// Check local property, ignore interceptor.
- LookupResult result(GetIsolate());
+ 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, strict_mode);
}
- bool found = false;
- MaybeObject* result_object;
- result_object = SetPropertyWithCallbackSetterInPrototypes(name,
- value,
- attributes,
- &found,
- strict_mode);
- if (found) return result_object;
// Add a new real property.
return AddProperty(name, value, attributes, strict_mode);
}
@@ -1780,7 +1671,7 @@
int new_enumeration_index = 0; // 0 means "Use the next available index."
if (old_index != -1) {
// All calls to ReplaceSlowProperty have had all transitions removed.
- ASSERT(!dictionary->ContainsTransition(old_index));
+ ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
new_enumeration_index = dictionary->DetailsAt(old_index).index();
}
@@ -1805,7 +1696,7 @@
return result;
}
// Do not add transitions to the map of "new Object()".
- if (map() == GetIsolate()->context()->global_context()->
+ if (map() == old_map->heap()->isolate()->context()->global_context()->
object_function()->map()) {
return result;
}
@@ -1930,22 +1821,11 @@
}
-Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
- Handle<String> key,
- Handle<Object> value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode) {
- CALL_HEAP_FUNCTION(object->GetIsolate(),
- object->SetProperty(*key, *value, attributes, strict_mode),
- Object);
-}
-
-
MaybeObject* JSReceiver::SetProperty(String* name,
Object* value,
PropertyAttributes attributes,
StrictModeFlag strict_mode) {
- LookupResult result(GetIsolate());
+ LookupResult result;
LocalLookup(name, &result);
return SetProperty(&result, name, value, attributes, strict_mode);
}
@@ -1970,7 +1850,7 @@
if (structure->IsForeign()) {
AccessorDescriptor* callback =
reinterpret_cast<AccessorDescriptor*>(
- Foreign::cast(structure)->foreign_address());
+ Foreign::cast(structure)->address());
MaybeObject* obj = (callback->setter)(this, value, callback->data);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
if (obj->IsFailure()) return obj;
@@ -1998,11 +1878,10 @@
return *value_handle;
}
- if (structure->IsAccessorPair()) {
- Object* setter = AccessorPair::cast(structure)->setter();
- if (setter->IsSpecFunction()) {
- // TODO(rossberg): nicer would be to cast to some JSCallable here...
- return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
+ if (structure->IsFixedArray()) {
+ Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
+ if (setter->IsJSFunction()) {
+ return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
} else {
if (strict_mode == kNonStrictMode) {
return value;
@@ -2021,24 +1900,22 @@
}
-MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
- Object* value) {
+MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
+ Object* value) {
Isolate* isolate = GetIsolate();
Handle<Object> value_handle(value, isolate);
- Handle<JSReceiver> fun(setter, isolate);
- Handle<JSReceiver> self(this, 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.
- // TODO(rossberg): should this apply to getters that are function proxies?
- if (debug->StepInActive() && fun->IsJSFunction()) {
- debug->HandleStepIn(
- Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
+ if (debug->StepInActive()) {
+ debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
}
#endif
bool has_pending_exception;
- Handle<Object> argv[] = { value_handle };
- Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
+ Object** argv[] = { value_handle.location() };
+ Execution::Call(fun, self, 1, argv, &has_pending_exception);
// Check for pending exception and return the result.
if (has_pending_exception) return Failure::Exception();
return *value_handle;
@@ -2051,9 +1928,6 @@
for (Object* pt = GetPrototype();
pt != heap->null_value();
pt = pt->GetPrototype()) {
- if (pt->IsJSProxy()) {
- return result->HandlerResult(JSProxy::cast(pt));
- }
JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
if (result->IsProperty()) {
if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
@@ -2074,16 +1948,6 @@
for (Object* pt = GetPrototype();
pt != heap->null_value();
pt = pt->GetPrototype()) {
- if (pt->IsJSProxy()) {
- String* name;
- MaybeObject* maybe = GetHeap()->Uint32ToString(index);
- if (!maybe->To<String>(&name)) {
- *found = true; // Force abort
- return maybe;
- }
- return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
- name, value, NONE, strict_mode, found);
- }
if (!JSObject::cast(pt)->HasDictionaryElements()) {
continue;
}
@@ -2106,48 +1970,6 @@
return heap->the_hole_value();
}
-MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
- String* name,
- Object* value,
- PropertyAttributes attributes,
- bool* found,
- StrictModeFlag strict_mode) {
- Heap* heap = GetHeap();
- // We could not find a local property so let's check whether there is an
- // accessor that wants to handle the property.
- LookupResult accessor_result(heap->isolate());
- LookupCallbackSetterInPrototypes(name, &accessor_result);
- if (accessor_result.IsFound()) {
- *found = true;
- if (accessor_result.type() == CALLBACKS) {
- return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
- name,
- value,
- accessor_result.holder(),
- strict_mode);
- } else if (accessor_result.type() == HANDLER) {
- // There is a proxy in the prototype chain. Invoke its
- // getPropertyDescriptor trap.
- bool found = false;
- // SetPropertyWithHandlerIfDefiningSetter can cause GC,
- // make sure to use the handlified references after calling
- // the function.
- Handle<JSObject> self(this);
- Handle<String> hname(name);
- Handle<Object> hvalue(value);
- MaybeObject* result =
- accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
- name, value, attributes, strict_mode, &found);
- if (found) return result;
- // The proxy does not define the property as an accessor.
- // Consequently, it has no effect on setting the receiver.
- return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
- }
- }
- *found = false;
- return heap->the_hole_value();
-}
-
void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
DescriptorArray* descriptors = map()->instance_descriptors();
@@ -2164,8 +1986,7 @@
String* name,
LookupResult* result) {
DescriptorArray* descriptors = instance_descriptors();
- DescriptorLookupCache* cache =
- GetHeap()->isolate()->descriptor_lookup_cache();
+ DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
int number = cache->Lookup(descriptors, name);
if (number == DescriptorLookupCache::kAbsent) {
number = descriptors->Search(name);
@@ -2179,295 +2000,75 @@
}
-static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
- ASSERT(!map.is_null());
- for (int i = 0; i < maps->length(); ++i) {
- if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
- }
- return false;
-}
-
-
-template <class T>
-static Handle<T> MaybeNull(T* p) {
- if (p == NULL) return Handle<T>::null();
- return Handle<T>(p);
-}
-
-
-Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
- ElementsKind elms_kind = elements_kind();
- if (elms_kind == FAST_DOUBLE_ELEMENTS) {
- bool dummy = true;
- Handle<Map> fast_map =
- MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
- if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
- return fast_map;
- }
- return Handle<Map>::null();
- }
- if (elms_kind == FAST_SMI_ONLY_ELEMENTS) {
- bool dummy = true;
- Handle<Map> double_map =
- MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy));
- // In the current implementation, if the DOUBLE map doesn't exist, the
- // FAST map can't exist either.
- if (double_map.is_null()) return Handle<Map>::null();
- Handle<Map> fast_map =
- MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
- &dummy));
- if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
- return fast_map;
- }
- if (ContainsMap(candidates, double_map)) return double_map;
- }
- return Handle<Map>::null();
-}
-
-static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
- ElementsKind elements_kind) {
- if (descriptor_contents->IsMap()) {
- Map* map = Map::cast(descriptor_contents);
- if (map->elements_kind() == elements_kind) {
- return map;
- }
- return NULL;
- }
-
- FixedArray* map_array = FixedArray::cast(descriptor_contents);
- for (int i = 0; i < map_array->length(); ++i) {
- Object* current = map_array->get(i);
- // Skip undefined slots, they are sentinels for reclaimed maps.
- if (!current->IsUndefined()) {
- Map* current_map = Map::cast(map_array->get(i));
- if (current_map->elements_kind() == elements_kind) {
- return current_map;
- }
- }
- }
-
- return NULL;
-}
-
-
-static MaybeObject* AddElementsTransitionMapToDescriptor(
- Object* descriptor_contents,
- Map* new_map) {
- // Nothing was in the descriptor for an ELEMENTS_TRANSITION,
- // simply add the map.
- if (descriptor_contents == NULL) {
- return new_map;
- }
-
- // There was already a map in the descriptor, create a 2-element FixedArray
- // to contain the existing map plus the new one.
- FixedArray* new_array;
- Heap* heap = new_map->GetHeap();
- if (descriptor_contents->IsMap()) {
- // Must tenure, DescriptorArray expects no new-space objects.
- MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED);
- if (!maybe_new_array->To<FixedArray>(&new_array)) {
- return maybe_new_array;
- }
- new_array->set(0, descriptor_contents);
- new_array->set(1, new_map);
- return new_array;
- }
-
- // The descriptor already contained a list of maps for different ElementKinds
- // of ELEMENTS_TRANSITION, first check the existing array for an undefined
- // slot, and if that's not available, create a FixedArray to hold the existing
- // maps plus the new one and fill it in.
- FixedArray* array = FixedArray::cast(descriptor_contents);
- for (int i = 0; i < array->length(); ++i) {
- if (array->get(i)->IsUndefined()) {
- array->set(i, new_map);
- return array;
- }
- }
-
- // Must tenure, DescriptorArray expects no new-space objects.
- MaybeObject* maybe_new_array =
- heap->AllocateFixedArray(array->length() + 1, TENURED);
- if (!maybe_new_array->To<FixedArray>(&new_array)) {
- return maybe_new_array;
- }
- int i = 0;
- while (i < array->length()) {
- new_array->set(i, array->get(i));
- ++i;
- }
- new_array->set(i, new_map);
- return new_array;
-}
-
-
-String* Map::elements_transition_sentinel_name() {
- return GetHeap()->empty_symbol();
-}
-
-
-Object* Map::GetDescriptorContents(String* sentinel_name,
- bool* safe_to_add_transition) {
- // Get the cached index for the descriptors lookup, or find and cache it.
+MaybeObject* Map::GetElementsTransitionMap(ElementsKind elements_kind,
+ bool safe_to_add_transition) {
+ Heap* current_heap = heap();
DescriptorArray* descriptors = instance_descriptors();
- DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache();
- int index = cache->Lookup(descriptors, sentinel_name);
- if (index == DescriptorLookupCache::kAbsent) {
- index = descriptors->Search(sentinel_name);
- cache->Update(descriptors, sentinel_name, index);
- }
- // If the transition already exists, return its descriptor.
- if (index != DescriptorArray::kNotFound) {
- PropertyDetails details(descriptors->GetDetails(index));
- if (details.type() == ELEMENTS_TRANSITION) {
- return descriptors->GetValue(index);
- } else {
- if (safe_to_add_transition != NULL) {
- *safe_to_add_transition = false;
- }
- }
- }
- return NULL;
-}
-
-
-Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
- bool* safe_to_add_transition) {
- // Special case: indirect SMI->FAST transition (cf. comment in
- // AddElementsTransition()).
- if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
- elements_kind == FAST_ELEMENTS) {
- Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
- safe_to_add_transition);
- if (double_map == NULL) return double_map;
- return double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
- safe_to_add_transition);
- }
- Object* descriptor_contents = GetDescriptorContents(
- elements_transition_sentinel_name(), safe_to_add_transition);
- if (descriptor_contents != NULL) {
- Map* maybe_transition_map =
- GetElementsTransitionMapFromDescriptor(descriptor_contents,
- elements_kind);
- ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
- return maybe_transition_map;
- }
- return NULL;
-}
-
-
-MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
- Map* transitioned_map) {
- // The map transition graph should be a tree, therefore the transition
- // from SMI to FAST elements is not done directly, but by going through
- // DOUBLE elements first.
- if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
- elements_kind == FAST_ELEMENTS) {
- bool safe_to_add = true;
- Map* double_map = this->LookupElementsTransitionMap(
- FAST_DOUBLE_ELEMENTS, &safe_to_add);
- // This method is only called when safe_to_add_transition has been found
- // to be true earlier.
- ASSERT(safe_to_add);
-
- if (double_map == NULL) {
- MaybeObject* maybe_map = this->CopyDropTransitions();
- if (!maybe_map->To(&double_map)) return maybe_map;
- double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
- MaybeObject* maybe_double_transition = this->AddElementsTransition(
- FAST_DOUBLE_ELEMENTS, double_map);
- if (maybe_double_transition->IsFailure()) return maybe_double_transition;
- }
- return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map);
- }
-
- bool safe_to_add_transition = true;
- Object* descriptor_contents = GetDescriptorContents(
- elements_transition_sentinel_name(), &safe_to_add_transition);
- // This method is only called when safe_to_add_transition has been found
- // to be true earlier.
- ASSERT(safe_to_add_transition);
- MaybeObject* maybe_new_contents =
- AddElementsTransitionMapToDescriptor(descriptor_contents,
- transitioned_map);
- Object* new_contents;
- if (!maybe_new_contents->ToObject(&new_contents)) {
- return maybe_new_contents;
- }
-
- ElementsTransitionDescriptor desc(elements_transition_sentinel_name(),
- new_contents);
- Object* new_descriptors;
- MaybeObject* maybe_new_descriptors =
- instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS);
- if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
- return maybe_new_descriptors;
- }
- set_instance_descriptors(DescriptorArray::cast(new_descriptors));
- return this;
-}
-
-
-Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
- ElementsKind to_kind) {
- Isolate* isolate = object->GetIsolate();
- CALL_HEAP_FUNCTION(isolate,
- object->GetElementsTransitionMap(isolate, to_kind),
- Map);
-}
-
-
-MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
- Map* current_map = map();
- ElementsKind from_kind = current_map->elements_kind();
-
- if (from_kind == to_kind) return current_map;
-
- // Only objects with FastProperties can have DescriptorArrays and can track
- // element-related maps. Also don't add descriptors to maps that are shared.
- bool safe_to_add_transition = HasFastProperties() &&
- !current_map->IsUndefined() &&
- !current_map->is_shared();
-
- // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
- // with elements that switch back and forth between dictionary and fast
- // element mode.
- if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
- safe_to_add_transition = false;
- }
+ String* elements_transition_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.
- Map* maybe_transition_map = current_map->LookupElementsTransitionMap(
- to_kind, &safe_to_add_transition);
- if (maybe_transition_map != NULL) {
- return maybe_transition_map;
+
+ ASSERT(!is_shared()); // no transitions can be added to shared maps.
+ // Check if the elements transition already exists.
+ DescriptorLookupCache* cache =
+ current_heap->isolate()->descriptor_lookup_cache();
+ int index = cache->Lookup(descriptors, elements_transition_sentinel_name);
+ if (index == DescriptorLookupCache::kAbsent) {
+ index = descriptors->Search(elements_transition_sentinel_name);
+ cache->Update(descriptors,
+ elements_transition_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() == ELEMENTS_TRANSITION &&
+ details.elements_kind() == elements_kind) {
+ return descriptors->GetValue(index);
+ } else {
+ safe_to_add_transition = false;
+ }
}
}
- Map* new_map = NULL;
-
// No transition to an existing map for the given ElementsKind. Make a new
// one.
- { MaybeObject* maybe_map = current_map->CopyDropTransitions();
- if (!maybe_map->To(&new_map)) return maybe_map;
+ Object* obj;
+ { MaybeObject* maybe_map = CopyDropTransitions();
+ if (!maybe_map->ToObject(&obj)) return maybe_map;
}
+ Map* new_map = Map::cast(obj);
- new_map->set_elements_kind(to_kind);
+ new_map->set_elements_kind(elements_kind);
+ 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 element transition.
- Context* global_context = GetIsolate()->context()->global_context();
- bool allow_map_transition = safe_to_add_transition &&
- (global_context->object_function()->map() != map());
+ bool allow_map_transition =
+ safe_to_add_transition &&
+ (GetIsolate()->context()->global_context()->object_function()->map() !=
+ map());
if (allow_map_transition) {
- MaybeObject* maybe_transition =
- current_map->AddElementsTransition(to_kind, new_map);
- if (maybe_transition->IsFailure()) return maybe_transition;
+ // Allocate new instance descriptors for the old map with map transition.
+ ElementsTransitionDescriptor desc(elements_transition_sentinel_name,
+ Map::cast(new_map),
+ elements_kind);
+ 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;
}
@@ -2478,7 +2079,6 @@
Object* proto = GetPrototype();
if (proto->IsNull()) return result->NotFound();
ASSERT(proto->IsJSGlobalObject());
- // A GlobalProxy's prototype should always be a proper JSObject.
return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
}
@@ -2573,7 +2173,7 @@
case INTERCEPTOR: {
// Try lookup real named properties. Note that only property can be
// set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
- LookupResult r(GetIsolate());
+ LookupResult r;
LookupRealNamedProperty(name, &r);
if (r.IsProperty()) {
return SetPropertyWithFailedAccessCheck(&r,
@@ -2591,10 +2191,10 @@
}
}
- Isolate* isolate = GetIsolate();
- HandleScope scope(isolate);
+ Heap* heap = GetHeap();
+ HandleScope scope(heap->isolate());
Handle<Object> value_handle(value);
- isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
return *value_handle;
}
@@ -2605,7 +2205,7 @@
PropertyAttributes attributes,
StrictModeFlag strict_mode) {
if (result->IsFound() && result->type() == HANDLER) {
- return result->proxy()->SetPropertyWithHandler(
+ return JSProxy::cast(this)->SetPropertyWithHandler(
key, value, attributes, strict_mode);
} else {
return JSObject::cast(this)->SetPropertyForResult(
@@ -2619,11 +2219,22 @@
HandleScope scope(isolate);
Handle<Object> receiver(this);
Handle<Object> name(name_raw);
+ Handle<Object> handler(this->handler());
- Handle<Object> args[] = { name };
- Handle<Object> result = CallTrap(
- "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
+ // Extract trap function.
+ Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
+ Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
if (isolate->has_pending_exception()) return Failure::Exception();
+ if (trap->IsUndefined()) {
+ trap = isolate->derived_has_trap();
+ }
+
+ // Call trap function.
+ Object** args[] = { name.location() };
+ bool has_exception;
+ Handle<Object> result =
+ Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
+ if (has_exception) return Failure::Exception();
return result->ToBoolean()->IsTrue();
}
@@ -2639,85 +2250,24 @@
Handle<Object> receiver(this);
Handle<Object> name(name_raw);
Handle<Object> value(value_raw);
+ Handle<Object> handler(this->handler());
- Handle<Object> args[] = { receiver, name, value };
- CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
+ // Extract trap function.
+ Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set");
+ Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
if (isolate->has_pending_exception()) return Failure::Exception();
-
- return *value;
-}
-
-
-MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
- String* name_raw,
- Object* value_raw,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode,
- bool* found) {
- *found = true; // except where defined otherwise...
- Isolate* isolate = GetHeap()->isolate();
- Handle<JSProxy> proxy(this);
- Handle<Object> handler(this->handler()); // Trap might morph proxy.
- Handle<String> name(name_raw);
- Handle<Object> value(value_raw);
- Handle<Object> args[] = { name };
- Handle<Object> result = proxy->CallTrap(
- "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
- if (isolate->has_pending_exception()) return Failure::Exception();
-
- if (!result->IsUndefined()) {
- // The proxy handler cares about this property.
- // Check whether it is virtualized as an accessor.
- // Emulate [[GetProperty]] semantics for proxies.
- bool has_pending_exception;
- Handle<Object> argv[] = { result };
- Handle<Object> desc =
- Execution::Call(isolate->to_complete_property_descriptor(), result,
- ARRAY_SIZE(argv), argv, &has_pending_exception);
- if (has_pending_exception) return Failure::Exception();
-
- Handle<String> conf_name =
- isolate->factory()->LookupAsciiSymbol("configurable_");
- Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
- ASSERT(!isolate->has_pending_exception());
- if (configurable->IsFalse()) {
- Handle<String> trap =
- isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
- Handle<Object> args[] = { handler, trap, name };
- Handle<Object> error = isolate->factory()->NewTypeError(
- "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
- return isolate->Throw(*error);
- }
- ASSERT(configurable->IsTrue());
-
- // Check for AccessorDescriptor.
- Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
- Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
- ASSERT(!isolate->has_pending_exception());
- if (!setter->IsUndefined()) {
- // We have a setter -- invoke it.
- // TODO(rossberg): nicer would be to cast to some JSCallable here...
- return proxy->SetPropertyWithDefinedSetter(
- JSReceiver::cast(*setter), *value);
- } else {
- Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
- Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
- ASSERT(!isolate->has_pending_exception());
- if (!getter->IsUndefined()) {
- // We have a getter but no setter -- the property may not be
- // written. In strict mode, throw an error.
- if (strict_mode == kNonStrictMode) return *value;
- Handle<Object> args[] = { name, proxy };
- Handle<Object> error = isolate->factory()->NewTypeError(
- "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
- return isolate->Throw(*error);
- }
- }
- // Fall-through.
+ if (trap->IsUndefined()) {
+ trap = isolate->derived_set_trap();
}
- // The proxy does not define the property as an accessor.
- *found = false;
+ // Call trap function.
+ Object** args[] = {
+ receiver.location(), name.location(), value.location()
+ };
+ bool has_exception;
+ Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
+ if (has_exception) return Failure::Exception();
+
return *value;
}
@@ -2728,16 +2278,31 @@
HandleScope scope(isolate);
Handle<Object> receiver(this);
Handle<Object> name(name_raw);
+ Handle<Object> handler(this->handler());
- Handle<Object> args[] = { name };
- Handle<Object> result = CallTrap(
- "delete", Handle<Object>(), ARRAY_SIZE(args), args);
+ // Extract trap function.
+ Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
+ Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
if (isolate->has_pending_exception()) return Failure::Exception();
+ if (trap->IsUndefined()) {
+ Handle<Object> args[] = { handler, trap_name };
+ Handle<Object> error = isolate->factory()->NewTypeError(
+ "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
+ isolate->Throw(*error);
+ return Failure::Exception();
+ }
+
+ // Call trap function.
+ Object** args[] = { name.location() };
+ bool has_exception;
+ Handle<Object> result =
+ Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
+ if (has_exception) return Failure::Exception();
Object* bool_result = result->ToBoolean();
- if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
- Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
- Handle<Object> args[] = { Handle<Object>(handler()), trap_name };
+ if (mode == STRICT_DELETION &&
+ bool_result == isolate->heap()->false_value()) {
+ Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
"handler_failed", HandleVector(args, ARRAY_SIZE(args)));
isolate->Throw(*error);
@@ -2747,76 +2312,39 @@
}
-MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
- uint32_t index,
- DeleteMode mode) {
- Isolate* isolate = GetIsolate();
- HandleScope scope(isolate);
- Handle<String> name = isolate->factory()->Uint32ToString(index);
- return JSProxy::DeletePropertyWithHandler(*name, mode);
-}
-
-
MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
JSReceiver* receiver_raw,
- String* name_raw) {
+ String* name_raw,
+ bool* has_exception) {
Isolate* isolate = GetIsolate();
HandleScope scope(isolate);
- Handle<JSProxy> proxy(this);
- Handle<Object> handler(this->handler()); // Trap might morph proxy.
Handle<JSReceiver> receiver(receiver_raw);
Handle<Object> name(name_raw);
+ Handle<Object> handler(this->handler());
- Handle<Object> args[] = { name };
- Handle<Object> result = CallTrap(
- "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
+ // Extract trap function.
+ Handle<String> trap_name =
+ isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
+ Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
if (isolate->has_pending_exception()) return NONE;
-
- if (result->IsUndefined()) return ABSENT;
-
- bool has_pending_exception;
- Handle<Object> argv[] = { result };
- Handle<Object> desc =
- Execution::Call(isolate->to_complete_property_descriptor(), result,
- ARRAY_SIZE(argv), argv, &has_pending_exception);
- if (has_pending_exception) return NONE;
-
- // Convert result to PropertyAttributes.
- Handle<String> enum_n = isolate->factory()->LookupAsciiSymbol("enumerable");
- Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_n));
- if (isolate->has_pending_exception()) return NONE;
- Handle<String> conf_n = isolate->factory()->LookupAsciiSymbol("configurable");
- Handle<Object> configurable(v8::internal::GetProperty(desc, conf_n));
- if (isolate->has_pending_exception()) return NONE;
- Handle<String> writ_n = isolate->factory()->LookupAsciiSymbol("writable");
- Handle<Object> writable(v8::internal::GetProperty(desc, writ_n));
- if (isolate->has_pending_exception()) return NONE;
-
- if (configurable->IsFalse()) {
- Handle<String> trap =
- isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
- Handle<Object> args[] = { handler, trap, name };
+ if (trap->IsUndefined()) {
+ Handle<Object> args[] = { handler, trap_name };
Handle<Object> error = isolate->factory()->NewTypeError(
- "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
+ "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
isolate->Throw(*error);
+ *has_exception = true;
return NONE;
}
- int attributes = NONE;
- if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM;
- if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE;
- if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY;
- return static_cast<PropertyAttributes>(attributes);
-}
+ // Call trap function.
+ Object** args[] = { name.location() };
+ Handle<Object> result =
+ Execution::Call(trap, handler, ARRAY_SIZE(args), args, has_exception);
+ if (has_exception) return NONE;
-
-MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
- JSReceiver* receiver,
- uint32_t index) {
- Isolate* isolate = GetIsolate();
- HandleScope scope(isolate);
- Handle<String> name = isolate->factory()->Uint32ToString(index);
- return GetPropertyAttributeWithHandler(receiver, *name);
+ // TODO(rossberg): convert result to PropertyAttributes
+ USE(result);
+ return NONE;
}
@@ -2825,9 +2353,6 @@
HandleScope scope(isolate);
Handle<JSProxy> self(this);
- // Save identity hash.
- MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
-
if (IsJSFunctionProxy()) {
isolate->factory()->BecomeJSFunction(self);
// Code will be set on the JavaScript side.
@@ -2835,42 +2360,9 @@
isolate->factory()->BecomeJSObject(self);
}
ASSERT(self->IsJSObject());
-
- // Inherit identity, if it was present.
- Object* hash;
- if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
- Handle<JSObject> new_self(JSObject::cast(*self));
- isolate->factory()->SetIdentityHash(new_self, hash);
- }
}
-MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
- Handle<Object> derived,
- int argc,
- Handle<Object> argv[]) {
- Isolate* isolate = GetIsolate();
- Handle<Object> handler(this->handler());
-
- Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol(name);
- Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
- if (isolate->has_pending_exception()) return trap;
-
- if (trap->IsUndefined()) {
- if (derived.is_null()) {
- Handle<Object> args[] = { handler, trap_name };
- Handle<Object> error = isolate->factory()->NewTypeError(
- "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
- isolate->Throw(*error);
- return Handle<Object>();
- }
- trap = Handle<Object>(derived);
- }
-
- bool threw;
- return Execution::Call(trap, handler, argc, argv, &threw);
-}
-
MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
String* name,
@@ -2895,46 +2387,48 @@
}
// Check access rights if needed.
- if (IsAccessCheckNeeded()) {
- if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
- return SetPropertyWithFailedAccessCheck(
- result, name, value, true, strict_mode);
- }
+ if (IsAccessCheckNeeded()
+ && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
+ return SetPropertyWithFailedAccessCheck(result,
+ name,
+ value,
+ true,
+ strict_mode);
}
if (IsJSGlobalProxy()) {
Object* proto = GetPrototype();
if (proto->IsNull()) return value;
ASSERT(proto->IsJSGlobalObject());
- return JSObject::cast(proto)->SetPropertyForResult(
+ return JSObject::cast(proto)->SetProperty(
result, name, value, attributes, strict_mode);
}
if (!result->IsProperty() && !IsJSContextExtensionObject()) {
- bool found = false;
- MaybeObject* result_object;
- result_object = SetPropertyWithCallbackSetterInPrototypes(name,
- value,
- attributes,
- &found,
- strict_mode);
- if (found) return result_object;
+ // We could not find a local property so let's check whether there is an
+ // accessor that wants to handle the property.
+ LookupResult accessor_result;
+ LookupCallbackSetterInPrototypes(name, &accessor_result);
+ if (accessor_result.IsProperty()) {
+ return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
+ name,
+ value,
+ accessor_result.holder(),
+ strict_mode);
+ }
}
-
- // At this point, no GC should have happened, as this would invalidate
- // 'result', which we cannot handlify!
-
if (!result->IsFound()) {
// Neither properties nor transitions found.
return AddProperty(name, value, attributes, strict_mode);
}
if (result->IsReadOnly() && result->IsProperty()) {
if (strict_mode == kStrictMode) {
- Handle<JSObject> self(this);
- Handle<String> hname(name);
- Handle<Object> args[] = { hname, self };
+ HandleScope scope(heap->isolate());
+ 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, ARRAY_SIZE(args))));
+ "strict_read_only_property", HandleVector(args, 2)));
} else {
return value;
}
@@ -2978,6 +2472,7 @@
ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
JSFunction* function =
JSFunction::cast(target_descriptors->GetValue(number));
+ ASSERT(!HEAP->InNewSpace(function));
if (value == function) {
set_map(target_map);
return value;
@@ -2989,11 +2484,10 @@
case NULL_DESCRIPTOR:
case ELEMENTS_TRANSITION:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
- case HANDLER:
+ default:
UNREACHABLE();
- return value;
}
- UNREACHABLE(); // keep the compiler happy
+ UNREACHABLE();
return value;
}
@@ -3007,18 +2501,6 @@
// Note that this method cannot be used to set the prototype of a function
// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
// doesn't handle function prototypes correctly.
-Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
- Handle<JSObject> object,
- Handle<String> key,
- Handle<Object> value,
- PropertyAttributes attributes) {
- CALL_HEAP_FUNCTION(
- object->GetIsolate(),
- object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
- Object);
-}
-
-
MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
String* name,
Object* value,
@@ -3027,12 +2509,12 @@
// Make sure that the top context does not change when doing callbacks or
// interceptor calls.
AssertNoContextChange ncc;
- Isolate* isolate = GetIsolate();
- LookupResult result(isolate);
+ LookupResult result;
LocalLookup(name, &result);
// Check access rights if needed.
if (IsAccessCheckNeeded()) {
- if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
+ Heap* heap = GetHeap();
+ if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
return SetPropertyWithFailedAccessCheck(&result,
name,
value,
@@ -3090,11 +2572,10 @@
case NULL_DESCRIPTOR:
case ELEMENTS_TRANSITION:
return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
- case HANDLER:
+ default:
UNREACHABLE();
- return value;
}
- UNREACHABLE(); // keep the compiler happy
+ UNREACHABLE();
return value;
}
@@ -3104,7 +2585,7 @@
String* name,
bool continue_search) {
// Check local property, ignore interceptor.
- LookupResult result(GetIsolate());
+ LookupResult result;
LocalLookupRealNamedProperty(name, &result);
if (result.IsProperty()) return result.GetAttributes();
@@ -3176,11 +2657,12 @@
String* key) {
uint32_t index = 0;
if (IsJSObject() && key->AsArrayIndex(&index)) {
- return JSObject::cast(this)->HasElementWithReceiver(receiver, index)
- ? NONE : ABSENT;
+ if (JSObject::cast(this)->HasElementWithReceiver(receiver, index))
+ return NONE;
+ return ABSENT;
}
// Named property.
- LookupResult result(GetIsolate());
+ LookupResult result;
Lookup(key, &result);
return GetPropertyAttribute(receiver, &result, key, true);
}
@@ -3207,8 +2689,10 @@
case CALLBACKS:
return result->GetAttributes();
case HANDLER: {
- return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler(
- receiver, name);
+ // TODO(rossberg): propagate exceptions properly.
+ bool has_exception = false;
+ return JSProxy::cast(this)->GetPropertyAttributeWithHandler(
+ receiver, name, &has_exception);
}
case INTERCEPTOR:
return result->holder()->GetPropertyAttributeWithInterceptor(
@@ -3229,7 +2713,7 @@
return ABSENT;
}
// Named property.
- LookupResult result(GetIsolate());
+ LookupResult result;
LocalLookup(name, &result);
return GetPropertyAttribute(this, &result, name, false);
}
@@ -3244,9 +2728,7 @@
if (result->IsMap() &&
Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
#ifdef DEBUG
- if (FLAG_verify_heap) {
- Map::cast(result)->SharedMapVerify();
- }
+ Map::cast(result)->SharedMapVerify();
if (FLAG_enable_slow_asserts) {
// The cached map should match newly created normalized map bit-by-bit.
Object* fresh;
@@ -3282,15 +2764,6 @@
}
-void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
- Handle<String> name,
- Handle<Code> code) {
- Isolate* isolate = object->GetIsolate();
- CALL_HEAP_FUNCTION_VOID(isolate,
- object->UpdateMapCodeCache(*name, *code));
-}
-
-
MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
if (map()->is_shared()) {
// Fast case maps are never marked as shared.
@@ -3309,15 +2782,6 @@
}
-void JSObject::NormalizeProperties(Handle<JSObject> object,
- PropertyNormalizationMode mode,
- int expected_additional_properties) {
- CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
- object->NormalizeProperties(
- mode, expected_additional_properties));
-}
-
-
MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
int expected_additional_properties) {
if (!HasFastProperties()) return this;
@@ -3336,10 +2800,12 @@
} else {
property_count += 2; // Make space for two more properties.
}
- StringDictionary* dictionary;
- { MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count);
- if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
+ Object* obj;
+ { MaybeObject* maybe_obj =
+ StringDictionary::Allocate(property_count);
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
+ StringDictionary* dictionary = StringDictionary::cast(obj);
DescriptorArray* descs = map_of_this->instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
@@ -3349,31 +2815,36 @@
PropertyDetails d =
PropertyDetails(details.attributes(), NORMAL, details.index());
Object* value = descs->GetConstantFunction(i);
- MaybeObject* maybe_dictionary =
- dictionary->Add(descs->GetKey(i), value, d);
- if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
+ Object* result;
+ { MaybeObject* maybe_result =
+ dictionary->Add(descs->GetKey(i), value, d);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ dictionary = StringDictionary::cast(result);
break;
}
case FIELD: {
PropertyDetails d =
PropertyDetails(details.attributes(), NORMAL, details.index());
Object* value = FastPropertyAt(descs->GetFieldIndex(i));
- MaybeObject* maybe_dictionary =
- dictionary->Add(descs->GetKey(i), value, d);
- if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
+ Object* result;
+ { MaybeObject* maybe_result =
+ dictionary->Add(descs->GetKey(i), value, d);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ dictionary = StringDictionary::cast(result);
break;
}
case CALLBACKS: {
- if (!descs->IsProperty(i)) break;
+ PropertyDetails d =
+ PropertyDetails(details.attributes(), CALLBACKS, details.index());
Object* value = descs->GetCallbacksObject(i);
- if (value->IsAccessorPair()) {
- MaybeObject* maybe_copy =
- AccessorPair::cast(value)->CopyWithoutTransitions();
- if (!maybe_copy->To(&value)) return maybe_copy;
+ Object* result;
+ { MaybeObject* maybe_result =
+ dictionary->Add(descs->GetKey(i), value, d);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
}
- MaybeObject* maybe_dictionary =
- dictionary->Add(descs->GetKey(i), value, details);
- if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
+ dictionary = StringDictionary::cast(result);
break;
}
case MAP_TRANSITION:
@@ -3382,25 +2853,23 @@
case INTERCEPTOR:
case ELEMENTS_TRANSITION:
break;
- case HANDLER:
- case NORMAL:
+ default:
UNREACHABLE();
- break;
}
}
- Heap* current_heap = GetHeap();
+ Heap* current_heap = map_of_this->heap();
// Copy the next enumeration index from instance descriptor.
int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
dictionary->SetNextEnumerationIndex(index);
- Map* new_map;
- { MaybeObject* maybe_map =
+ { MaybeObject* maybe_obj =
current_heap->isolate()->context()->global_context()->
normalized_map_cache()->Get(this, mode);
- if (!maybe_map->To(&new_map)) return maybe_map;
+ 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.
@@ -3411,11 +2880,6 @@
ASSERT(instance_size_delta >= 0);
current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
instance_size_delta);
- if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
- MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
- -instance_size_delta);
- }
-
set_map(new_map);
new_map->clear_instance_descriptors();
@@ -3434,14 +2898,6 @@
}
-void JSObject::TransformToFastProperties(Handle<JSObject> object,
- int unused_property_fields) {
- CALL_HEAP_FUNCTION_VOID(
- object->GetIsolate(),
- object->TransformToFastProperties(unused_property_fields));
-}
-
-
MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
if (HasFastProperties()) return this;
ASSERT(!IsGlobalObject());
@@ -3450,14 +2906,6 @@
}
-Handle<SeededNumberDictionary> JSObject::NormalizeElements(
- Handle<JSObject> object) {
- CALL_HEAP_FUNCTION(object->GetIsolate(),
- object->NormalizeElements(),
- SeededNumberDictionary);
-}
-
-
MaybeObject* JSObject::NormalizeElements() {
ASSERT(!HasExternalArrayElements());
@@ -3465,14 +2913,13 @@
FixedArrayBase* array = FixedArrayBase::cast(elements());
Map* old_map = array->map();
bool is_arguments =
- (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
+ (old_map == old_map->heap()->non_strict_arguments_elements_map());
if (is_arguments) {
array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
}
if (array->IsDictionary()) return array;
ASSERT(HasFastElements() ||
- HasFastSmiOnlyElements() ||
HasFastDoubleElements() ||
HasFastArgumentsElements());
// Compute the effective length and allocate a new backing store.
@@ -3507,8 +2954,7 @@
if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
}
} else {
- ASSERT(old_map->has_fast_elements() ||
- old_map->has_fast_smi_only_elements());
+ ASSERT(old_map->has_fast_elements());
value = FixedArray::cast(array)->get(i);
}
PropertyDetails details = PropertyDetails(NONE, NORMAL);
@@ -3528,15 +2974,13 @@
// Set the new map first to satify the elements type assert in
// set_elements().
Object* new_map;
- MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
- DICTIONARY_ELEMENTS);
+ MaybeObject* maybe = map()->GetSlowElementsMap();
if (!maybe->ToObject(&new_map)) return maybe;
set_map(Map::cast(new_map));
set_elements(dictionary);
}
- old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
- Increment();
+ old_map->isolate()->counters()->elements_to_dictionary()->Increment();
#ifdef DEBUG
if (FLAG_trace_normalization) {
@@ -3550,252 +2994,102 @@
}
-Smi* JSReceiver::GenerateIdentityHash() {
+MaybeObject* JSObject::GetHiddenProperties(HiddenPropertiesFlag flag) {
Isolate* isolate = GetIsolate();
+ Heap* heap = isolate->heap();
+ Object* holder = BypassGlobalProxy();
+ if (holder->IsUndefined()) return heap->undefined_value();
+ JSObject* obj = JSObject::cast(holder);
+ if (obj->HasFastProperties()) {
+ // If the object has fast properties, check whether the first slot
+ // in the descriptor array matches the hidden symbol. Since the
+ // hidden symbols hash code is zero (and no other string has hash
+ // code zero) it will always occupy the first entry if present.
+ DescriptorArray* descriptors = obj->map()->instance_descriptors();
+ if ((descriptors->number_of_descriptors() > 0) &&
+ (descriptors->GetKey(0) == heap->hidden_symbol()) &&
+ descriptors->IsProperty(0)) {
+ ASSERT(descriptors->GetType(0) == FIELD);
+ return obj->FastPropertyAt(descriptors->GetFieldIndex(0));
+ }
+ }
+
+ // Only attempt to find the hidden properties in the local object and not
+ // in the prototype chain.
+ if (!obj->HasHiddenPropertiesObject()) {
+ // Hidden properties object not found. Allocate a new hidden properties
+ // object if requested. Otherwise return the undefined value.
+ if (flag == ALLOW_CREATION) {
+ Object* hidden_obj;
+ { MaybeObject* maybe_obj = heap->AllocateJSObject(
+ isolate->context()->global_context()->object_function());
+ if (!maybe_obj->ToObject(&hidden_obj)) return maybe_obj;
+ }
+ // Don't allow leakage of the hidden object through accessors
+ // on Object.prototype.
+ {
+ MaybeObject* maybe_obj =
+ JSObject::cast(hidden_obj)->SetPrototype(heap->null_value(), false);
+ if (maybe_obj->IsFailure()) return maybe_obj;
+ }
+ return obj->SetHiddenPropertiesObject(hidden_obj);
+ } else {
+ return heap->undefined_value();
+ }
+ }
+ return obj->GetHiddenPropertiesObject();
+}
+
+
+MaybeObject* JSObject::GetIdentityHash(HiddenPropertiesFlag flag) {
+ Isolate* isolate = GetIsolate();
+ Object* hidden_props_obj;
+ { MaybeObject* maybe_obj = GetHiddenProperties(flag);
+ if (!maybe_obj->ToObject(&hidden_props_obj)) return maybe_obj;
+ }
+ if (!hidden_props_obj->IsJSObject()) {
+ // We failed to create hidden properties. That's a detached
+ // global proxy.
+ ASSERT(hidden_props_obj->IsUndefined());
+ return Smi::FromInt(0);
+ }
+ JSObject* hidden_props = JSObject::cast(hidden_props_obj);
+ String* hash_symbol = isolate->heap()->identity_hash_symbol();
+ {
+ // Note that HasLocalProperty() can cause a GC in the general case in the
+ // presence of interceptors.
+ AssertNoAllocation no_alloc;
+ if (hidden_props->HasLocalProperty(hash_symbol)) {
+ MaybeObject* hash = hidden_props->GetProperty(hash_symbol);
+ return Smi::cast(hash->ToObjectChecked());
+ }
+ }
int hash_value;
int attempts = 0;
do {
// Generate a random 32-bit hash value but limit range to fit
// within a smi.
- hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
+ hash_value = V8::Random(isolate) & Smi::kMaxValue;
attempts++;
} while (hash_value == 0 && attempts < 30);
hash_value = hash_value != 0 ? hash_value : 1; // never return 0
- return Smi::FromInt(hash_value);
-}
-
-
-MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
- MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
- hash);
- if (maybe->IsFailure()) return maybe;
- return this;
-}
-
-
-int JSObject::GetIdentityHash(Handle<JSObject> obj) {
- CALL_AND_RETRY(obj->GetIsolate(),
- obj->GetIdentityHash(ALLOW_CREATION),
- return Smi::cast(__object__)->value(),
- return 0);
-}
-
-
-MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
- Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
- if (stored_value->IsSmi()) return stored_value;
-
- // Do not generate permanent identity hash code if not requested.
- if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
-
- Smi* hash = GenerateIdentityHash();
- MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
- hash);
- if (result->IsFailure()) return result;
- if (result->ToObjectUnchecked()->IsUndefined()) {
- // Trying to get hash of detached proxy.
- return Smi::FromInt(0);
+ Smi* hash = Smi::FromInt(hash_value);
+ { MaybeObject* result = hidden_props->SetLocalPropertyIgnoreAttributes(
+ hash_symbol,
+ hash,
+ static_cast<PropertyAttributes>(None));
+ if (result->IsFailure()) return result;
}
return hash;
}
-MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
- Object* hash = this->hash();
- if (!hash->IsSmi() && flag == ALLOW_CREATION) {
- hash = GenerateIdentityHash();
- set_hash(hash);
- }
- return hash;
-}
-
-
-Object* JSObject::GetHiddenProperty(String* key) {
- if (IsJSGlobalProxy()) {
- // For a proxy, use the prototype as target object.
- Object* proxy_parent = GetPrototype();
- // If the proxy is detached, return undefined.
- if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
- ASSERT(proxy_parent->IsJSGlobalObject());
- return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
- }
- ASSERT(!IsJSGlobalProxy());
- MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
- ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
- if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
- return GetHeap()->undefined_value();
- }
- StringDictionary* dictionary =
- StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
- int entry = dictionary->FindEntry(key);
- if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
- return dictionary->ValueAt(entry);
-}
-
-
-Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
- Handle<String> key,
- Handle<Object> value) {
- CALL_HEAP_FUNCTION(obj->GetIsolate(),
- obj->SetHiddenProperty(*key, *value),
- Object);
-}
-
-
-MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
- if (IsJSGlobalProxy()) {
- // For a proxy, use the prototype as target object.
- Object* proxy_parent = GetPrototype();
- // If the proxy is detached, return undefined.
- if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
- ASSERT(proxy_parent->IsJSGlobalObject());
- return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
- }
- ASSERT(!IsJSGlobalProxy());
- MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
- StringDictionary* dictionary;
- if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
-
- // If it was found, check if the key is already in the dictionary.
- int entry = dictionary->FindEntry(key);
- if (entry != StringDictionary::kNotFound) {
- // If key was found, just update the value.
- dictionary->ValueAtPut(entry, value);
- return this;
- }
- // Key was not already in the dictionary, so add the entry.
- MaybeObject* insert_result = dictionary->Add(key,
- value,
- PropertyDetails(NONE, NORMAL));
- StringDictionary* new_dict;
- if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
- if (new_dict != dictionary) {
- // If adding the key expanded the dictionary (i.e., Add returned a new
- // dictionary), store it back to the object.
- MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
- if (store_result->IsFailure()) return store_result;
- }
- // Return this to mark success.
- return this;
-}
-
-
-void JSObject::DeleteHiddenProperty(String* key) {
- if (IsJSGlobalProxy()) {
- // For a proxy, use the prototype as target object.
- Object* proxy_parent = GetPrototype();
- // If the proxy is detached, return immediately.
- if (proxy_parent->IsNull()) return;
- ASSERT(proxy_parent->IsJSGlobalObject());
- JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
- return;
- }
- MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
- ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
- if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
- StringDictionary* dictionary =
- StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
- int entry = dictionary->FindEntry(key);
- if (entry == StringDictionary::kNotFound) {
- // Key wasn't in dictionary. Deletion is a success.
- return;
- }
- // Key was in the dictionary. Remove it.
- dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
-}
-
-
-bool JSObject::HasHiddenProperties() {
- return GetPropertyAttributePostInterceptor(this,
- GetHeap()->hidden_symbol(),
- false) != ABSENT;
-}
-
-
-MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
- ASSERT(!IsJSGlobalProxy());
- if (HasFastProperties()) {
- // If the object has fast properties, check whether the first slot
- // in the descriptor array matches the hidden symbol. Since the
- // hidden symbols hash code is zero (and no other string has hash
- // code zero) it will always occupy the first entry if present.
- DescriptorArray* descriptors = this->map()->instance_descriptors();
- if ((descriptors->number_of_descriptors() > 0) &&
- (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
- if (descriptors->GetType(0) == FIELD) {
- Object* hidden_store =
- this->FastPropertyAt(descriptors->GetFieldIndex(0));
- return StringDictionary::cast(hidden_store);
- } else {
- ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
- descriptors->GetType(0) == MAP_TRANSITION);
- }
- }
- } else {
- PropertyAttributes attributes;
- // You can't install a getter on a property indexed by the hidden symbol,
- // so we can be sure that GetLocalPropertyPostInterceptor returns a real
- // object.
- Object* lookup =
- GetLocalPropertyPostInterceptor(this,
- GetHeap()->hidden_symbol(),
- &attributes)->ToObjectUnchecked();
- if (!lookup->IsUndefined()) {
- return StringDictionary::cast(lookup);
- }
- }
- if (!create_if_absent) return GetHeap()->undefined_value();
- const int kInitialSize = 5;
- MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
- StringDictionary* dictionary;
- if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
- MaybeObject* store_result =
- SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
- dictionary,
- DONT_ENUM,
- kNonStrictMode);
- if (store_result->IsFailure()) return store_result;
- return dictionary;
-}
-
-
-MaybeObject* JSObject::SetHiddenPropertiesDictionary(
- StringDictionary* dictionary) {
- ASSERT(!IsJSGlobalProxy());
- ASSERT(HasHiddenProperties());
- if (HasFastProperties()) {
- // If the object has fast properties, check whether the first slot
- // in the descriptor array matches the hidden symbol. Since the
- // hidden symbols hash code is zero (and no other string has hash
- // code zero) it will always occupy the first entry if present.
- DescriptorArray* descriptors = this->map()->instance_descriptors();
- if ((descriptors->number_of_descriptors() > 0) &&
- (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
- if (descriptors->GetType(0) == FIELD) {
- this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
- return this;
- } else {
- ASSERT(descriptors->GetType(0) == NULL_DESCRIPTOR ||
- descriptors->GetType(0) == MAP_TRANSITION);
- }
- }
- }
- MaybeObject* store_result =
- SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
- dictionary,
- DONT_ENUM,
- kNonStrictMode);
- if (store_result->IsFailure()) return store_result;
- return this;
-}
-
-
MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
DeleteMode mode) {
// Check local property, ignore interceptor.
- LookupResult result(GetIsolate());
+ LookupResult result;
LocalLookupRealNamedProperty(name, &result);
if (!result.IsProperty()) return GetHeap()->true_value();
@@ -3877,14 +3171,6 @@
}
-Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
- uint32_t index) {
- CALL_HEAP_FUNCTION(obj->GetIsolate(),
- obj->DeleteElement(index, JSObject::NORMAL_DELETION),
- Object);
-}
-
-
MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Isolate* isolate = GetIsolate();
// Check access rights if needed.
@@ -3913,11 +3199,12 @@
}
-Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj,
- Handle<String> prop) {
- CALL_HEAP_FUNCTION(obj->GetIsolate(),
- obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
- Object);
+MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
+ if (IsJSProxy()) {
+ return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
+ } else {
+ return JSObject::cast(this)->DeleteProperty(name, mode);
+ }
}
@@ -3944,7 +3231,7 @@
if (name->AsArrayIndex(&index)) {
return DeleteElement(index, mode);
} else {
- LookupResult result(isolate);
+ LookupResult result;
LocalLookup(name, &result);
if (!result.IsProperty()) return isolate->heap()->true_value();
// Ignore attributes if forcing a deletion.
@@ -3978,27 +3265,10 @@
}
-MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
- if (IsJSProxy()) {
- return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
- }
- return JSObject::cast(this)->DeleteElement(index, mode);
-}
-
-
-MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
- if (IsJSProxy()) {
- return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
- }
- return JSObject::cast(this)->DeleteProperty(name, mode);
-}
-
-
bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
ElementsKind kind,
Object* object) {
- ASSERT(kind == FAST_ELEMENTS ||
- kind == DICTIONARY_ELEMENTS);
+ ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
if (kind == FAST_ELEMENTS) {
int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value()
@@ -4019,7 +3289,7 @@
// Check whether this object references another object.
bool JSObject::ReferencesObject(Object* obj) {
Map* map_of_this = map();
- Heap* heap = GetHeap();
+ Heap* heap = map_of_this->heap();
AssertNoAllocation no_alloc;
// Is the object the constructor for this object?
@@ -4054,8 +3324,6 @@
// Raw pixels and external arrays do not reference other
// objects.
break;
- case FAST_SMI_ONLY_ELEMENTS:
- break;
case FAST_ELEMENTS:
case DICTIONARY_ELEMENTS: {
FixedArray* elements = FixedArray::cast(this->elements());
@@ -4121,11 +3389,6 @@
}
-Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
- CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
-}
-
-
MaybeObject* JSObject::PreventExtensions() {
Isolate* isolate = GetIsolate();
if (IsAccessCheckNeeded() &&
@@ -4177,16 +3440,15 @@
// Tests for the fast common case for property enumeration:
-// - This object and all prototypes has an enum cache (which means that
-// it is no proxy, has no interceptors and needs no access checks).
+// - 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 JSReceiver::IsSimpleEnum() {
+bool JSObject::IsSimpleEnum() {
Heap* heap = GetHeap();
for (Object* o = this;
o != heap->null_value();
o = JSObject::cast(o)->GetPrototype()) {
- if (!o->IsJSObject()) return false;
JSObject* curr = JSObject::cast(o);
if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
ASSERT(!curr->HasNamedInterceptor());
@@ -4203,14 +3465,11 @@
}
-int Map::NumberOfDescribedProperties(PropertyAttributes filter) {
+int Map::NumberOfDescribedProperties() {
int result = 0;
DescriptorArray* descs = instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
- PropertyDetails details(descs->GetDetails(i));
- if (descs->IsProperty(i) && (details.attributes() & filter) == 0) {
- result++;
- }
+ if (descs->IsProperty(i)) result++;
}
return result;
}
@@ -4252,6 +3511,15 @@
void JSReceiver::LocalLookup(String* name, LookupResult* result) {
+ if (IsJSProxy()) {
+ result->HandlerResult();
+ } else {
+ JSObject::cast(this)->LocalLookup(name, result);
+ }
+}
+
+
+void JSObject::LocalLookup(String* name, LookupResult* result) {
ASSERT(name->IsString());
Heap* heap = GetHeap();
@@ -4260,36 +3528,28 @@
Object* proto = GetPrototype();
if (proto->IsNull()) return result->NotFound();
ASSERT(proto->IsJSGlobalObject());
- return JSReceiver::cast(proto)->LocalLookup(name, result);
- }
-
- if (IsJSProxy()) {
- result->HandlerResult(JSProxy::cast(this));
- return;
+ return JSObject::cast(proto)->LocalLookup(name, result);
}
// Do not use inline caching if the object is a non-global object
// that requires access checks.
- if (IsAccessCheckNeeded()) {
+ if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
result->DisallowCaching();
}
- JSObject* js_object = JSObject::cast(this);
-
// Check __proto__ before interceptor.
if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
- result->ConstantResult(js_object);
+ result->ConstantResult(this);
return;
}
// Check for lookup interceptor except when bootstrapping.
- if (js_object->HasNamedInterceptor() &&
- !heap->isolate()->bootstrapper()->IsActive()) {
- result->InterceptorResult(js_object);
+ if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
+ result->InterceptorResult(this);
return;
}
- js_object->LocalLookupRealNamedProperty(name, result);
+ LocalLookupRealNamedProperty(name, result);
}
@@ -4299,7 +3559,7 @@
for (Object* current = this;
current != heap->null_value();
current = JSObject::cast(current)->GetPrototype()) {
- JSReceiver::cast(current)->LocalLookup(name, result);
+ JSObject::cast(current)->LocalLookup(name, result);
if (result->IsProperty()) return;
}
result->NotFound();
@@ -4310,144 +3570,128 @@
void JSObject::LookupCallback(String* name, LookupResult* result) {
Heap* heap = GetHeap();
for (Object* current = this;
- current != heap->null_value() && current->IsJSObject();
+ current != heap->null_value();
current = JSObject::cast(current)->GetPrototype()) {
JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
- if (result->IsFound() && result->type() == CALLBACKS) return;
+ if (result->IsProperty() && result->type() == CALLBACKS) return;
}
result->NotFound();
}
-// Try to update an accessor in an elements dictionary. Return true if the
-// update succeeded, and false otherwise.
-static bool UpdateGetterSetterInDictionary(
- SeededNumberDictionary* dictionary,
- uint32_t index,
- Object* getter,
- Object* setter,
- PropertyAttributes attributes) {
+// Search for a getter or setter in an elements dictionary. Returns either
+// undefined if the element is read-only, or the getter/setter pair (fixed
+// array) if there is an existing one, or the hole value if the element does
+// not exist or is a normal non-getter/setter data element.
+static Object* FindGetterSetterInDictionary(SeededNumberDictionary* dictionary,
+ uint32_t index,
+ Heap* heap) {
int entry = dictionary->FindEntry(index);
if (entry != SeededNumberDictionary::kNotFound) {
Object* result = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.type() == CALLBACKS && result->IsAccessorPair()) {
- ASSERT(!details.IsDontDelete());
- if (details.attributes() != attributes) {
- dictionary->DetailsAtPut(entry,
- PropertyDetails(attributes, CALLBACKS, index));
- }
- AccessorPair::cast(result)->SetComponents(getter, setter);
- return true;
- }
+ if (details.IsReadOnly()) return heap->undefined_value();
+ if (details.type() == CALLBACKS && result->IsFixedArray()) return result;
}
- return false;
+ return heap->the_hole_value();
}
-MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
- Object* getter,
- Object* setter,
- PropertyAttributes attributes) {
- switch (GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- break;
- 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:
- case EXTERNAL_DOUBLE_ELEMENTS:
- // Ignore getters and setters on pixel and external array elements.
- return GetHeap()->undefined_value();
- case DICTIONARY_ELEMENTS:
- if (UpdateGetterSetterInDictionary(element_dictionary(),
- index,
- getter,
- setter,
- attributes)) {
- return GetHeap()->undefined_value();
+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();
+ }
+
+ uint32_t index = 0;
+ bool is_element = name->AsArrayIndex(&index);
+
+ if (is_element) {
+ switch (GetElementsKind()) {
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS:
+ break;
+ 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:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ // Ignore getters and setters on pixel and external array
+ // elements.
+ return heap->undefined_value();
+ case DICTIONARY_ELEMENTS: {
+ Object* probe =
+ FindGetterSetterInDictionary(element_dictionary(), index, heap);
+ if (!probe->IsTheHole()) return probe;
+ // Otherwise allow to override it.
+ break;
}
- break;
- case NON_STRICT_ARGUMENTS_ELEMENTS: {
- // Ascertain whether we have read-only properties or an existing
- // getter/setter pair in an arguments elements dictionary backing
- // store.
- FixedArray* parameter_map = FixedArray::cast(elements());
- uint32_t length = parameter_map->length();
- Object* probe =
- index < (length - 2) ? parameter_map->get(index + 2) : NULL;
- if (probe == NULL || probe->IsTheHole()) {
- FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- if (arguments->IsDictionary()) {
- SeededNumberDictionary* dictionary =
- SeededNumberDictionary::cast(arguments);
- if (UpdateGetterSetterInDictionary(dictionary,
- index,
- getter,
- setter,
- attributes)) {
- return GetHeap()->undefined_value();
+ case NON_STRICT_ARGUMENTS_ELEMENTS: {
+ // Ascertain whether we have read-only properties or an existing
+ // getter/setter pair in an arguments elements dictionary backing
+ // store.
+ FixedArray* parameter_map = FixedArray::cast(elements());
+ uint32_t length = parameter_map->length();
+ Object* probe =
+ index < (length - 2) ? parameter_map->get(index + 2) : NULL;
+ if (probe == NULL || probe->IsTheHole()) {
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ if (arguments->IsDictionary()) {
+ SeededNumberDictionary* dictionary =
+ SeededNumberDictionary::cast(arguments);
+ probe = FindGetterSetterInDictionary(dictionary, index, heap);
+ if (!probe->IsTheHole()) return probe;
}
}
+ break;
}
- break;
}
- }
-
- AccessorPair* accessors;
- { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
- if (!maybe_accessors->To(&accessors)) return maybe_accessors;
- }
- accessors->SetComponents(getter, setter);
-
- return SetElementCallback(index, accessors, attributes);
-}
-
-
-MaybeObject* JSObject::DefinePropertyAccessor(String* name,
- Object* getter,
- Object* setter,
- PropertyAttributes attributes) {
- // Lookup the name.
- LookupResult result(GetHeap()->isolate());
- LocalLookupRealNamedProperty(name, &result);
- if (result.IsFound()) {
- if (result.type() == CALLBACKS) {
- ASSERT(!result.IsDontDelete());
- Object* obj = result.GetCallbackObject();
- // Need to preserve old getters/setters.
- if (obj->IsAccessorPair()) {
- AccessorPair* copy;
- { MaybeObject* maybe_copy =
- AccessorPair::cast(obj)->CopyWithoutTransitions();
- if (!maybe_copy->To(©)) return maybe_copy;
+ } else {
+ // Lookup the name.
+ LookupResult result;
+ LocalLookup(name, &result);
+ if (result.IsProperty()) {
+ 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.
+ return SetPropertyCallback(name, obj, attributes);
}
- copy->SetComponents(getter, setter);
- // Use set to update attributes.
- return SetPropertyCallback(name, copy, attributes);
}
}
}
- AccessorPair* accessors;
- { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
- if (!maybe_accessors->To(&accessors)) return maybe_accessors;
+ // Allocate the fixed array to hold getter and setter.
+ Object* structure;
+ { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
+ if (!maybe_structure->ToObject(&structure)) return maybe_structure;
}
- accessors->SetComponents(getter, setter);
- return SetPropertyCallback(name, accessors, attributes);
+ if (is_element) {
+ return SetElementCallback(index, structure, attributes);
+ } else {
+ return SetPropertyCallback(name, structure, attributes);
+ }
}
bool JSObject::CanSetCallback(String* name) {
- ASSERT(!IsAccessCheckNeeded() ||
- GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
+ ASSERT(!IsAccessCheckNeeded()
+ || 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.
@@ -4455,7 +3699,7 @@
// certain accessors such as window.location should not be allowed
// to be overwritten because allowing overwriting could potentially
// cause security problems.
- LookupResult callback_result(GetIsolate());
+ LookupResult callback_result;
LookupCallback(name, &callback_result);
if (callback_result.IsProperty()) {
Object* obj = callback_result.GetCallbackObject();
@@ -4475,15 +3719,19 @@
PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
// Normalize elements to make this operation simple.
- SeededNumberDictionary* dictionary;
- { MaybeObject* maybe_dictionary = NormalizeElements();
- if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
+ SeededNumberDictionary* dictionary = NULL;
+ { Object* result;
+ MaybeObject* maybe = NormalizeElements();
+ if (!maybe->ToObject(&result)) return maybe;
+ dictionary = SeededNumberDictionary::cast(result);
}
ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
// Update the dictionary with the new CALLBACKS property.
- { MaybeObject* maybe_dictionary = dictionary->Set(index, structure, details);
- if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
+ { Object* result;
+ MaybeObject* maybe = dictionary->Set(index, structure, details);
+ if (!maybe->ToObject(&result)) return maybe;
+ dictionary = SeededNumberDictionary::cast(result);
}
dictionary->set_requires_slow_elements();
@@ -4495,7 +3743,8 @@
// switch to a direct backing store without the parameter map. This
// would allow GC of the context.
FixedArray* parameter_map = FixedArray::cast(elements());
- if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
+ uint32_t length = parameter_map->length();
+ if (index < length - 2) {
parameter_map->set(index + 2, GetHeap()->the_hole_value());
}
parameter_map->set(1, dictionary);
@@ -4503,26 +3752,33 @@
set_elements(dictionary);
}
- return GetHeap()->undefined_value();
+ return structure;
}
MaybeObject* JSObject::SetPropertyCallback(String* name,
Object* structure,
PropertyAttributes attributes) {
+ PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
+
+ bool convert_back_to_fast = HasFastProperties() &&
+ (map()->instance_descriptors()->number_of_descriptors()
+ < DescriptorArray::kMaxNumberOfDescriptors);
+
// Normalize object to make this operation simple.
+ Object* ok;
{ MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
- if (maybe_ok->IsFailure()) return maybe_ok;
+ if (!maybe_ok->ToObject(&ok)) return maybe_ok;
}
// For the global object allocate a new map to invalidate the global inline
// caches which have a global property cell reference directly in the code.
if (IsGlobalObject()) {
- Map* new_map;
+ Object* new_map;
{ MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
}
- set_map(new_map);
+ set_map(Map::cast(new_map));
// When running crankshaft, changing the map is not enough. We
// need to deoptimize all functions that rely on this global
// object.
@@ -4530,29 +3786,24 @@
}
// Update the dictionary with the new CALLBACKS property.
- PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
- { MaybeObject* maybe_ok = SetNormalizedProperty(name, structure, details);
- if (maybe_ok->IsFailure()) return maybe_ok;
+ Object* result;
+ { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
}
- return GetHeap()->undefined_value();
-}
-
-
-void JSObject::DefineAccessor(Handle<JSObject> object,
- Handle<String> name,
- Handle<Object> getter,
- Handle<Object> setter,
- PropertyAttributes attributes) {
- CALL_HEAP_FUNCTION_VOID(
- object->GetIsolate(),
- object->DefineAccessor(*name, *getter, *setter, attributes));
+ if (convert_back_to_fast) {
+ { MaybeObject* maybe_ok = TransformToFastProperties(0);
+ if (!maybe_ok->ToObject(&ok)) return maybe_ok;
+ }
+ }
+ return result;
}
MaybeObject* JSObject::DefineAccessor(String* name,
- Object* getter,
- Object* setter,
+ bool is_getter,
+ Object* fun,
PropertyAttributes attributes) {
+ ASSERT(fun->IsJSFunction() || fun->IsUndefined());
Isolate* isolate = GetIsolate();
// Check access rights if needed.
if (IsAccessCheckNeeded() &&
@@ -4565,23 +3816,17 @@
Object* proto = GetPrototype();
if (proto->IsNull()) return this;
ASSERT(proto->IsJSGlobalObject());
- return JSObject::cast(proto)->DefineAccessor(
- name, getter, setter, attributes);
+ return JSObject::cast(proto)->DefineAccessor(name, is_getter,
+ fun, attributes);
}
- // 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 isolate->heap()->undefined_value();
-
- uint32_t index = 0;
- return name->AsArrayIndex(&index) ?
- DefineElementAccessor(index, getter, setter, attributes) :
- DefinePropertyAccessor(name, getter, setter, attributes);
+ Object* array;
+ { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
+ if (!maybe_array->ToObject(&array)) return maybe_array;
+ }
+ if (array->IsUndefined()) return array;
+ FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
+ return this;
}
@@ -4621,7 +3866,6 @@
// Accessors overwrite previous callbacks (cf. with getters/setters).
switch (GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
break;
@@ -4644,22 +3888,24 @@
break;
}
+ Object* ok;
{ MaybeObject* maybe_ok =
SetElementCallback(index, info, info->property_attributes());
- if (maybe_ok->IsFailure()) return maybe_ok;
+ if (!maybe_ok->ToObject(&ok)) return maybe_ok;
}
} else {
// Lookup the name.
- LookupResult result(isolate);
+ 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 isolate->heap()->undefined_value();
}
+ Object* ok;
{ MaybeObject* maybe_ok =
SetPropertyCallback(name, info, info->property_attributes());
- if (maybe_ok->IsFailure()) return maybe_ok;
+ if (!maybe_ok->ToObject(&ok)) return maybe_ok;
}
}
@@ -4667,7 +3913,7 @@
}
-Object* JSObject::LookupAccessor(String* name, AccessorComponent component) {
+Object* JSObject::LookupAccessor(String* name, bool is_getter) {
Heap* heap = GetHeap();
// Make sure that the top context does not change when doing callbacks or
@@ -4682,6 +3928,7 @@
}
// 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;
@@ -4693,9 +3940,11 @@
int entry = dictionary->FindEntry(index);
if (entry != SeededNumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
- if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
- element->IsAccessorPair()) {
- return AccessorPair::cast(element)->GetComponent(component);
+ PropertyDetails details = dictionary->DetailsAt(entry);
+ if (details.type() == CALLBACKS) {
+ if (element->IsFixedArray()) {
+ return FixedArray::cast(element)->get(accessor_index);
+ }
}
}
}
@@ -4704,14 +3953,14 @@
for (Object* obj = this;
obj != heap->null_value();
obj = JSObject::cast(obj)->GetPrototype()) {
- LookupResult result(heap->isolate());
+ LookupResult result;
JSObject::cast(obj)->LocalLookup(name, &result);
if (result.IsProperty()) {
if (result.IsReadOnly()) return heap->undefined_value();
if (result.type() == CALLBACKS) {
Object* obj = result.GetCallbackObject();
- if (obj->IsAccessorPair()) {
- return AccessorPair::cast(obj)->GetComponent(component);
+ if (obj->IsFixedArray()) {
+ return FixedArray::cast(obj)->get(accessor_index);
}
}
}
@@ -4812,7 +4061,7 @@
Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
#ifdef DEBUG
- if (FLAG_verify_heap && Map::cast(result)->is_shared()) {
+ if (Map::cast(result)->is_shared()) {
Map::cast(result)->SharedMapVerify();
}
#endif
@@ -4835,19 +4084,12 @@
return new_map;
}
-void Map::UpdateCodeCache(Handle<Map> map,
- Handle<String> name,
- Handle<Code> code) {
- Isolate* isolate = map->GetIsolate();
- CALL_HEAP_FUNCTION_VOID(isolate,
- map->UpdateCodeCache(*name, *code));
-}
MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
// Allocate the code cache if not present.
if (code_cache()->IsFixedArray()) {
Object* result;
- { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
+ { MaybeObject* maybe_result = code->heap()->AllocateCodeCache();
if (!maybe_result->ToObject(&result)) return maybe_result;
}
set_code_cache(result);
@@ -4885,219 +4127,75 @@
}
-// An iterator over all map transitions in an descriptor array, reusing the map
-// field of the contens array while it is running.
-class IntrusiveMapTransitionIterator {
- public:
- explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array)
- : descriptor_array_(descriptor_array) { }
-
- void Start() {
- ASSERT(!IsIterating());
- if (HasContentArray()) *ContentHeader() = Smi::FromInt(0);
- }
-
- bool IsIterating() {
- return HasContentArray() && (*ContentHeader())->IsSmi();
- }
-
- Map* Next() {
- ASSERT(IsIterating());
- FixedArray* contents = ContentArray();
- // Attention, tricky index manipulation ahead: Every entry in the contents
- // array consists of a value/details pair, so the index is typically even.
- // An exception is made for CALLBACKS entries: An even index means we look
- // at its getter, and an odd index means we look at its setter.
- int index = Smi::cast(*ContentHeader())->value();
- while (index < contents->length()) {
- PropertyDetails details(Smi::cast(contents->get(index | 1)));
- switch (details.type()) {
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- case ELEMENTS_TRANSITION:
- // We definitely have a map transition.
- *ContentHeader() = Smi::FromInt(index + 2);
- return static_cast<Map*>(contents->get(index));
- case CALLBACKS: {
- // We might have a map transition in a getter or in a setter.
- AccessorPair* accessors =
- static_cast<AccessorPair*>(contents->get(index & ~1));
- Object* accessor =
- ((index & 1) == 0) ? accessors->getter() : accessors->setter();
- index++;
- if (accessor->IsMap()) {
- *ContentHeader() = Smi::FromInt(index);
- return static_cast<Map*>(accessor);
- }
+void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
+ // Traverse the transition tree without using a stack. We do this by
+ // reversing the pointers in the maps and descriptor arrays.
+ Map* current = this;
+ Map* meta_map = heap()->meta_map();
+ Object** map_or_index_field = NULL;
+ while (current != meta_map) {
+ DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
+ *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
+ if (!d->IsEmpty()) {
+ FixedArray* contents = reinterpret_cast<FixedArray*>(
+ d->get(DescriptorArray::kContentArrayIndex));
+ map_or_index_field = RawField(contents, HeapObject::kMapOffset);
+ Object* map_or_index = *map_or_index_field;
+ bool map_done = true; // Controls a nested continue statement.
+ for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
+ i < contents->length();
+ i += 2) {
+ PropertyDetails details(Smi::cast(contents->get(i + 1)));
+ if (details.IsTransition()) {
+ // Found a map in the transition array. We record our progress in
+ // the transition array by recording the current map in the map field
+ // of the next map and recording the index in the transition array in
+ // the map field of the array.
+ Map* next = Map::cast(contents->get(i));
+ next->set_map(current);
+ *map_or_index_field = Smi::FromInt(i + 2);
+ current = next;
+ map_done = false;
break;
}
- case NORMAL:
- case FIELD:
- case CONSTANT_FUNCTION:
- case HANDLER:
- case INTERCEPTOR:
- case NULL_DESCRIPTOR:
- // We definitely have no map transition.
- index += 2;
- break;
+ }
+ if (!map_done) continue;
+ } else {
+ map_or_index_field = NULL;
+ }
+ // That was the regular transitions, now for the prototype transitions.
+ FixedArray* prototype_transitions =
+ current->unchecked_prototype_transitions();
+ Object** proto_map_or_index_field =
+ RawField(prototype_transitions, HeapObject::kMapOffset);
+ Object* map_or_index = *proto_map_or_index_field;
+ const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
+ int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
+ if (i < prototype_transitions->length()) {
+ // Found a map in the prototype transition array. Record progress in
+ // an analogous way to the regular transitions array above.
+ Object* perhaps_map = prototype_transitions->get(i);
+ if (perhaps_map->IsMap()) {
+ Map* next = Map::cast(perhaps_map);
+ next->set_map(current);
+ *proto_map_or_index_field =
+ Smi::FromInt(i + kProtoTransitionElementsPerEntry);
+ current = next;
+ continue;
}
}
- *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map();
- return NULL;
- }
-
- private:
- bool HasContentArray() {
- return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex;
- }
-
- FixedArray* ContentArray() {
- Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex);
- return static_cast<FixedArray*>(array);
- }
-
- Object** ContentHeader() {
- return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset);
- }
-
- DescriptorArray* descriptor_array_;
-};
-
-
-// An iterator over all prototype transitions, reusing the map field of the
-// underlying array while it is running.
-class IntrusivePrototypeTransitionIterator {
- public:
- explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
- : proto_trans_(proto_trans) { }
-
- void Start() {
- ASSERT(!IsIterating());
- if (HasTransitions()) *Header() = Smi::FromInt(0);
- }
-
- bool IsIterating() {
- return HasTransitions() && (*Header())->IsSmi();
- }
-
- Map* Next() {
- ASSERT(IsIterating());
- int transitionNumber = Smi::cast(*Header())->value();
- if (transitionNumber < NumberOfTransitions()) {
- *Header() = Smi::FromInt(transitionNumber + 1);
- return GetTransition(transitionNumber);
+ *proto_map_or_index_field = heap()->fixed_array_map();
+ if (map_or_index_field != NULL) {
+ *map_or_index_field = heap()->fixed_array_map();
}
- *Header() = proto_trans_->GetHeap()->fixed_array_map();
- return NULL;
- }
- private:
- bool HasTransitions() {
- return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
- }
-
- Object** Header() {
- return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
- }
-
- int NumberOfTransitions() {
- Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
- return Smi::cast(num)->value();
- }
-
- Map* GetTransition(int transitionNumber) {
- return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
- }
-
- int IndexFor(int transitionNumber) {
- return Map::kProtoTransitionHeaderSize +
- Map::kProtoTransitionMapOffset +
- transitionNumber * Map::kProtoTransitionElementsPerEntry;
- }
-
- FixedArray* proto_trans_;
-};
-
-
-// To traverse the transition tree iteratively, we have to store two kinds of
-// information in a map: The parent map in the traversal and which children of a
-// node have already been visited. To do this without additional memory, we
-// temporarily reuse two maps with known values:
-//
-// (1) The map of the map temporarily holds the parent, and is restored to the
-// meta map afterwards.
-//
-// (2) The info which children have already been visited depends on which part
-// of the map we currently iterate:
-//
-// (a) If we currently follow normal map transitions, we temporarily store
-// the current index in the map of the FixedArray of the desciptor
-// array's contents, and restore it to the fixed array map afterwards.
-// Note that a single descriptor can have 0, 1, or 2 transitions.
-//
-// (b) If we currently follow prototype transitions, we temporarily store
-// the current index in the map of the FixedArray holding the prototype
-// transitions, and restore it to the fixed array map afterwards.
-//
-// Note that the child iterator is just a concatenation of two iterators: One
-// iterating over map transitions and one iterating over prototype transisitons.
-class TraversableMap : public Map {
- public:
- // Record the parent in the traversal within this map. Note that this destroys
- // this map's map!
- void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
-
- // Reset the current map's map, returning the parent previously stored in it.
- TraversableMap* GetAndResetParent() {
- TraversableMap* old_parent = static_cast<TraversableMap*>(map());
- set_map_no_write_barrier(GetHeap()->meta_map());
- return old_parent;
- }
-
- // Start iterating over this map's children, possibly destroying a FixedArray
- // map (see explanation above).
- void ChildIteratorStart() {
- IntrusiveMapTransitionIterator(instance_descriptors()).Start();
- IntrusivePrototypeTransitionIterator(
- unchecked_prototype_transitions()).Start();
- }
-
- // If we have an unvisited child map, return that one and advance. If we have
- // none, return NULL and reset any destroyed FixedArray maps.
- TraversableMap* ChildIteratorNext() {
- IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors());
- if (descriptor_iterator.IsIterating()) {
- Map* next = descriptor_iterator.Next();
- if (next != NULL) return static_cast<TraversableMap*>(next);
- }
- IntrusivePrototypeTransitionIterator
- proto_iterator(unchecked_prototype_transitions());
- if (proto_iterator.IsIterating()) {
- Map* next = proto_iterator.Next();
- if (next != NULL) return static_cast<TraversableMap*>(next);
- }
- return NULL;
- }
-};
-
-
-// Traverse the transition tree in postorder without using the C++ stack by
-// doing pointer reversal.
-void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
- TraversableMap* current = static_cast<TraversableMap*>(this);
- current->ChildIteratorStart();
- while (true) {
- TraversableMap* child = current->ChildIteratorNext();
- if (child != NULL) {
- child->ChildIteratorStart();
- child->SetParent(current);
- current = child;
- } else {
- TraversableMap* parent = current->GetAndResetParent();
- callback(current, data);
- if (current == this) break;
- current = parent;
- }
+ // The callback expects a map to have a real map as its map, so we save
+ // the map field, which is being used to track the traversal and put the
+ // correct map (the meta_map) in place while we do the callback.
+ Map* prev = current->map();
+ current->set_map(meta_map);
+ callback(current, data);
+ current = prev;
}
}
@@ -5311,7 +4409,7 @@
MUST_USE_RESULT MaybeObject* AsObject() {
ASSERT(code_ != NULL);
Object* obj;
- { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2);
+ { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* pair = FixedArray::cast(obj);
@@ -5369,22 +4467,13 @@
void CodeCacheHashTable::RemoveByIndex(int index) {
ASSERT(index >= 0);
Heap* heap = GetHeap();
- set(EntryToIndex(index), heap->the_hole_value());
- set(EntryToIndex(index) + 1, heap->the_hole_value());
+ set(EntryToIndex(index), heap->null_value());
+ set(EntryToIndex(index) + 1, heap->null_value());
ElementRemoved();
}
-void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
- MapHandleList* maps,
- Code::Flags flags,
- Handle<Code> code) {
- Isolate* isolate = cache->GetIsolate();
- CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
-}
-
-
-MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
+MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
Code::Flags flags,
Code* code) {
// Initialize cache if necessary.
@@ -5412,14 +4501,13 @@
}
-Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
- Code::Flags flags) {
+Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
if (!cache()->IsUndefined()) {
PolymorphicCodeCacheHashTable* hash_table =
PolymorphicCodeCacheHashTable::cast(cache());
- return Handle<Object>(hash_table->Lookup(maps, flags));
+ return hash_table->Lookup(maps, flags);
} else {
- return GetIsolate()->factory()->undefined_value();
+ return GetHeap()->undefined_value();
}
}
@@ -5430,12 +4518,12 @@
class PolymorphicCodeCacheHashTableKey : public HashTableKey {
public:
// Callers must ensure that |maps| outlives the newly constructed object.
- PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
+ PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags)
: maps_(maps),
code_flags_(code_flags) {}
bool IsMatch(Object* other) {
- MapHandleList other_maps(kDefaultListAllocationSize);
+ MapList other_maps(kDefaultListAllocationSize);
int other_flags;
FromObject(other, &other_flags, &other_maps);
if (code_flags_ != other_flags) return false;
@@ -5451,7 +4539,7 @@
for (int i = 0; i < maps_->length(); ++i) {
bool match_found = false;
for (int j = 0; j < other_maps.length(); ++j) {
- if (*(maps_->at(i)) == *(other_maps.at(j))) {
+ if (maps_->at(i)->EquivalentTo(other_maps.at(j))) {
match_found = true;
break;
}
@@ -5461,7 +4549,7 @@
return true;
}
- static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
+ static uint32_t MapsHashHelper(MapList* maps, int code_flags) {
uint32_t hash = code_flags;
for (int i = 0; i < maps->length(); ++i) {
hash ^= maps->at(i)->Hash();
@@ -5474,7 +4562,7 @@
}
uint32_t HashForObject(Object* obj) {
- MapHandleList other_maps(kDefaultListAllocationSize);
+ MapList other_maps(kDefaultListAllocationSize);
int other_flags;
FromObject(obj, &other_flags, &other_maps);
return MapsHashHelper(&other_maps, other_flags);
@@ -5492,32 +4580,29 @@
FixedArray* list = FixedArray::cast(obj);
list->set(0, Smi::FromInt(code_flags_));
for (int i = 0; i < maps_->length(); ++i) {
- list->set(i + 1, *maps_->at(i));
+ list->set(i + 1, maps_->at(i));
}
return list;
}
private:
- static MapHandleList* FromObject(Object* obj,
- int* code_flags,
- MapHandleList* maps) {
+ static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) {
FixedArray* list = FixedArray::cast(obj);
maps->Rewind(0);
*code_flags = Smi::cast(list->get(0))->value();
for (int i = 1; i < list->length(); ++i) {
- maps->Add(Handle<Map>(Map::cast(list->get(i))));
+ maps->Add(Map::cast(list->get(i)));
}
return maps;
}
- MapHandleList* maps_; // weak.
+ MapList* maps_; // weak.
int code_flags_;
static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
};
-Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
- int code_flags) {
+Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
PolymorphicCodeCacheHashTableKey key(maps, code_flags);
int entry = FindEntry(&key);
if (entry == kNotFound) return GetHeap()->undefined_value();
@@ -5525,7 +4610,7 @@
}
-MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
+MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
int code_flags,
Code* code) {
PolymorphicCodeCacheHashTableKey key(maps, code_flags);
@@ -5549,7 +4634,7 @@
MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
ElementsAccessor* accessor = array->GetElementsAccessor();
MaybeObject* maybe_result =
- accessor->AddElementsToFixedArray(array, array, this);
+ accessor->AddElementsToFixedArray(array->elements(), this, array, array);
FixedArray* result;
if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
#ifdef DEBUG
@@ -5567,7 +4652,7 @@
MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
MaybeObject* maybe_result =
- accessor->AddElementsToFixedArray(NULL, NULL, this, other);
+ accessor->AddElementsToFixedArray(other, this, NULL, NULL);
FixedArray* result;
if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
#ifdef DEBUG
@@ -5594,9 +4679,7 @@
AssertNoAllocation no_gc;
int len = length();
if (new_length < len) len = new_length;
- // We are taking the map from the old fixed array so the map is sure to
- // be an immortal immutable object.
- result->set_map_no_write_barrier(map());
+ result->set_map(map());
WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
for (int i = 0; i < len; i++) {
result->set(i, get(i), mode);
@@ -5653,61 +4736,23 @@
void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
- FixedArray* new_cache,
- Object* new_index_cache) {
+ FixedArray* new_cache) {
ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
- ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
if (HasEnumCache()) {
FixedArray::cast(get(kEnumerationIndexIndex))->
set(kEnumCacheBridgeCacheIndex, new_cache);
- FixedArray::cast(get(kEnumerationIndexIndex))->
- set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
} else {
if (IsEmpty()) return; // Do nothing for empty descriptor array.
FixedArray::cast(bridge_storage)->
set(kEnumCacheBridgeCacheIndex, new_cache);
- FixedArray::cast(bridge_storage)->
- set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
- NoWriteBarrierSet(FixedArray::cast(bridge_storage),
- kEnumCacheBridgeEnumIndex,
- get(kEnumerationIndexIndex));
+ fast_set(FixedArray::cast(bridge_storage),
+ kEnumCacheBridgeEnumIndex,
+ get(kEnumerationIndexIndex));
set(kEnumerationIndexIndex, bridge_storage);
}
}
-static bool InsertionPointFound(String* key1, String* key2) {
- return key1->Hash() > key2->Hash() || key1 == key2;
-}
-
-
-void DescriptorArray::CopyFrom(Handle<DescriptorArray> dst,
- int dst_index,
- Handle<DescriptorArray> src,
- int src_index,
- const WhitenessWitness& witness) {
- CALL_HEAP_FUNCTION_VOID(dst->GetIsolate(),
- dst->CopyFrom(dst_index, *src, src_index, witness));
-}
-
-
-MaybeObject* DescriptorArray::CopyFrom(int dst_index,
- DescriptorArray* src,
- int src_index,
- const WhitenessWitness& witness) {
- Object* value = src->GetValue(src_index);
- PropertyDetails details(src->GetDetails(src_index));
- if (details.type() == CALLBACKS && value->IsAccessorPair()) {
- MaybeObject* maybe_copy =
- AccessorPair::cast(value)->CopyWithoutTransitions();
- if (!maybe_copy->To(&value)) return maybe_copy;
- }
- Descriptor desc(src->GetKey(src_index), value, details);
- Set(dst_index, &desc, witness);
- return this;
-}
-
-
MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
TransitionFlag transition_flag) {
// Transitions are only kept when inserting another transition.
@@ -5716,26 +4761,38 @@
// Conversely, we filter after replacing, so replacing a transition and
// removing all other transitions is not supported.
bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
- ASSERT(remove_transitions == !descriptor->ContainsTransition());
+ ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
// Ensure the key is a symbol.
+ Object* result;
{ MaybeObject* maybe_result = descriptor->KeyToSymbol();
- if (maybe_result->IsFailure()) return maybe_result;
+ if (!maybe_result->ToObject(&result)) return maybe_result;
}
- int new_size = 0;
- for (int i = 0; i < number_of_descriptors(); i++) {
- if (IsNullDescriptor(i)) continue;
- if (remove_transitions && IsTransitionOnly(i)) continue;
- new_size++;
+ int transitions = 0;
+ int null_descriptors = 0;
+ if (remove_transitions) {
+ for (int i = 0; i < number_of_descriptors(); i++) {
+ if (IsTransition(i)) transitions++;
+ if (IsNullDescriptor(i)) null_descriptors++;
+ }
+ } else {
+ for (int i = 0; i < number_of_descriptors(); i++) {
+ if (IsNullDescriptor(i)) null_descriptors++;
+ }
}
+ int new_size = number_of_descriptors() - transitions - null_descriptors;
// If key is in descriptor, we replace it in-place when filtering.
// Count a null descriptor for key as inserted, not replaced.
int index = Search(descriptor->GetKey());
- const bool replacing = (index != kNotFound);
+ const bool inserting = (index == kNotFound);
+ const bool replacing = !inserting;
bool keep_enumeration_index = false;
+ if (inserting) {
+ ++new_size;
+ }
if (replacing) {
// We are replacing an existing descriptor. We keep the enumeration
// index of a visible property.
@@ -5750,21 +4807,15 @@
// a transition that will be replaced. Adjust count in this case.
++new_size;
}
- } else {
- ++new_size;
}
-
- DescriptorArray* new_descriptors;
{ MaybeObject* maybe_result = Allocate(new_size);
- if (!maybe_result->To(&new_descriptors)) return maybe_result;
+ if (!maybe_result->ToObject(&result)) return maybe_result;
}
-
- DescriptorArray::WhitenessWitness witness(new_descriptors);
-
+ DescriptorArray* new_descriptors = DescriptorArray::cast(result);
// Set the enumeration index in the descriptors and set the enumeration index
// in the result.
int enumeration_index = NextEnumerationIndex();
- if (!descriptor->ContainsTransition()) {
+ if (!descriptor->GetDetails().IsTransition()) {
if (keep_enumeration_index) {
descriptor->SetEnumerationIndex(
PropertyDetails(GetDetails(index)).index());
@@ -5777,26 +4828,28 @@
// Copy the descriptors, filtering out transitions and null descriptors,
// and inserting or replacing a descriptor.
- int to_index = 0;
- int insertion_index = -1;
+ uint32_t descriptor_hash = descriptor->GetKey()->Hash();
int from_index = 0;
- while (from_index < number_of_descriptors()) {
- if (insertion_index < 0 &&
- InsertionPointFound(GetKey(from_index), descriptor->GetKey())) {
- insertion_index = to_index++;
- if (replacing) from_index++;
- } else {
- if (!(IsNullDescriptor(from_index) ||
- (remove_transitions && IsTransitionOnly(from_index)))) {
- MaybeObject* copy_result =
- new_descriptors->CopyFrom(to_index++, this, from_index, witness);
- if (copy_result->IsFailure()) return copy_result;
- }
- from_index++;
+ int to_index = 0;
+
+ for (; from_index < number_of_descriptors(); from_index++) {
+ String* key = GetKey(from_index);
+ if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
+ break;
}
+ if (IsNullDescriptor(from_index)) continue;
+ if (remove_transitions && IsTransition(from_index)) continue;
+ new_descriptors->CopyFrom(to_index++, this, from_index);
}
- if (insertion_index < 0) insertion_index = to_index++;
- new_descriptors->Set(insertion_index, descriptor, witness);
+
+ new_descriptors->Set(to_index++, descriptor);
+ if (replacing) from_index++;
+
+ for (; from_index < number_of_descriptors(); from_index++) {
+ if (IsNullDescriptor(from_index)) continue;
+ if (remove_transitions && IsTransition(from_index)) continue;
+ new_descriptors->CopyFrom(to_index++, this, from_index);
+ }
ASSERT(to_index == new_descriptors->number_of_descriptors());
SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
@@ -5806,25 +4859,27 @@
MaybeObject* DescriptorArray::RemoveTransitions() {
- // Allocate the new descriptor array.
- int new_number_of_descriptors = 0;
+ // Remove all transitions and null descriptors. Return a copy of the array
+ // with all transitions removed, or a Failure object if the new array could
+ // not be allocated.
+
+ // Compute the size of the map transition entries to be removed.
+ int num_removed = 0;
for (int i = 0; i < number_of_descriptors(); i++) {
- if (IsProperty(i)) new_number_of_descriptors++;
- }
- DescriptorArray* new_descriptors;
- { MaybeObject* maybe_result = Allocate(new_number_of_descriptors);
- if (!maybe_result->To(&new_descriptors)) return maybe_result;
+ if (!IsProperty(i)) num_removed++;
}
+ // Allocate the new descriptor array.
+ Object* result;
+ { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ DescriptorArray* new_descriptors = DescriptorArray::cast(result);
+
// Copy the content.
- DescriptorArray::WhitenessWitness witness(new_descriptors);
int next_descriptor = 0;
for (int i = 0; i < number_of_descriptors(); i++) {
- if (IsProperty(i)) {
- MaybeObject* copy_result =
- new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
- if (copy_result->IsFailure()) return copy_result;
- }
+ if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
}
ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
@@ -5832,7 +4887,7 @@
}
-void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
+void DescriptorArray::SortUnchecked() {
// In-place heap sort.
int len = number_of_descriptors();
@@ -5853,7 +4908,7 @@
}
}
if (child_hash <= parent_hash) break;
- NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
+ Swap(parent_index, child_index);
// Now element at child_index could be < its children.
parent_index = child_index; // parent_hash remains correct.
}
@@ -5862,8 +4917,8 @@
// Extract elements and create sorted array.
for (int i = len - 1; i > 0; --i) {
// Put max element at the back of the array.
- NoIncrementalWriteBarrierSwapDescriptors(0, i);
- // Shift down the new top element.
+ Swap(0, i);
+ // Sift down the new top element.
int parent_index = 0;
const uint32_t parent_hash = GetKey(parent_index)->Hash();
const int max_parent_index = (i / 2) - 1;
@@ -5878,15 +4933,15 @@
}
}
if (child_hash <= parent_hash) break;
- NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
+ Swap(parent_index, child_index);
parent_index = child_index;
}
}
}
-void DescriptorArray::Sort(const WhitenessWitness& witness) {
- SortUnchecked(witness);
+void DescriptorArray::Sort() {
+ SortUnchecked();
SLOW_ASSERT(IsSortedNoDuplicates());
}
@@ -5936,24 +4991,6 @@
}
-MaybeObject* AccessorPair::CopyWithoutTransitions() {
- Heap* heap = GetHeap();
- AccessorPair* copy;
- { MaybeObject* maybe_copy = heap->AllocateAccessorPair();
- if (!maybe_copy->To(©)) return maybe_copy;
- }
- copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter());
- copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter());
- return copy;
-}
-
-
-Object* AccessorPair::GetComponent(AccessorComponent component) {
- Object* accessor = (component == ACCESSOR_GETTER) ? getter() : setter();
- return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
-}
-
-
MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
PretenureFlag pretenure) {
ASSERT(deopt_entry_count > 0);
@@ -5989,6 +5026,24 @@
}
+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(
+ 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;
+}
+
+
String::FlatContent String::GetFlatContent() {
int length = this->length();
StringShape shape(this);
@@ -6015,7 +5070,7 @@
if (shape.representation_tag() == kSeqStringTag) {
start = SeqAsciiString::cast(string)->GetChars();
} else {
- start = ExternalAsciiString::cast(string)->GetChars();
+ start = ExternalAsciiString::cast(string)->resource()->data();
}
return FlatContent(Vector<const char>(start + offset, length));
} else {
@@ -6024,7 +5079,7 @@
if (shape.representation_tag() == kSeqStringTag) {
start = SeqTwoByteString::cast(string)->GetChars();
} else {
- start = ExternalTwoByteString::cast(string)->GetChars();
+ start = ExternalTwoByteString::cast(string)->resource()->data();
}
return FlatContent(Vector<const uc16>(start + offset, length));
}
@@ -6050,11 +5105,12 @@
buffer->Reset(offset, this);
int character_position = offset;
int utf8_bytes = 0;
- int last = unibrow::Utf16::kNoPreviousCharacter;
- while (buffer->has_more() && character_position++ < offset + length) {
+ while (buffer->has_more()) {
uint16_t character = buffer->GetNext();
- utf8_bytes += unibrow::Utf8::Length(character, last);
- last = character;
+ if (character_position < offset + length) {
+ utf8_bytes += unibrow::Utf8::Length(character);
+ }
+ character_position++;
}
if (length_return) {
@@ -6068,15 +5124,16 @@
buffer->Seek(offset);
character_position = offset;
int utf8_byte_position = 0;
- last = unibrow::Utf16::kNoPreviousCharacter;
- while (buffer->has_more() && character_position++ < offset + length) {
+ while (buffer->has_more()) {
uint16_t character = buffer->GetNext();
- if (allow_nulls == DISALLOW_NULLS && character == 0) {
- character = ' ';
+ if (character_position < offset + length) {
+ if (allow_nulls == DISALLOW_NULLS && character == 0) {
+ character = ' ';
+ }
+ utf8_byte_position +=
+ unibrow::Utf8::Encode(result + utf8_byte_position, character);
}
- utf8_byte_position +=
- unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
- last = character;
+ character_position++;
}
result[utf8_byte_position] = 0;
return SmartArrayPointer<char>(result);
@@ -6261,26 +5318,44 @@
}
+uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
+ ASSERT(index >= 0 && index < length());
+ return resource()->data()[index];
+}
+
+
const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
unsigned* remaining,
unsigned* offset_ptr,
unsigned max_chars) {
// Cast const char* to unibrow::byte* (signedness difference).
const unibrow::byte* b =
- reinterpret_cast<const unibrow::byte*>(GetChars()) + *offset_ptr;
+ reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
*remaining = max_chars;
*offset_ptr += max_chars;
return b;
}
+const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
+ unsigned start) {
+ return resource()->data() + start;
+}
+
+
+uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
+ ASSERT(index >= 0 && index < length());
+ return resource()->data()[index];
+}
+
+
void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
ReadBlockBuffer* rbb,
unsigned* offset_ptr,
unsigned max_chars) {
unsigned chars_read = 0;
unsigned offset = *offset_ptr;
- const uint16_t* data = GetChars();
+ const uint16_t* data = resource()->data();
while (chars_read < max_chars) {
uint16_t c = data[offset];
if (c <= kMaxAsciiCharCode) {
@@ -6326,7 +5401,9 @@
unsigned max_chars) {
unsigned capacity = rbb->capacity - rbb->cursor;
if (max_chars > capacity) max_chars = capacity;
- memcpy(rbb->util_buffer + rbb->cursor, GetChars() + *offset_ptr, max_chars);
+ memcpy(rbb->util_buffer + rbb->cursor,
+ resource()->data() + *offset_ptr,
+ max_chars);
rbb->remaining += max_chars;
*offset_ptr += max_chars;
rbb->cursor += max_chars;
@@ -6701,13 +5778,13 @@
switch (StringShape(source).full_representation_tag()) {
case kAsciiStringTag | kExternalStringTag: {
CopyChars(sink,
- ExternalAsciiString::cast(source)->GetChars() + from,
+ ExternalAsciiString::cast(source)->resource()->data() + from,
to - from);
return;
}
case kTwoByteStringTag | kExternalStringTag: {
const uc16* data =
- ExternalTwoByteString::cast(source)->GetChars();
+ ExternalTwoByteString::cast(source)->resource()->data();
CopyChars(sink,
data + from,
to - from);
@@ -6745,21 +5822,10 @@
// Left hand side is longer. Recurse over right.
if (to > boundary) {
String* second = cons_string->second();
- // When repeatedly appending to a string, we get a cons string that
- // is unbalanced to the left, a list, essentially. We inline the
- // common case of sequential ascii right child.
- if (to - boundary == 1) {
- sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
- } else if (second->IsSeqAsciiString()) {
- CopyChars(sink + boundary - from,
- SeqAsciiString::cast(second)->GetChars(),
+ WriteToFlat(second,
+ sink + boundary - from,
+ 0,
to - boundary);
- } else {
- WriteToFlat(second,
- sink + boundary - from,
- 0,
- to - boundary);
- }
to = boundary;
}
source = first;
@@ -6783,10 +5849,8 @@
// General slow case check. We know that the ia and ib iterators
// have the same length.
while (ia->has_more()) {
- uint32_t ca = ia->GetNext();
- uint32_t cb = ib->GetNext();
- ASSERT(ca <= unibrow::Utf16::kMaxNonSurrogateCharCode);
- ASSERT(cb <= unibrow::Utf16::kMaxNonSurrogateCharCode);
+ uc32 ca = ia->GetNext();
+ uc32 cb = ib->GetNext();
if (ca != cb)
return false;
}
@@ -6948,7 +6012,7 @@
if (StringShape(this).IsSymbol()) return false;
Map* map = this->map();
- Heap* heap = GetHeap();
+ Heap* heap = map->heap();
if (map == heap->string_map()) {
this->set_map(heap->undetectable_string_map());
return true;
@@ -6969,14 +6033,8 @@
decoder->Reset(str.start(), str.length());
int i;
for (i = 0; i < slen && decoder->has_more(); i++) {
- uint32_t r = decoder->GetNext();
- if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
- if (i > slen - 1) return false;
- if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
- if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
- } else {
- if (Get(i) != r) return false;
- }
+ uc32 r = decoder->GetNext();
+ if (Get(i) != r) return false;
}
return i == slen && !decoder->has_more();
}
@@ -7106,22 +6164,6 @@
}
-void StringHasher::AddSurrogatePair(uc32 c) {
- uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
- AddCharacter(lead);
- uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
- AddCharacter(trail);
-}
-
-
-void StringHasher::AddSurrogatePairNoIndex(uc32 c) {
- uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
- AddCharacterNoIndex(lead);
- uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
- AddCharacterNoIndex(trail);
-}
-
-
uint32_t StringHasher::GetHashField() {
ASSERT(is_valid());
if (length_ <= String::kMaxHashCalcLength) {
@@ -7178,155 +6220,66 @@
}
-void Map::CreateOneBackPointer(Object* transition_target) {
- if (!transition_target->IsMap()) return;
- Map* target = Map::cast(transition_target);
-#ifdef DEBUG
- // Verify target.
- Object* source_prototype = prototype();
- Object* target_prototype = target->prototype();
- ASSERT(source_prototype->IsJSReceiver() ||
- source_prototype->IsMap() ||
- source_prototype->IsNull());
- ASSERT(target_prototype->IsJSReceiver() ||
- target_prototype->IsNull());
- ASSERT(source_prototype->IsMap() ||
- source_prototype == target_prototype);
-#endif
- // Point target back to source. set_prototype() will not let us set
- // the prototype to a map, as we do here.
- *RawField(target, kPrototypeOffset) = this;
-}
-
-
void Map::CreateBackPointers() {
DescriptorArray* descriptors = instance_descriptors();
for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
- switch (descriptors->GetType(i)) {
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- CreateOneBackPointer(descriptors->GetValue(i));
- break;
- case ELEMENTS_TRANSITION: {
- Object* object = descriptors->GetValue(i);
- if (object->IsMap()) {
- CreateOneBackPointer(object);
- } else {
- FixedArray* array = FixedArray::cast(object);
- for (int i = 0; i < array->length(); ++i) {
- CreateOneBackPointer(array->get(i));
- }
- }
- break;
- }
- case CALLBACKS: {
- Object* object = descriptors->GetValue(i);
- if (object->IsAccessorPair()) {
- AccessorPair* accessors = AccessorPair::cast(object);
- CreateOneBackPointer(accessors->getter());
- CreateOneBackPointer(accessors->setter());
- }
- break;
- }
- case NORMAL:
- case FIELD:
- case CONSTANT_FUNCTION:
- case HANDLER:
- case INTERCEPTOR:
- case NULL_DESCRIPTOR:
- break;
+ if (descriptors->GetType(i) == MAP_TRANSITION ||
+ descriptors->GetType(i) == ELEMENTS_TRANSITION ||
+ descriptors->GetType(i) == CONSTANT_TRANSITION) {
+ // Get target.
+ Map* target = Map::cast(descriptors->GetValue(i));
+#ifdef DEBUG
+ // Verify target.
+ Object* source_prototype = prototype();
+ Object* target_prototype = target->prototype();
+ ASSERT(source_prototype->IsJSObject() ||
+ source_prototype->IsMap() ||
+ source_prototype->IsNull());
+ ASSERT(target_prototype->IsJSObject() ||
+ target_prototype->IsNull());
+ ASSERT(source_prototype->IsMap() ||
+ source_prototype == target_prototype);
+#endif
+ // Point target back to source. set_prototype() will not let us set
+ // the prototype to a map, as we do here.
+ *RawField(target, kPrototypeOffset) = this;
}
}
}
-bool Map::RestoreOneBackPointer(Object* object,
- Object* real_prototype,
- bool* keep_entry) {
- if (!object->IsMap()) return false;
- Map* map = Map::cast(object);
- if (Marking::MarkBitFrom(map).Get()) {
- *keep_entry = true;
- return false;
- }
- ASSERT(map->prototype() == this || map->prototype() == real_prototype);
- // Getter prototype() is read-only, set_prototype() has side effects.
- *RawField(map, Map::kPrototypeOffset) = real_prototype;
- return true;
-}
-
-
void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
- DescriptorArray* d = DescriptorArray::cast(
+ // 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::kInstanceDescriptorsOrBitField3Offset));
if (d->IsEmpty()) return;
Smi* NullDescriptorDetails =
PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
- FixedArray* contents = FixedArray::cast(
+ FixedArray* contents = reinterpret_cast<FixedArray*>(
d->get(DescriptorArray::kContentArrayIndex));
ASSERT(contents->length() >= 2);
for (int i = 0; i < contents->length(); i += 2) {
- // If the pair (value, details) is a map transition, check if the target is
- // live. If not, null the descriptor. 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.
- bool keep_entry = false;
+ // If the pair (value, details) is a map transition,
+ // check if the target is live. If not, null the descriptor.
+ // 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)));
- switch (details.type()) {
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- RestoreOneBackPointer(contents->get(i), real_prototype, &keep_entry);
- break;
- case ELEMENTS_TRANSITION: {
- Object* object = contents->get(i);
- if (object->IsMap()) {
- RestoreOneBackPointer(object, real_prototype, &keep_entry);
- } else {
- FixedArray* array = FixedArray::cast(object);
- for (int j = 0; j < array->length(); ++j) {
- if (RestoreOneBackPointer(array->get(j),
- real_prototype,
- &keep_entry)) {
- array->set_undefined(j);
- }
- }
- }
- break;
+ if (details.type() == MAP_TRANSITION ||
+ details.type() == ELEMENTS_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(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;
}
- case CALLBACKS: {
- Object* object = contents->get(i);
- if (object->IsAccessorPair()) {
- AccessorPair* accessors = AccessorPair::cast(object);
- if (RestoreOneBackPointer(accessors->getter(),
- real_prototype,
- &keep_entry)) {
- accessors->set_getter(heap->the_hole_value());
- }
- if (RestoreOneBackPointer(accessors->setter(),
- real_prototype,
- &keep_entry)) {
- accessors->set_setter(heap->the_hole_value());
- }
- } else {
- keep_entry = true;
- }
- break;
- }
- case NORMAL:
- case FIELD:
- case CONSTANT_FUNCTION:
- case HANDLER:
- case INTERCEPTOR:
- case NULL_DESCRIPTOR:
- keep_entry = true;
- break;
- }
- // Make sure that an entry containing only dead transitions gets collected.
- // What we *really* want to do here is removing this entry completely, but
- // for technical reasons we can't do this, so we zero it out instead.
- if (!keep_entry) {
- contents->set_unchecked(i + 1, NullDescriptorDetails);
- contents->set_null_unchecked(heap, i);
}
}
}
@@ -7384,57 +6337,6 @@
}
-bool SharedFunctionInfo::EnsureCompiled(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag) {
- return shared->is_compiled() || CompileLazy(shared, flag);
-}
-
-
-static bool CompileLazyHelper(CompilationInfo* info,
- ClearExceptionFlag flag) {
- // Compile the source information to a code object.
- ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
- ASSERT(!info->isolate()->has_pending_exception());
- bool result = Compiler::CompileLazy(info);
- ASSERT(result != Isolate::Current()->has_pending_exception());
- if (!result && flag == CLEAR_EXCEPTION) {
- info->isolate()->clear_pending_exception();
- }
- return result;
-}
-
-
-bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
- ClearExceptionFlag flag) {
- CompilationInfo info(shared);
- return CompileLazyHelper(&info, flag);
-}
-
-
-bool JSFunction::CompileLazy(Handle<JSFunction> function,
- ClearExceptionFlag flag) {
- bool result = true;
- if (function->shared()->is_compiled()) {
- function->ReplaceCode(function->shared()->code());
- function->shared()->set_code_age(0);
- } else {
- CompilationInfo info(function);
- result = CompileLazyHelper(&info, flag);
- ASSERT(!result || function->is_compiled());
- }
- return result;
-}
-
-
-bool JSFunction::CompileOptimized(Handle<JSFunction> function,
- int osr_ast_id,
- ClearExceptionFlag flag) {
- CompilationInfo info(function);
- info.SetOptimizing(osr_ast_id);
- return CompileLazyHelper(&info, flag);
-}
-
-
bool JSFunction::IsInlineable() {
if (IsBuiltin()) return false;
SharedFunctionInfo* shared_info = shared();
@@ -7449,19 +6351,11 @@
}
-MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
- ASSERT(value->IsJSReceiver());
+Object* JSFunction::SetInstancePrototype(Object* value) {
+ ASSERT(value->IsJSObject());
Heap* heap = GetHeap();
if (has_initial_map()) {
- // If the function has allocated the initial map
- // replace it with a copy containing the new prototype.
- Map* new_map;
- MaybeObject* maybe_new_map = initial_map()->CopyDropTransitions();
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
- new_map->set_prototype(value);
- MaybeObject* maybe_object =
- set_initial_map_and_cache_transitions(new_map);
- if (maybe_object->IsFailure()) return maybe_object;
+ 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
@@ -7477,19 +6371,20 @@
ASSERT(should_have_prototype());
Object* construct_prototype = value;
- // If the value is not a JSReceiver, store the value in the map's
+ // If the value is not a JSObject, store the value in the map's
// constructor field so it can be accessed. Also, set the prototype
// used for constructing objects to the original object prototype.
// See ECMA-262 13.2.2.
- if (!value->IsJSReceiver()) {
+ 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.
- Map* new_map;
+ Object* new_object;
{ MaybeObject* maybe_new_map = map()->CopyDropTransitions();
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+ if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
}
- Heap* heap = new_map->GetHeap();
+ 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);
@@ -7506,21 +6401,21 @@
Object* JSFunction::RemovePrototype() {
Context* global_context = context()->global_context();
- Map* no_prototype_map = shared()->is_classic_mode()
- ? global_context->function_without_prototype_map()
- : global_context->strict_mode_function_without_prototype_map();
+ 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(map() == (shared()->is_classic_mode()
- ? global_context->function_map()
- : global_context->strict_mode_function_map()));
+ 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->GetHeap()->the_hole_value());
+ set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
return this;
}
@@ -7545,12 +6440,12 @@
MaybeObject* Oddball::Initialize(const char* to_string,
Object* to_number,
byte kind) {
- String* symbol;
+ Object* symbol;
{ MaybeObject* maybe_symbol =
Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
- if (!maybe_symbol->To(&symbol)) return maybe_symbol;
+ if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
}
- set_to_string(symbol);
+ set_to_string(String::cast(symbol));
set_to_number(to_number);
set_kind(kind);
return this;
@@ -7570,10 +6465,13 @@
}
-Handle<Object> SharedFunctionInfo::GetSourceCode() {
- if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
- Handle<String> source(String::cast(Script::cast(script())->source()));
- return SubString(source, start_position(), end_position());
+Object* SharedFunctionInfo::GetSourceCode() {
+ 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), isolate),
+ start_position(), end_position());
}
@@ -7621,10 +6519,10 @@
obj = obj->GetPrototype()) {
JSObject* js_object = JSObject::cast(obj);
for (int i = 0; i < this_property_assignments_count(); i++) {
- LookupResult result(heap->isolate());
+ LookupResult result;
String* name = GetThisPropertyAssignmentName(i);
js_object->LocalLookupRealNamedProperty(name, &result);
- if (result.IsFound() && result.type() == CALLBACKS) {
+ if (result.IsProperty() && result.type() == CALLBACKS) {
return false;
}
}
@@ -7770,7 +6668,7 @@
}
-void SharedFunctionInfo::DisableOptimization() {
+void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
// Disable optimization for the shared function info and mark the
// code as non-optimizable. The marker on the shared function info
// is there because we flush non-optimized code thereby loosing the
@@ -7786,12 +6684,17 @@
code()->set_optimizable(false);
}
if (FLAG_trace_opt) {
- PrintF("[disabled optimization for %s]\n", *DebugName()->ToCString());
+ PrintF("[disabled optimization for: ");
+ function->PrintName();
+ PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
}
}
bool SharedFunctionInfo::VerifyBailoutId(int id) {
+ // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
+ // we are always bailing out on ARM.
+
ASSERT(id != AstNode::kNoNumber);
Code* unoptimized = code();
DeoptimizationOutputData* data =
@@ -7805,8 +6708,6 @@
void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
ASSERT(!IsInobjectSlackTrackingInProgress());
- if (!FLAG_clever_optimizations) return;
-
// Only initiate the tracking the first time.
if (live_objects_may_exist()) return;
set_live_objects_may_exist(true);
@@ -7822,7 +6723,7 @@
set_construction_count(kGenerousAllocationCount);
}
set_initial_map(map);
- Builtins* builtins = map->GetHeap()->isolate()->builtins();
+ Builtins* builtins = map->heap()->isolate()->builtins();
ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
construct_stub());
set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
@@ -7842,9 +6743,8 @@
// 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.
- Heap* heap = map->GetHeap();
- set_initial_map(heap->raw_unchecked_undefined_value());
- Builtins* builtins = heap->isolate()->builtins();
+ 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::kJSConstructStubGeneric));
@@ -7860,7 +6760,7 @@
// Resume inobject slack tracking.
set_initial_map(map);
- Builtins* builtins = map->GetHeap()->isolate()->builtins();
+ Builtins* builtins = map->heap()->isolate()->builtins();
ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
*RawField(this, kConstructStubOffset));
set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
@@ -7892,7 +6792,7 @@
ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
Map* map = Map::cast(initial_map());
- Heap* heap = map->GetHeap();
+ Heap* heap = map->heap();
set_initial_map(heap->undefined_value());
Builtins* builtins = heap->isolate()->builtins();
ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
@@ -7912,22 +6812,6 @@
}
-#define DECLARE_TAG(ignore1, name, ignore2) name,
-const char* const VisitorSynchronization::kTags[
- VisitorSynchronization::kNumberOfSyncTags] = {
- VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
-};
-#undef DECLARE_TAG
-
-
-#define DECLARE_TAG(ignore1, ignore2, name) name,
-const char* const VisitorSynchronization::kTagNames[
- VisitorSynchronization::kNumberOfSyncTags] = {
- VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
-};
-#undef DECLARE_TAG
-
-
void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
@@ -7970,18 +6854,8 @@
}
-void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
- ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
- VisitPointer(rinfo->target_object_address());
-}
-
-void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
- Address* p = rinfo->target_reference_address();
- VisitExternalReferences(p, p + 1);
-}
-
void Code::InvalidateRelocation() {
- set_relocation_info(GetHeap()->empty_byte_array());
+ set_relocation_info(heap()->empty_byte_array());
}
@@ -7994,8 +6868,6 @@
void Code::CopyFrom(const CodeDesc& desc) {
- ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
-
// copy code
memmove(instruction_start(), desc.buffer, desc.instr_size);
@@ -8015,17 +6887,16 @@
RelocInfo::Mode mode = it.rinfo()->rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
Handle<Object> p = it.rinfo()->target_object_handle(origin);
- it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
+ it.rinfo()->set_target_object(*p);
} else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
- Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
- it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
+ Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
+ it.rinfo()->set_target_cell(*cell);
} else if (RelocInfo::IsCodeTarget(mode)) {
// rewrite code handles in inline cache targets to direct
// pointers to the first instruction in the code object
Handle<Object> p = it.rinfo()->target_object_handle(origin);
Code* code = Code::cast(*p);
- it.rinfo()->set_target_address(code->instruction_start(),
- SKIP_WRITE_BARRIER);
+ it.rinfo()->set_target_address(code->instruction_start());
} else {
it.rinfo()->apply(delta);
}
@@ -8144,11 +7015,8 @@
static_cast<Translation::Opcode>(iterator.Next());
ASSERT(Translation::BEGIN == opcode);
int frame_count = iterator.Next();
- int jsframe_count = iterator.Next();
- PrintF(out, " %s {frame count=%d, js frame count=%d}\n",
- Translation::StringFor(opcode),
- frame_count,
- jsframe_count);
+ PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
+ frame_count);
while (iterator.HasNext() &&
Translation::BEGIN !=
@@ -8160,7 +7028,7 @@
UNREACHABLE();
break;
- case Translation::JS_FRAME: {
+ case Translation::FRAME: {
int ast_id = iterator.Next();
int function_id = iterator.Next();
JSFunction* function =
@@ -8172,18 +7040,6 @@
break;
}
- case Translation::ARGUMENTS_ADAPTOR_FRAME:
- case Translation::CONSTRUCT_STUB_FRAME: {
- int function_id = iterator.Next();
- JSFunction* function =
- JSFunction::cast(LiteralArray()->get(function_id));
- unsigned height = iterator.Next();
- PrintF(out, "{function=");
- function->PrintName(out);
- PrintF(out, ", height=%u}", height);
- break;
- }
-
case Translation::DUPLICATE:
break;
@@ -8307,7 +7163,7 @@
case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
}
- UNREACHABLE(); // keep the compiler happy
+ UNREACHABLE();
return NULL;
}
@@ -8416,55 +7272,125 @@
#endif // ENABLE_DISASSEMBLER
-MaybeObject* JSObject::SetFastElementsCapacityAndLength(
- int capacity,
- int length,
- SetFastElementsCapacityMode set_capacity_mode) {
+static void CopyFastElementsToFast(FixedArray* source,
+ FixedArray* destination,
+ WriteBarrierMode mode) {
+ uint32_t count = static_cast<uint32_t>(source->length());
+ for (uint32_t i = 0; i < count; ++i) {
+ destination->set(i, source->get(i), mode);
+ }
+}
+
+
+static void CopySlowElementsToFast(SeededNumberDictionary* source,
+ FixedArray* destination,
+ WriteBarrierMode mode) {
+ for (int i = 0; i < source->Capacity(); ++i) {
+ Object* key = source->KeyAt(i);
+ if (key->IsNumber()) {
+ uint32_t entry = static_cast<uint32_t>(key->Number());
+ destination->set(entry, source->ValueAt(i), mode);
+ }
+ }
+}
+
+
+MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
+ int length) {
Heap* heap = GetHeap();
// We should never end in here with a pixel or external array.
ASSERT(!HasExternalArrayElements());
// Allocate a new fast elements backing store.
- FixedArray* new_elements;
- { MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
- if (!maybe->To(&new_elements)) return maybe;
+ FixedArray* new_elements = NULL;
+ { Object* object;
+ MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
+ if (!maybe->ToObject(&object)) return maybe;
+ new_elements = FixedArray::cast(object);
}
// Find the new map to use for this object if there is a map change.
Map* new_map = NULL;
if (elements()->map() != heap->non_strict_arguments_elements_map()) {
- // The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces
- // it, or if it's allowed and the old elements array contained only SMIs.
- bool has_fast_smi_only_elements =
- (set_capacity_mode == kForceSmiOnlyElements) ||
- ((set_capacity_mode == kAllowSmiOnlyElements) &&
- (elements()->map()->has_fast_smi_only_elements() ||
- elements() == heap->empty_fixed_array()));
- ElementsKind elements_kind = has_fast_smi_only_elements
- ? FAST_SMI_ONLY_ELEMENTS
- : FAST_ELEMENTS;
- MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), elements_kind);
- if (!maybe->To(&new_map)) return maybe;
+ Object* object;
+ MaybeObject* maybe = map()->GetFastElementsMap();
+ if (!maybe->ToObject(&object)) return maybe;
+ new_map = Map::cast(object);
}
- FixedArrayBase* old_elements = elements();
- ElementsKind elements_kind = GetElementsKind();
- ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
- ElementsKind to_kind = (elements_kind == FAST_SMI_ONLY_ELEMENTS)
- ? FAST_SMI_ONLY_ELEMENTS
- : FAST_ELEMENTS;
- // int copy_size = Min(old_elements_raw->length(), new_elements->length());
- accessor->CopyElements(this, new_elements, to_kind);
- if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
- set_map_and_elements(new_map, new_elements);
- } else {
- FixedArray* parameter_map = FixedArray::cast(old_elements);
- parameter_map->set(1, new_elements);
- }
-
- if (FLAG_trace_elements_transitions) {
- PrintElementsTransition(stdout, elements_kind, old_elements,
- GetElementsKind(), new_elements);
+ switch (GetElementsKind()) {
+ case FAST_ELEMENTS: {
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
+ CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
+ set_map(new_map);
+ set_elements(new_elements);
+ break;
+ }
+ case DICTIONARY_ELEMENTS: {
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
+ CopySlowElementsToFast(SeededNumberDictionary::cast(elements()),
+ new_elements,
+ mode);
+ set_map(new_map);
+ set_elements(new_elements);
+ break;
+ }
+ case NON_STRICT_ARGUMENTS_ELEMENTS: {
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
+ // The object's map and the parameter map are unchanged, the unaliased
+ // arguments are copied to the new backing store.
+ FixedArray* parameter_map = FixedArray::cast(elements());
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ if (arguments->IsDictionary()) {
+ CopySlowElementsToFast(SeededNumberDictionary::cast(arguments),
+ new_elements,
+ mode);
+ } else {
+ CopyFastElementsToFast(arguments, new_elements, mode);
+ }
+ parameter_map->set(1, new_elements);
+ break;
+ }
+ case FAST_DOUBLE_ELEMENTS: {
+ FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements());
+ uint32_t old_length = static_cast<uint32_t>(old_elements->length());
+ // Fill out the new array with this content and array holes.
+ for (uint32_t i = 0; i < old_length; i++) {
+ if (!old_elements->is_the_hole(i)) {
+ Object* obj;
+ // Objects must be allocated in the old object space, since the
+ // overall number of HeapNumbers needed for the conversion might
+ // exceed the capacity of new space, and we would fail repeatedly
+ // trying to convert the FixedDoubleArray.
+ MaybeObject* maybe_value_object =
+ GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
+ TENURED);
+ if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
+ // Force write barrier. It's not worth trying to exploit
+ // elems->GetWriteBarrierMode(), since it requires an
+ // AssertNoAllocation stack object that would have to be positioned
+ // after the HeapNumber allocation anyway.
+ new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
+ }
+ }
+ set_map(new_map);
+ set_elements(new_elements);
+ break;
+ }
+ 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:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ UNREACHABLE();
+ break;
}
// Update the length if necessary.
@@ -8483,33 +7409,41 @@
// We should never end in here with a pixel or external array.
ASSERT(!HasExternalArrayElements());
- FixedDoubleArray* elems;
+ Object* obj;
{ MaybeObject* maybe_obj =
heap->AllocateUninitializedFixedDoubleArray(capacity);
- if (!maybe_obj->To(&elems)) return maybe_obj;
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+ FixedDoubleArray* elems = FixedDoubleArray::cast(obj);
+
+ { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap();
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+ Map* new_map = Map::cast(obj);
+
+ AssertNoAllocation no_gc;
+ switch (GetElementsKind()) {
+ case FAST_ELEMENTS: {
+ elems->Initialize(FixedArray::cast(elements()));
+ break;
+ }
+ case FAST_DOUBLE_ELEMENTS: {
+ elems->Initialize(FixedDoubleArray::cast(elements()));
+ break;
+ }
+ case DICTIONARY_ELEMENTS: {
+ elems->Initialize(SeededNumberDictionary::cast(elements()));
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
}
- Map* new_map;
- { MaybeObject* maybe_obj =
- GetElementsTransitionMap(heap->isolate(), FAST_DOUBLE_ELEMENTS);
- if (!maybe_obj->To(&new_map)) return maybe_obj;
- }
-
- FixedArrayBase* old_elements = elements();
- ElementsKind elements_kind = GetElementsKind();
- ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
- accessor->CopyElements(this, elems, FAST_DOUBLE_ELEMENTS);
- if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
- set_map_and_elements(new_map, elems);
- } else {
- FixedArray* parameter_map = FixedArray::cast(old_elements);
- parameter_map->set(1, elems);
- }
-
- if (FLAG_trace_elements_transitions) {
- PrintElementsTransition(stdout, elements_kind, old_elements,
- FAST_DOUBLE_ELEMENTS, elems);
- }
+ ASSERT(new_map->has_fast_double_elements());
+ set_map(new_map);
+ ASSERT(elems->IsFixedDoubleArray());
+ set_elements(elems);
if (IsJSArray()) {
JSArray::cast(this)->set_length(Smi::FromInt(length));
@@ -8519,6 +7453,53 @@
}
+MaybeObject* JSObject::SetSlowElements(Object* len) {
+ // We should never end in here with a pixel or external array.
+ ASSERT(!HasExternalArrayElements());
+
+ uint32_t new_length = static_cast<uint32_t>(len->Number());
+
+ switch (GetElementsKind()) {
+ case FAST_ELEMENTS: {
+ case FAST_DOUBLE_ELEMENTS:
+ // Make sure we never try to shrink dense arrays into sparse arrays.
+ ASSERT(static_cast<uint32_t>(
+ FixedArrayBase::cast(elements())->length()) <= new_length);
+ MaybeObject* result = NormalizeElements();
+ if (result->IsFailure()) return result;
+
+ // Update length for JSArrays.
+ if (IsJSArray()) JSArray::cast(this)->set_length(len);
+ break;
+ }
+ case DICTIONARY_ELEMENTS: {
+ if (IsJSArray()) {
+ uint32_t old_length =
+ static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
+ element_dictionary()->RemoveNumberEntries(new_length, old_length),
+ JSArray::cast(this)->set_length(len);
+ }
+ break;
+ }
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
+ UNIMPLEMENTED();
+ break;
+ 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:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ UNREACHABLE();
+ break;
+ }
+ return this;
+}
+
+
MaybeObject* JSArray::Initialize(int capacity) {
Heap* heap = GetHeap();
ASSERT(capacity >= 0);
@@ -8527,8 +7508,11 @@
if (capacity == 0) {
new_elements = heap->empty_fixed_array();
} else {
- MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
- if (!maybe_obj->To(&new_elements)) return maybe_obj;
+ Object* obj;
+ { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+ new_elements = FixedArray::cast(obj);
}
set_elements(new_elements);
return this;
@@ -8536,15 +7520,162 @@
void JSArray::Expand(int required_size) {
- GetIsolate()->factory()->SetElementsCapacityAndLength(
- Handle<JSArray>(this), required_size, 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);
+ // 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);
}
-MaybeObject* JSArray::SetElementsLength(Object* len) {
+static Failure* ArrayLengthRangeError(Heap* heap) {
+ HandleScope scope(heap->isolate());
+ 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.
ASSERT(AllowsSetElementsLength());
- return GetElementsAccessor()->SetLength(this, len);
+
+ 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(GetHeap());
+ ElementsKind elements_kind = GetElementsKind();
+ switch (elements_kind) {
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS: {
+ int old_capacity = FixedArrayBase::cast(elements())->length();
+ if (value <= old_capacity) {
+ if (IsJSArray()) {
+ Object* obj;
+ if (elements_kind == FAST_ELEMENTS) {
+ MaybeObject* maybe_obj = EnsureWritableFastElements();
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+ if (2 * value <= old_capacity) {
+ // If more than half the elements won't be used, trim the array.
+ if (value == 0) {
+ initialize_elements();
+ } else {
+ Address filler_start;
+ int filler_size;
+ if (GetElementsKind() == FAST_ELEMENTS) {
+ FixedArray* fast_elements = FixedArray::cast(elements());
+ fast_elements->set_length(value);
+ filler_start = fast_elements->address() +
+ FixedArray::OffsetOfElementAt(value);
+ filler_size = (old_capacity - value) * kPointerSize;
+ } else {
+ ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ FixedDoubleArray* fast_double_elements =
+ FixedDoubleArray::cast(elements());
+ fast_double_elements->set_length(value);
+ filler_start = fast_double_elements->address() +
+ FixedDoubleArray::OffsetOfElementAt(value);
+ filler_size = (old_capacity - value) * kDoubleSize;
+ }
+ GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
+ }
+ } else {
+ // Otherwise, fill the unused tail with holes.
+ int old_length = FastD2I(JSArray::cast(this)->length()->Number());
+ if (GetElementsKind() == FAST_ELEMENTS) {
+ FixedArray* fast_elements = FixedArray::cast(elements());
+ for (int i = value; i < old_length; i++) {
+ fast_elements->set_the_hole(i);
+ }
+ } else {
+ ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ FixedDoubleArray* fast_double_elements =
+ FixedDoubleArray::cast(elements());
+ for (int i = value; i < old_length; i++) {
+ fast_double_elements->set_the_hole(i);
+ }
+ }
+ }
+ JSArray::cast(this)->set_length(Smi::cast(smi_length));
+ }
+ return this;
+ }
+ int min = NewElementsCapacity(old_capacity);
+ int new_capacity = value > min ? value : min;
+ if (!ShouldConvertToSlowElements(new_capacity)) {
+ MaybeObject* result;
+ if (GetElementsKind() == FAST_ELEMENTS) {
+ result = SetFastElementsCapacityAndLength(new_capacity, value);
+ } else {
+ ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ result = SetFastDoubleElementsCapacityAndLength(new_capacity,
+ value);
+ }
+ if (result->IsFailure()) return result;
+ return this;
+ }
+ break;
+ }
+ case DICTIONARY_ELEMENTS: {
+ if (IsJSArray()) {
+ if (value == 0) {
+ // If the length of a slow array is reset to zero, we clear
+ // the array and flush backing storage. This has the added
+ // benefit that the array returns to fast mode.
+ Object* obj;
+ { MaybeObject* maybe_obj = ResetElements();
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+ } else {
+ // Remove deleted elements.
+ uint32_t old_length =
+ static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
+ element_dictionary()->RemoveNumberEntries(value, old_length);
+ }
+ JSArray::cast(this)->set_length(Smi::cast(smi_length));
+ }
+ return this;
+ }
+ case NON_STRICT_ARGUMENTS_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:
+ case EXTERNAL_DOUBLE_ELEMENTS:
+ case EXTERNAL_PIXEL_ELEMENTS:
+ UNREACHABLE();
+ break;
+ }
+ }
+
+ // General slow case.
+ if (len->IsNumber()) {
+ uint32_t length;
+ if (len->ToArrayIndex(&length)) {
+ return SetSlowElements(len);
+ } else {
+ 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 = 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));
+ return this;
}
@@ -8587,8 +7718,8 @@
FixedArray* new_cache;
// Grow array by factor 2 over and above what we need.
{ MaybeObject* maybe_cache =
- GetHeap()->AllocateFixedArray(transitions * 2 * step + header);
- if (!maybe_cache->To(&new_cache)) return maybe_cache;
+ heap()->AllocateFixedArray(transitions * 2 * step + header);
+ if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
}
for (int i = 0; i < capacity * step; i++) {
@@ -8640,7 +7771,7 @@
// 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()) {
- if (JSReceiver::cast(pt) == this) {
+ if (JSObject::cast(pt) == this) {
// Cycle detected.
HandleScope scope(heap->isolate());
return heap->isolate()->Throw(
@@ -8655,8 +7786,8 @@
// hidden and set the new prototype on that object.
Object* current_proto = real_receiver->GetPrototype();
while (current_proto->IsJSObject() &&
- JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) {
- real_receiver = JSReceiver::cast(current_proto);
+ JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
+ real_receiver = JSObject::cast(current_proto);
current_proto = current_proto->GetPrototype();
}
}
@@ -8689,16 +7820,69 @@
}
-MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
- uint32_t first_arg,
- uint32_t arg_count,
- EnsureElementsMode mode) {
- // Elements in |Arguments| are ordered backwards (because they're on the
- // stack), but the method that's called here iterates over them in forward
- // direction.
- return EnsureCanContainElements(
- args->arguments() - first_arg - (arg_count - 1),
- arg_count, mode);
+bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
+ switch (GetElementsKind()) {
+ case FAST_ELEMENTS: {
+ uint32_t length = IsJSArray() ?
+ static_cast<uint32_t>
+ (Smi::cast(JSArray::cast(this)->length())->value()) :
+ static_cast<uint32_t>(FixedArray::cast(elements())->length());
+ if ((index < length) &&
+ !FixedArray::cast(elements())->get(index)->IsTheHole()) {
+ return true;
+ }
+ break;
+ }
+ case FAST_DOUBLE_ELEMENTS: {
+ uint32_t length = IsJSArray() ?
+ static_cast<uint32_t>
+ (Smi::cast(JSArray::cast(this)->length())->value()) :
+ static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
+ if ((index < length) &&
+ !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
+ return true;
+ }
+ break;
+ }
+ case EXTERNAL_PIXEL_ELEMENTS: {
+ ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
+ if (index < static_cast<uint32_t>(pixels->length())) {
+ return true;
+ }
+ break;
+ }
+ 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:
+ case EXTERNAL_DOUBLE_ELEMENTS: {
+ ExternalArray* array = ExternalArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ return true;
+ }
+ break;
+ }
+ case DICTIONARY_ELEMENTS: {
+ if (element_dictionary()->FindEntry(index)
+ != SeededNumberDictionary::kNotFound) {
+ return true;
+ }
+ break;
+ }
+ case NON_STRICT_ARGUMENTS_ELEMENTS:
+ UNREACHABLE();
+ break;
+ }
+
+ // Handle [] on String objects.
+ if (this->IsStringObjectWithCharacterAt(index)) return true;
+
+ Object* pt = GetPrototype();
+ if (pt->IsNull()) return false;
+ return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
}
@@ -8741,21 +7925,7 @@
}
if (!result.IsEmpty()) return true;
}
-
- if (holder_handle->GetElementsAccessor()->HasElement(
- *receiver_handle, *holder_handle, index)) {
- return true;
- }
-
- if (holder_handle->IsStringObjectWithCharacterAt(index)) return true;
- Object* pt = holder_handle->GetPrototype();
- if (pt->IsJSProxy()) {
- // We need to follow the spec and simulate a call to [[GetOwnProperty]].
- return JSProxy::cast(pt)->GetElementAttributeWithHandler(
- receiver, index) != ABSENT;
- }
- if (pt->IsNull()) return false;
- return JSObject::cast(pt)->HasElementWithReceiver(*receiver_handle, index);
+ return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
}
@@ -8788,7 +7958,6 @@
}
switch (GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
uint32_t length = IsJSArray() ?
static_cast<uint32_t>
@@ -8865,6 +8034,28 @@
}
+bool JSObject::HasElementInElements(FixedArray* elements,
+ ElementsKind kind,
+ uint32_t index) {
+ ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
+ if (kind == FAST_ELEMENTS) {
+ int length = IsJSArray()
+ ? Smi::cast(JSArray::cast(this)->length())->value()
+ : elements->length();
+ if (index < static_cast<uint32_t>(length) &&
+ !elements->get(index)->IsTheHole()) {
+ return true;
+ }
+ } else {
+ if (SeededNumberDictionary::cast(elements)->FindEntry(index) !=
+ SeededNumberDictionary::kNotFound) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
// Check access rights if needed.
if (IsAccessCheckNeeded()) {
@@ -8880,9 +8071,67 @@
return HasElementWithInterceptor(receiver, index);
}
- ElementsAccessor* accessor = GetElementsAccessor();
- if (accessor->HasElement(receiver, this, index)) {
- return true;
+ ElementsKind kind = GetElementsKind();
+ switch (kind) {
+ case FAST_ELEMENTS: {
+ uint32_t length = IsJSArray() ?
+ static_cast<uint32_t>
+ (Smi::cast(JSArray::cast(this)->length())->value()) :
+ static_cast<uint32_t>(FixedArray::cast(elements())->length());
+ if ((index < length) &&
+ !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
+ break;
+ }
+ case FAST_DOUBLE_ELEMENTS: {
+ uint32_t length = IsJSArray() ?
+ static_cast<uint32_t>
+ (Smi::cast(JSArray::cast(this)->length())->value()) :
+ static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
+ if ((index < length) &&
+ !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
+ break;
+ }
+ case EXTERNAL_PIXEL_ELEMENTS: {
+ ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
+ if (index < static_cast<uint32_t>(pixels->length())) {
+ return true;
+ }
+ break;
+ }
+ 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:
+ case EXTERNAL_DOUBLE_ELEMENTS: {
+ ExternalArray* array = ExternalArray::cast(elements());
+ if (index < static_cast<uint32_t>(array->length())) {
+ return true;
+ }
+ break;
+ }
+ case DICTIONARY_ELEMENTS: {
+ if (element_dictionary()->FindEntry(index)
+ != SeededNumberDictionary::kNotFound) {
+ return true;
+ }
+ break;
+ }
+ case NON_STRICT_ARGUMENTS_ELEMENTS: {
+ FixedArray* parameter_map = FixedArray::cast(elements());
+ uint32_t length = parameter_map->length();
+ Object* probe =
+ (index < length - 2) ? parameter_map->get(index + 2) : NULL;
+ if (probe != NULL && !probe->IsTheHole()) return true;
+
+ // Not a mapped parameter, check the arguments.
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
+ if (HasElementInElements(arguments, kind, index)) return true;
+ break;
+ }
}
// Handle [] on String objects.
@@ -8890,21 +8139,14 @@
Object* pt = GetPrototype();
if (pt->IsNull()) return false;
- if (pt->IsJSProxy()) {
- // We need to follow the spec and simulate a call to [[GetOwnProperty]].
- return JSProxy::cast(pt)->GetElementAttributeWithHandler(
- receiver, index) != ABSENT;
- }
return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
}
MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Object* value,
- PropertyAttributes attributes,
StrictModeFlag strict_mode,
- bool check_prototype,
- SetPropertyMode set_mode) {
+ bool check_prototype) {
Isolate* isolate = GetIsolate();
// Make sure that the top context does not change when doing
// callbacks or interceptor calls.
@@ -8932,10 +8174,8 @@
MaybeObject* raw_result =
this_handle->SetElementWithoutInterceptor(index,
*value_handle,
- attributes,
strict_mode,
- check_prototype,
- set_mode);
+ check_prototype);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return raw_result;
}
@@ -8973,11 +8213,11 @@
}
// __defineGetter__ callback
- if (structure->IsAccessorPair()) {
- Object* getter = AccessorPair::cast(structure)->getter();
- if (getter->IsSpecFunction()) {
- // TODO(rossberg): nicer would be to cast to some JSCallable here...
- return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
+ if (structure->IsFixedArray()) {
+ Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
+ if (getter->IsJSFunction()) {
+ return Object::GetPropertyWithDefinedGetter(receiver,
+ JSFunction::cast(getter));
}
// Getter is not a function.
return isolate->heap()->undefined_value();
@@ -9030,11 +8270,10 @@
return *value_handle;
}
- if (structure->IsAccessorPair()) {
- Handle<Object> setter(AccessorPair::cast(structure)->setter());
- if (setter->IsSpecFunction()) {
- // TODO(rossberg): nicer would be to cast to some JSCallable here...
- return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
+ if (structure->IsFixedArray()) {
+ Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
+ if (setter->IsJSFunction()) {
+ return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value);
} else {
if (strict_mode == kNonStrictMode) {
return value;
@@ -9084,20 +8323,21 @@
Object* value,
StrictModeFlag strict_mode,
bool check_prototype) {
- ASSERT(HasFastTypeElements() ||
- HasFastArgumentsElements());
+ ASSERT(HasFastElements() || HasFastArgumentsElements());
FixedArray* backing_store = FixedArray::cast(elements());
if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
backing_store = FixedArray::cast(backing_store->get(1));
} else {
+ Object* writable;
MaybeObject* maybe = EnsureWritableFastElements();
- if (!maybe->To(&backing_store)) return maybe;
+ if (!maybe->ToObject(&writable)) return maybe;
+ backing_store = FixedArray::cast(writable);
}
- uint32_t capacity = static_cast<uint32_t>(backing_store->length());
+ uint32_t length = static_cast<uint32_t>(backing_store->length());
if (check_prototype &&
- (index >= capacity || backing_store->get(index)->IsTheHole())) {
+ (index >= length || backing_store->get(index)->IsTheHole())) {
bool found;
MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
value,
@@ -9106,88 +8346,46 @@
if (found) return result;
}
- uint32_t new_capacity = capacity;
- // Check if the length property of this object needs to be updated.
- uint32_t array_length = 0;
- bool must_update_array_length = false;
- if (IsJSArray()) {
- CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
- if (index >= array_length) {
- must_update_array_length = true;
- array_length = index + 1;
- }
- }
- // Check if the capacity of the backing store needs to be increased, or if
- // a transition to slow elements is necessary.
- if (index >= capacity) {
- bool convert_to_slow = true;
- if ((index - capacity) < kMaxGap) {
- new_capacity = NewElementsCapacity(index + 1);
- ASSERT(new_capacity > index);
- if (!ShouldConvertToSlowElements(new_capacity)) {
- convert_to_slow = false;
+ // Check whether there is extra space in fixed array.
+ if (index < length) {
+ backing_store->set(index, value);
+ if (IsJSArray()) {
+ // Update the length of the array if needed.
+ uint32_t array_length = 0;
+ CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
+ if (index >= array_length) {
+ JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
}
}
- if (convert_to_slow) {
- MaybeObject* result = NormalizeElements();
- if (result->IsFailure()) return result;
- return SetDictionaryElement(index, value, NONE, strict_mode,
- check_prototype);
- }
- }
- // Convert to fast double elements if appropriate.
- if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) {
- MaybeObject* maybe =
- SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
- if (maybe->IsFailure()) return maybe;
- FixedDoubleArray::cast(elements())->set(index, value->Number());
return value;
}
- // Change elements kind from SMI_ONLY to generic FAST if necessary.
- if (HasFastSmiOnlyElements() && !value->IsSmi()) {
- Map* new_map;
- { MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
- FAST_ELEMENTS);
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
- }
- set_map(new_map);
- if (FLAG_trace_elements_transitions) {
- PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
- FAST_ELEMENTS, elements());
+
+ // Allow gap in fast case.
+ if ((index - length) < kMaxGap) {
+ // Try allocating extra space.
+ int new_capacity = NewElementsCapacity(index + 1);
+ if (!ShouldConvertToSlowElements(new_capacity)) {
+ ASSERT(static_cast<uint32_t>(new_capacity) > index);
+ Object* new_elements;
+ MaybeObject* maybe =
+ SetFastElementsCapacityAndLength(new_capacity, index + 1);
+ if (!maybe->ToObject(&new_elements)) return maybe;
+ FixedArray::cast(new_elements)->set(index, value);
+ return value;
}
}
- // Increase backing store capacity if that's been decided previously.
- if (new_capacity != capacity) {
- FixedArray* new_elements;
- SetFastElementsCapacityMode set_capacity_mode =
- value->IsSmi() && HasFastSmiOnlyElements()
- ? kAllowSmiOnlyElements
- : kDontAllowSmiOnlyElements;
- { MaybeObject* maybe =
- SetFastElementsCapacityAndLength(new_capacity,
- array_length,
- set_capacity_mode);
- if (!maybe->To(&new_elements)) return maybe;
- }
- new_elements->set(index, value);
- return value;
- }
- // Finally, set the new element and length.
- ASSERT(elements()->IsFixedArray());
- backing_store->set(index, value);
- if (must_update_array_length) {
- JSArray::cast(this)->set_length(Smi::FromInt(array_length));
- }
- return value;
+
+ // Otherwise default to slow case.
+ MaybeObject* result = NormalizeElements();
+ if (result->IsFailure()) return result;
+ return SetDictionaryElement(index, value, strict_mode, check_prototype);
}
MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
Object* value,
- PropertyAttributes attributes,
StrictModeFlag strict_mode,
- bool check_prototype,
- SetPropertyMode set_mode) {
+ bool check_prototype) {
ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Isolate* isolate = GetIsolate();
Heap* heap = isolate->heap();
@@ -9207,40 +8405,20 @@
if (entry != SeededNumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
+ if (details.type() == CALLBACKS) {
return SetElementWithCallback(element, index, value, this, strict_mode);
} else {
dictionary->UpdateMaxNumberKey(index);
- // If a value has not been initialized we allow writing to it even if it
- // is read-only (a declared const that has not been initialized). If a
- // value is being defined we skip attribute checks completely.
- if (set_mode == DEFINE_PROPERTY) {
- details = PropertyDetails(attributes, NORMAL, details.index());
- dictionary->DetailsAtPut(entry, details);
- } else if (details.IsReadOnly() && !element->IsTheHole()) {
- if (strict_mode == kNonStrictMode) {
- return isolate->heap()->undefined_value();
- } else {
- Handle<Object> holder(this);
- Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
- Handle<Object> args[2] = { number, holder };
- Handle<Object> error =
- isolate->factory()->NewTypeError("strict_read_only_property",
- HandleVector(args, 2));
- return isolate->Throw(*error);
- }
+ // If put fails in strict mode, throw an exception.
+ if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) {
+ Handle<Object> holder(this);
+ Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
+ Handle<Object> args[2] = { number, holder };
+ Handle<Object> error =
+ isolate->factory()->NewTypeError("strict_read_only_property",
+ HandleVector(args, 2));
+ return isolate->Throw(*error);
}
- // Elements of the arguments object in slow mode might be slow aliases.
- if (is_arguments && element->IsAliasedArgumentsEntry()) {
- AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(element);
- Context* context = Context::cast(elements->get(0));
- int context_index = entry->aliased_context_slot();
- ASSERT(!context->get(context_index)->IsTheHole());
- context->set(context_index, value);
- // For elements that are still writable we keep slow aliasing.
- if (!details.IsReadOnly()) value = element;
- }
- dictionary->ValueAtPut(entry, value);
}
} else {
// Index not already used. Look for an accessor in the prototype chain.
@@ -9267,9 +8445,8 @@
}
}
FixedArrayBase* new_dictionary;
- PropertyDetails details = PropertyDetails(attributes, NORMAL);
- MaybeObject* maybe = dictionary->AddNumberEntry(index, value, details);
- if (!maybe->To(&new_dictionary)) return maybe;
+ MaybeObject* maybe = dictionary->AtNumberPut(index, value);
+ if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
if (is_arguments) {
elements->set(1, new_dictionary);
@@ -9295,20 +8472,9 @@
} else {
new_length = dictionary->max_number_key() + 1;
}
- SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays
- ? kAllowSmiOnlyElements
- : kDontAllowSmiOnlyElements;
- bool has_smi_only_elements = false;
- bool should_convert_to_fast_double_elements =
- ShouldConvertToFastDoubleElements(&has_smi_only_elements);
- if (has_smi_only_elements) {
- set_capacity_mode = kForceSmiOnlyElements;
- }
- MaybeObject* result = should_convert_to_fast_double_elements
+ MaybeObject* result = CanConvertToFastDoubleElements()
? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
- : SetFastElementsCapacityAndLength(new_length,
- new_length,
- set_capacity_mode);
+ : SetFastElementsCapacityAndLength(new_length, new_length);
if (result->IsFailure()) return result;
#ifdef DEBUG
if (FLAG_trace_normalization) {
@@ -9328,14 +8494,13 @@
bool check_prototype) {
ASSERT(HasFastDoubleElements());
- FixedArrayBase* base_elms = FixedArrayBase::cast(elements());
- uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
+ FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
+ uint32_t elms_length = static_cast<uint32_t>(elms->length());
// If storing to an element that isn't in the array, pass the store request
// up the prototype chain before storing in the receiver's elements.
if (check_prototype &&
- (index >= elms_length ||
- FixedDoubleArray::cast(base_elms)->is_the_hole(index))) {
+ (index >= elms_length || elms->is_the_hole(index))) {
bool found;
MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
value,
@@ -9353,15 +8518,10 @@
if (IsJSArray()) {
CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
}
- MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
- elms_length,
- length,
- kDontAllowSmiOnlyElements);
+ MaybeObject* maybe_obj =
+ SetFastElementsCapacityAndLength(elms_length, length);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- return SetFastElement(index,
- value,
- strict_mode,
- check_prototype);
+ return SetFastElement(index, value, strict_mode, check_prototype);
}
double double_value = value_is_smi
@@ -9370,7 +8530,6 @@
// Check whether there is extra space in the fixed array.
if (index < elms_length) {
- FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
elms->set(index, double_value);
if (IsJSArray()) {
// Update the length of the array if needed.
@@ -9409,64 +8568,14 @@
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
ASSERT(HasDictionaryElements());
- return SetElement(index, value, NONE, strict_mode, check_prototype);
-}
-
-
-MaybeObject* JSReceiver::SetElement(uint32_t index,
- Object* value,
- PropertyAttributes attributes,
- StrictModeFlag strict_mode,
- bool check_proto) {
- if (IsJSProxy()) {
- return JSProxy::cast(this)->SetElementWithHandler(
- index, value, strict_mode);
- } else {
- return JSObject::cast(this)->SetElement(
- index, value, attributes, strict_mode, check_proto);
- }
-}
-
-
-Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
- uint32_t index,
- Handle<Object> value,
- StrictModeFlag strict_mode) {
- ASSERT(!object->HasExternalArrayElements());
- CALL_HEAP_FUNCTION(
- object->GetIsolate(),
- object->SetElement(index, *value, NONE, strict_mode, false),
- Object);
-}
-
-
-Handle<Object> JSObject::SetElement(Handle<JSObject> object,
- uint32_t index,
- Handle<Object> value,
- PropertyAttributes attr,
- StrictModeFlag strict_mode,
- SetPropertyMode set_mode) {
- if (object->HasExternalArrayElements()) {
- if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
- bool has_exception;
- Handle<Object> number = Execution::ToNumber(value, &has_exception);
- if (has_exception) return Handle<Object>();
- value = number;
- }
- }
- CALL_HEAP_FUNCTION(
- object->GetIsolate(),
- object->SetElement(index, *value, attr, strict_mode, true, set_mode),
- Object);
+ return SetElement(index, value, strict_mode, check_prototype);
}
MaybeObject* JSObject::SetElement(uint32_t index,
Object* value,
- PropertyAttributes attributes,
StrictModeFlag strict_mode,
- bool check_prototype,
- SetPropertyMode set_mode) {
+ bool check_prototype) {
// Check access rights if needed.
if (IsAccessCheckNeeded()) {
Heap* heap = GetHeap();
@@ -9484,62 +8593,31 @@
ASSERT(proto->IsJSGlobalObject());
return JSObject::cast(proto)->SetElement(index,
value,
- attributes,
strict_mode,
- check_prototype,
- set_mode);
- }
-
- // Don't allow element properties to be redefined for external arrays.
- if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) {
- Isolate* isolate = GetHeap()->isolate();
- Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
- Handle<Object> args[] = { Handle<Object>(this), number };
- Handle<Object> error = isolate->factory()->NewTypeError(
- "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args)));
- return isolate->Throw(*error);
- }
-
- // Normalize the elements to enable attributes on the property.
- if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
- SeededNumberDictionary* dictionary;
- MaybeObject* maybe_object = NormalizeElements();
- if (!maybe_object->To(&dictionary)) return maybe_object;
- // Make sure that we never go back to fast case.
- dictionary->set_requires_slow_elements();
+ check_prototype);
}
// Check for lookup interceptor
if (HasIndexedInterceptor()) {
return SetElementWithInterceptor(index,
value,
- attributes,
strict_mode,
- check_prototype,
- set_mode);
+ check_prototype);
}
return SetElementWithoutInterceptor(index,
value,
- attributes,
strict_mode,
- check_prototype,
- set_mode);
+ check_prototype);
}
MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Object* value,
- PropertyAttributes attr,
StrictModeFlag strict_mode,
- bool check_prototype,
- SetPropertyMode set_mode) {
- ASSERT(HasDictionaryElements() ||
- HasDictionaryArgumentsElements() ||
- (attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
+ bool check_prototype) {
Isolate* isolate = GetIsolate();
switch (GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
return SetFastElement(index, value, strict_mode, check_prototype);
case FAST_DOUBLE_ELEMENTS:
@@ -9584,8 +8662,7 @@
return array->SetValue(index, value);
}
case DICTIONARY_ELEMENTS:
- return SetDictionaryElement(index, value, attr, strict_mode,
- check_prototype, set_mode);
+ return SetDictionaryElement(index, value, strict_mode, check_prototype);
case NON_STRICT_ARGUMENTS_ELEMENTS: {
FixedArray* parameter_map = FixedArray::cast(elements());
uint32_t length = parameter_map->length();
@@ -9596,22 +8673,16 @@
int context_index = Smi::cast(probe)->value();
ASSERT(!context->get(context_index)->IsTheHole());
context->set(context_index, value);
- // Redefining attributes of an aliased element destroys fast aliasing.
- if (set_mode == SET_PROPERTY || attr == NONE) return value;
- parameter_map->set_the_hole(index + 2);
- // For elements that are still writable we re-establish slow aliasing.
- if ((attr & READ_ONLY) == 0) {
- MaybeObject* maybe_entry =
- isolate->heap()->AllocateAliasedArgumentsEntry(context_index);
- if (!maybe_entry->ToObject(&value)) return maybe_entry;
- }
- }
- FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- if (arguments->IsDictionary()) {
- return SetDictionaryElement(index, value, attr, strict_mode,
- check_prototype, set_mode);
+ return value;
} else {
- return SetFastElement(index, value, strict_mode, check_prototype);
+ // Object is not mapped, defer to the arguments.
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ if (arguments->IsDictionary()) {
+ return SetDictionaryElement(index, value, strict_mode,
+ check_prototype);
+ } else {
+ return SetFastElement(index, value, strict_mode, check_prototype);
+ }
}
}
}
@@ -9622,79 +8693,6 @@
}
-Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
- ElementsKind to_kind) {
- CALL_HEAP_FUNCTION(object->GetIsolate(),
- object->TransitionElementsKind(to_kind),
- Object);
-}
-
-
-MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
- ElementsKind from_kind = map()->elements_kind();
-
- Isolate* isolate = GetIsolate();
- if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
- (to_kind == FAST_ELEMENTS ||
- elements() == isolate->heap()->empty_fixed_array())) {
- MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
- Map* new_map;
- if (!maybe_new_map->To(&new_map)) return maybe_new_map;
- set_map(new_map);
- if (FLAG_trace_elements_transitions) {
- FixedArrayBase* elms = FixedArrayBase::cast(elements());
- PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
- }
- return this;
- }
-
- FixedArrayBase* elms = FixedArrayBase::cast(elements());
- uint32_t capacity = static_cast<uint32_t>(elms->length());
- uint32_t length = capacity;
-
- if (IsJSArray()) {
- Object* raw_length = JSArray::cast(this)->length();
- if (raw_length->IsUndefined()) {
- // If length is undefined, then JSArray is being initialized and has no
- // elements, assume a length of zero.
- length = 0;
- } else {
- CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
- }
- }
-
- if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
- to_kind == FAST_DOUBLE_ELEMENTS) {
- MaybeObject* maybe_result =
- SetFastDoubleElementsCapacityAndLength(capacity, length);
- if (maybe_result->IsFailure()) return maybe_result;
- return this;
- }
-
- if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
- MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
- capacity, length, kDontAllowSmiOnlyElements);
- if (maybe_result->IsFailure()) return maybe_result;
- return this;
- }
-
- // This method should never be called for any other case than the ones
- // handled above.
- UNREACHABLE();
- return GetIsolate()->heap()->null_value();
-}
-
-
-// static
-bool Map::IsValidElementsTransition(ElementsKind from_kind,
- ElementsKind to_kind) {
- return
- (from_kind == FAST_SMI_ONLY_ELEMENTS &&
- (to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) ||
- (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS);
-}
-
-
MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
Object* value) {
uint32_t old_len = 0;
@@ -9742,9 +8740,10 @@
Heap* heap = holder_handle->GetHeap();
ElementsAccessor* handler = holder_handle->GetElementsAccessor();
- MaybeObject* raw_result = handler->Get(*this_handle,
+ MaybeObject* raw_result = handler->Get(holder_handle->elements(),
+ index,
*holder_handle,
- index);
+ *this_handle);
if (raw_result != heap->the_hole_value()) return raw_result;
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
@@ -9782,7 +8781,6 @@
break;
}
// Fall through.
- case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS:
backing_store = FixedArray::cast(backing_store_base);
*capacity = backing_store->length();
@@ -9876,26 +8874,18 @@
}
-bool JSObject::ShouldConvertToFastDoubleElements(
- bool* has_smi_only_elements) {
- *has_smi_only_elements = false;
+bool JSObject::CanConvertToFastDoubleElements() {
if (FLAG_unbox_double_arrays) {
ASSERT(HasDictionaryElements());
SeededNumberDictionary* dictionary =
SeededNumberDictionary::cast(elements());
- bool found_double = false;
for (int i = 0; i < dictionary->Capacity(); i++) {
Object* key = dictionary->KeyAt(i);
if (key->IsNumber()) {
- Object* value = dictionary->ValueAt(i);
- if (!value->IsNumber()) return false;
- if (!value->IsSmi()) {
- found_double = true;
- }
+ if (!dictionary->ValueAt(i)->IsNumber()) return false;
}
}
- *has_smi_only_elements = !found_double;
- return found_double;
+ return true;
} else {
return false;
}
@@ -9970,7 +8960,7 @@
String* name,
PropertyAttributes* attributes) {
// Check local property in holder, ignore interceptor.
- LookupResult result(GetIsolate());
+ LookupResult result;
LocalLookupRealNamedProperty(name, &result);
if (result.IsProperty()) {
return GetProperty(receiver, &result, name, attributes);
@@ -9988,7 +8978,7 @@
String* name,
PropertyAttributes* attributes) {
// Check local property in holder, ignore interceptor.
- LookupResult result(GetIsolate());
+ LookupResult result;
LocalLookupRealNamedProperty(name, &result);
if (result.IsProperty()) {
return GetProperty(receiver, &result, name, attributes);
@@ -10039,15 +9029,15 @@
bool JSObject::HasRealNamedProperty(String* key) {
// Check access rights if needed.
- Isolate* isolate = GetIsolate();
if (IsAccessCheckNeeded()) {
- if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
- isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ Heap* heap = GetHeap();
+ if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return false;
}
}
- LookupResult result(isolate);
+ LookupResult result;
LocalLookupRealNamedProperty(key, &result);
return result.IsProperty() && (result.type() != INTERCEPTOR);
}
@@ -10067,7 +9057,6 @@
if (this->IsStringObjectWithCharacterAt(index)) return true;
switch (GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
uint32_t length = IsJSArray() ?
static_cast<uint32_t>(
@@ -10116,24 +9105,39 @@
bool JSObject::HasRealNamedCallbackProperty(String* key) {
// Check access rights if needed.
- Isolate* isolate = GetIsolate();
if (IsAccessCheckNeeded()) {
- if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
- isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
+ Heap* heap = GetHeap();
+ if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
+ heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
return false;
}
}
- LookupResult result(isolate);
+ LookupResult result;
LocalLookupRealNamedProperty(key, &result);
- return result.IsFound() && (result.type() == CALLBACKS);
+ return result.IsProperty() && (result.type() == CALLBACKS);
}
int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
- return HasFastProperties() ?
- map()->NumberOfDescribedProperties(filter) :
- property_dictionary()->NumberOfElementsFilterAttributes(filter);
+ if (HasFastProperties()) {
+ DescriptorArray* descs = map()->instance_descriptors();
+ int result = 0;
+ for (int i = 0; i < descs->number_of_descriptors(); i++) {
+ PropertyDetails details(descs->GetDetails(i));
+ if (details.IsProperty() && (details.attributes() & filter) == 0) {
+ result++;
+ }
+ }
+ return result;
+ } else {
+ return property_dictionary()->NumberOfElementsFilterAttributes(filter);
+ }
+}
+
+
+int JSObject::NumberOfEnumProperties() {
+ return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
}
@@ -10143,8 +9147,8 @@
set(j, temp);
if (this != numbers) {
temp = numbers->get(i);
- numbers->set(i, Smi::cast(numbers->get(j)));
- numbers->set(j, Smi::cast(temp));
+ numbers->set(i, numbers->get(j));
+ numbers->set(j, temp);
}
}
@@ -10254,7 +9258,7 @@
// purpose of this function is to provide reflection information for the object
// mirrors.
void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
- ASSERT(storage->length() >= (NumberOfLocalProperties() - index));
+ ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
if (HasFastProperties()) {
DescriptorArray* descs = map()->instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
@@ -10292,7 +9296,6 @@
PropertyAttributes filter) {
int counter = 0;
switch (GetElementsKind()) {
- case FAST_SMI_ONLY_ELEMENTS:
case FAST_ELEMENTS: {
int length = IsJSArray() ?
Smi::cast(JSArray::cast(this)->length())->value() :
@@ -10459,87 +9462,70 @@
public:
StringSharedKey(String* source,
SharedFunctionInfo* shared,
- LanguageMode language_mode,
- int scope_position)
+ StrictModeFlag strict_mode)
: source_(source),
shared_(shared),
- language_mode_(language_mode),
- scope_position_(scope_position) { }
+ strict_mode_(strict_mode) { }
bool IsMatch(Object* other) {
if (!other->IsFixedArray()) return false;
- FixedArray* other_array = FixedArray::cast(other);
- SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
+ FixedArray* pair = FixedArray::cast(other);
+ SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
if (shared != shared_) return false;
- int language_unchecked = Smi::cast(other_array->get(2))->value();
- ASSERT(language_unchecked == CLASSIC_MODE ||
- language_unchecked == STRICT_MODE ||
- language_unchecked == EXTENDED_MODE);
- LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
- if (language_mode != language_mode_) return false;
- int scope_position = Smi::cast(other_array->get(3))->value();
- if (scope_position != scope_position_) return false;
- String* source = String::cast(other_array->get(1));
+ StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
+ Smi::cast(pair->get(2))->value());
+ if (strict_mode != strict_mode_) return false;
+ String* source = String::cast(pair->get(1));
return source->Equals(source_);
}
static uint32_t StringSharedHashHelper(String* source,
SharedFunctionInfo* shared,
- LanguageMode language_mode,
- int scope_position) {
+ StrictModeFlag strict_mode) {
uint32_t hash = source->Hash();
if (shared->HasSourceCode()) {
// Instead of using the SharedFunctionInfo pointer in the hash
// code computation, we use a combination of the hash of the
- // script source code and the start position of the calling scope.
- // We do this to ensure that the cache entries can survive garbage
+ // script source code and the start and end positions. We do
+ // this to ensure that the cache entries can survive garbage
// collection.
Script* script = Script::cast(shared->script());
hash ^= String::cast(script->source())->Hash();
- if (language_mode == STRICT_MODE) hash ^= 0x8000;
- if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
- hash += scope_position;
+ if (strict_mode == kStrictMode) hash ^= 0x8000;
+ hash += shared->start_position();
}
return hash;
}
uint32_t Hash() {
- return StringSharedHashHelper(
- source_, shared_, language_mode_, scope_position_);
+ return StringSharedHashHelper(source_, shared_, strict_mode_);
}
uint32_t HashForObject(Object* obj) {
- FixedArray* other_array = FixedArray::cast(obj);
- SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
- String* source = String::cast(other_array->get(1));
- int language_unchecked = Smi::cast(other_array->get(2))->value();
- ASSERT(language_unchecked == CLASSIC_MODE ||
- language_unchecked == STRICT_MODE ||
- language_unchecked == EXTENDED_MODE);
- LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
- int scope_position = Smi::cast(other_array->get(3))->value();
- return StringSharedHashHelper(
- source, shared, language_mode, scope_position);
+ FixedArray* pair = FixedArray::cast(obj);
+ SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
+ String* source = String::cast(pair->get(1));
+ StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
+ Smi::cast(pair->get(2))->value());
+ return StringSharedHashHelper(source, shared, strict_mode);
}
MUST_USE_RESULT MaybeObject* AsObject() {
Object* obj;
- { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(4);
+ { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- FixedArray* other_array = FixedArray::cast(obj);
- other_array->set(0, shared_);
- other_array->set(1, source_);
- other_array->set(2, Smi::FromInt(language_mode_));
- other_array->set(3, Smi::FromInt(scope_position_));
- return other_array;
+ FixedArray* pair = FixedArray::cast(obj);
+ pair->set(0, shared_);
+ pair->set(1, source_);
+ pair->set(2, Smi::FromInt(strict_mode_));
+ return pair;
}
private:
String* source_;
SharedFunctionInfo* shared_;
- LanguageMode language_mode_;
- int scope_position_;
+ StrictModeFlag strict_mode_;
};
@@ -10597,7 +9583,7 @@
if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
unibrow::Utf8InputBuffer<> buffer(string_.start(),
static_cast<unsigned>(string_.length()));
- chars_ = buffer.Utf16Length();
+ chars_ = buffer.Length();
hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
uint32_t result = hash_field_ >> String::kHashShift;
ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
@@ -10792,7 +9778,7 @@
// Transform string to symbol if possible.
Map* map = heap->SymbolMapForString(string_);
if (map != NULL) {
- string_->set_map_no_write_barrier(map);
+ string_->set_map(map);
ASSERT(string_->IsSymbol());
return string_;
}
@@ -10853,7 +9839,7 @@
// Optimized for symbol key. Knowledge of the key type allows:
// 1. Move the check if the key is a symbol out of the loop.
- // 2. Avoid comparing hash codes in symbol to symbol comparison.
+ // 2. Avoid comparing hash codes in symbol to symbol comparision.
// 3. Detect a case when a dictionary key is not a symbol but the key is.
// In case of positive result the dictionary key may be replaced by
// the symbol with minimal performance penalty. It gives a chance to
@@ -10871,45 +9857,20 @@
if (element->IsUndefined()) break; // Empty entry.
if (key == element) return entry;
if (!element->IsSymbol() &&
- !element->IsTheHole() &&
+ !element->IsNull() &&
String::cast(element)->Equals(key)) {
// Replace a non-symbol key by the equivalent symbol for faster further
// lookups.
set(index, key);
return entry;
}
- ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key));
+ ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
entry = NextProbe(entry, count++, capacity);
}
return kNotFound;
}
-bool StringDictionary::ContainsTransition(int entry) {
- switch (DetailsAt(entry).type()) {
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- case ELEMENTS_TRANSITION:
- return true;
- case CALLBACKS: {
- Object* value = ValueAt(entry);
- if (!value->IsAccessorPair()) return false;
- AccessorPair* accessors = AccessorPair::cast(value);
- return accessors->getter()->IsMap() || accessors->setter()->IsMap();
- }
- case NORMAL:
- case FIELD:
- case CONSTANT_FUNCTION:
- case HANDLER:
- case INTERCEPTOR:
- case NULL_DESCRIPTOR:
- return false;
- }
- UNREACHABLE(); // Keep the compiler happy.
- return false;
-}
-
-
template<typename Shape, typename Key>
MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
ASSERT(NumberOfElements() < new_table->Capacity());
@@ -11007,7 +9968,7 @@
// EnsureCapacity will guarantee the hash table is never full.
while (true) {
Object* element = KeyAt(entry);
- if (element->IsUndefined() || element->IsTheHole()) break;
+ if (element->IsUndefined() || element->IsNull()) break;
entry = NextProbe(entry, count++, capacity);
}
return entry;
@@ -11022,9 +9983,7 @@
template class HashTable<MapCacheShape, HashTableKey*>;
-template class HashTable<ObjectHashTableShape<1>, Object*>;
-
-template class HashTable<ObjectHashTableShape<2>, Object*>;
+template class HashTable<ObjectHashTableShape, JSObject*>;
template class Dictionary<StringDictionaryShape, String*>;
@@ -11047,9 +10006,6 @@
template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
AtPut(uint32_t, Object*);
-template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
- SlowReverseLookup(Object* value);
-
template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
SlowReverseLookup(Object* value);
@@ -11228,6 +10184,8 @@
// If the object is in dictionary mode, it is converted to fast elements
// mode.
MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
+ ASSERT(!HasExternalArrayElements());
+
Heap* heap = GetHeap();
if (HasDictionaryElements()) {
@@ -11241,8 +10199,7 @@
// Convert to fast elements.
Object* obj;
- { MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
- FAST_ELEMENTS);
+ { MaybeObject* maybe_obj = map()->GetFastElementsMap();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
Map* new_map = Map::cast(obj);
@@ -11258,16 +10215,13 @@
set_map(new_map);
set_elements(fast_elements);
- } else if (HasExternalArrayElements()) {
- // External arrays cannot have holes or undefined elements.
- return Smi::FromInt(ExternalArray::cast(elements())->length());
} else if (!HasFastDoubleElements()) {
Object* obj;
{ MaybeObject* maybe_obj = EnsureWritableFastElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
}
- ASSERT(HasFastTypeElements() || HasFastDoubleElements());
+ ASSERT(HasFastElements() || HasFastDoubleElements());
// Collect holes at the end, undefined before that and the rest at the
// start, and return the number of non-hole, non-undefined values.
@@ -11489,7 +10443,7 @@
MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
- float cast_value = static_cast<float>(OS::nan_value());
+ float cast_value = 0;
Heap* heap = GetHeap();
if (index < static_cast<uint32_t>(length())) {
if (value->IsSmi()) {
@@ -11499,7 +10453,7 @@
double double_value = HeapNumber::cast(value)->value();
cast_value = static_cast<float>(double_value);
} else {
- // Clamp undefined to NaN (default). All other types have been
+ // Clamp undefined to zero (default). All other types have been
// converted to a number type further up in the call chain.
ASSERT(value->IsUndefined());
}
@@ -11510,7 +10464,7 @@
MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
- double double_value = OS::nan_value();
+ double double_value = 0;
Heap* heap = GetHeap();
if (index < static_cast<uint32_t>(length())) {
if (value->IsSmi()) {
@@ -11519,7 +10473,7 @@
} else if (value->IsHeapNumber()) {
double_value = HeapNumber::cast(value)->value();
} else {
- // Clamp undefined to NaN (default). All other types have been
+ // Clamp undefined to zero (default). All other types have been
// converted to a number type further up in the call chain.
ASSERT(value->IsUndefined());
}
@@ -11536,16 +10490,6 @@
}
-Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
- Handle<GlobalObject> global,
- Handle<String> name) {
- Isolate* isolate = global->GetIsolate();
- CALL_HEAP_FUNCTION(isolate,
- global->EnsurePropertyCell(*name),
- JSGlobalPropertyCell);
-}
-
-
MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
ASSERT(!HasFastProperties());
int entry = property_dictionary()->FindEntry(name);
@@ -11747,12 +10691,8 @@
Object* CompilationCacheTable::LookupEval(String* src,
Context* context,
- LanguageMode language_mode,
- int scope_position) {
- StringSharedKey key(src,
- context->closure()->shared(),
- language_mode,
- scope_position);
+ StrictModeFlag strict_mode) {
+ StringSharedKey key(src, context->closure()->shared(), strict_mode);
int entry = FindEntry(&key);
if (entry == kNotFound) return GetHeap()->undefined_value();
return get(EntryToIndex(entry) + 1);
@@ -11787,12 +10727,10 @@
MaybeObject* CompilationCacheTable::PutEval(String* src,
Context* context,
- SharedFunctionInfo* value,
- int scope_position) {
+ SharedFunctionInfo* value) {
StringSharedKey key(src,
context->closure()->shared(),
- value->language_mode(),
- scope_position);
+ value->strict_mode() ? kStrictMode : kNonStrictMode);
Object* obj;
{ MaybeObject* maybe_obj = EnsureCapacity(1, &key);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
@@ -11836,13 +10774,13 @@
void CompilationCacheTable::Remove(Object* value) {
- Object* the_hole_value = GetHeap()->the_hole_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) {
- NoWriteBarrierSet(this, entry_index, the_hole_value);
- NoWriteBarrierSet(this, value_index, the_hole_value);
+ fast_set(this, entry_index, null_value);
+ fast_set(this, value_index, null_value);
ElementRemoved();
}
}
@@ -11995,6 +10933,30 @@
}
+void SeededNumberDictionary::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();
+ 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());
+ if (from <= number && number < to) {
+ SetEntry(i, sentinel, sentinel);
+ removed_entries++;
+ }
+ }
+ }
+
+ // Update the number of elements.
+ ElementsRemoved(removed_entries);
+}
+
+
template<typename Shape, typename Key>
Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
JSReceiver::DeleteMode mode) {
@@ -12004,7 +10966,7 @@
if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
return heap->false_value();
}
- SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
+ SetEntry(entry, heap->null_value(), heap->null_value());
HashTable<Shape, Key>::ElementRemoved();
return heap->true_value();
}
@@ -12136,27 +11098,6 @@
}
-Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
- Handle<SeededNumberDictionary> dictionary,
- uint32_t index,
- Handle<Object> value,
- PropertyDetails details) {
- CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
- dictionary->Set(index, *value, details),
- SeededNumberDictionary);
-}
-
-
-Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
- Handle<UnseededNumberDictionary> dictionary,
- uint32_t index,
- Handle<Object> value) {
- CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
- dictionary->Set(index, *value),
- UnseededNumberDictionary);
-}
-
-
MaybeObject* SeededNumberDictionary::Set(uint32_t key,
Object* value,
PropertyDetails details) {
@@ -12338,15 +11279,14 @@
}
// Allocate the instance descriptor.
- DescriptorArray* descriptors;
- { MaybeObject* maybe_descriptors =
+ Object* descriptors_unchecked;
+ { MaybeObject* maybe_descriptors_unchecked =
DescriptorArray::Allocate(instance_descriptor_length);
- if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) {
- return maybe_descriptors;
+ if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
+ return maybe_descriptors_unchecked;
}
}
-
- DescriptorArray::WhitenessWitness witness(descriptors);
+ DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
int inobject_props = obj->map()->inobject_properties();
int number_of_allocated_fields =
@@ -12384,7 +11324,7 @@
JSFunction::cast(value),
details.attributes(),
details.index());
- descriptors->Set(next_descriptor++, &d, witness);
+ descriptors->Set(next_descriptor++, &d);
} else if (type == NORMAL) {
if (current_offset < inobject_props) {
obj->InObjectPropertyAtPut(current_offset,
@@ -12398,18 +11338,13 @@
current_offset++,
details.attributes(),
details.index());
- descriptors->Set(next_descriptor++, &d, witness);
+ descriptors->Set(next_descriptor++, &d);
} else if (type == CALLBACKS) {
- if (value->IsAccessorPair()) {
- MaybeObject* maybe_copy =
- AccessorPair::cast(value)->CopyWithoutTransitions();
- if (!maybe_copy->To(&value)) return maybe_copy;
- }
CallbacksDescriptor d(String::cast(key),
value,
details.attributes(),
details.index());
- descriptors->Set(next_descriptor++, &d, witness);
+ descriptors->Set(next_descriptor++, &d);
} else {
UNREACHABLE();
}
@@ -12417,7 +11352,7 @@
}
ASSERT(current_offset == number_of_fields);
- descriptors->Sort(witness);
+ descriptors->Sort();
// Allocate new map.
Object* new_map;
{ MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
@@ -12440,84 +11375,20 @@
}
-bool ObjectHashSet::Contains(Object* key) {
- ASSERT(IsKey(key));
-
+Object* ObjectHashTable::Lookup(JSObject* key) {
// If the object does not have an identity hash, it was never used as a key.
- { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
- if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
- }
- return (FindEntry(key) != kNotFound);
-}
-
-
-MaybeObject* ObjectHashSet::Add(Object* key) {
- ASSERT(IsKey(key));
-
- // Make sure the key object has an identity hash code.
- int hash;
- { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
- if (maybe_hash->IsFailure()) return maybe_hash;
- hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
- }
- int entry = FindEntry(key);
-
- // Check whether key is already present.
- if (entry != kNotFound) return this;
-
- // Check whether the hash set should be extended and add entry.
- Object* obj;
- { MaybeObject* maybe_obj = EnsureCapacity(1, key);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
- ObjectHashSet* table = ObjectHashSet::cast(obj);
- entry = table->FindInsertionEntry(hash);
- table->set(EntryToIndex(entry), key);
- table->ElementAdded();
- return table;
-}
-
-
-MaybeObject* ObjectHashSet::Remove(Object* key) {
- ASSERT(IsKey(key));
-
- // If the object does not have an identity hash, it was never used as a key.
- { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
- if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
- }
- int entry = FindEntry(key);
-
- // Check whether key is actually present.
- if (entry == kNotFound) return this;
-
- // Remove entry and try to shrink this hash set.
- set_the_hole(EntryToIndex(entry));
- ElementRemoved();
- return Shrink(key);
-}
-
-
-Object* ObjectHashTable::Lookup(Object* key) {
- ASSERT(IsKey(key));
-
- // If the object does not have an identity hash, it was never used as a key.
- { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
- if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
- return GetHeap()->undefined_value();
- }
- }
+ MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::OMIT_CREATION);
+ if (maybe_hash->IsFailure()) return GetHeap()->undefined_value();
int entry = FindEntry(key);
if (entry == kNotFound) return GetHeap()->undefined_value();
return get(EntryToIndex(entry) + 1);
}
-MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
- ASSERT(IsKey(key));
-
+MaybeObject* ObjectHashTable::Put(JSObject* key, Object* value) {
// Make sure the key object has an identity hash code.
int hash;
- { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
+ { MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::ALLOW_CREATION);
if (maybe_hash->IsFailure()) return maybe_hash;
hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
}
@@ -12547,16 +11418,16 @@
}
-void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
+void ObjectHashTable::AddEntry(int entry, JSObject* key, Object* value) {
set(EntryToIndex(entry), key);
set(EntryToIndex(entry) + 1, value);
ElementAdded();
}
-void ObjectHashTable::RemoveEntry(int entry) {
- set_the_hole(EntryToIndex(entry));
- set_the_hole(EntryToIndex(entry) + 1);
+void ObjectHashTable::RemoveEntry(int entry, Heap* heap) {
+ set_null(heap, EntryToIndex(entry));
+ set_null(heap, EntryToIndex(entry) + 1);
ElementRemoved();
}
@@ -12811,136 +11682,7 @@
// Multiple break points.
return FixedArray::cast(break_point_objects())->length();
}
-#endif // ENABLE_DEBUGGER_SUPPORT
+#endif
-MaybeObject* JSDate::GetField(Object* object, Smi* index) {
- return JSDate::cast(object)->DoGetField(
- static_cast<FieldIndex>(index->value()));
-}
-
-
-Object* JSDate::DoGetField(FieldIndex index) {
- ASSERT(index != kDateValue);
-
- DateCache* date_cache = GetIsolate()->date_cache();
-
- if (index < kFirstUncachedField) {
- Object* stamp = cache_stamp();
- if (stamp != date_cache->stamp() && stamp->IsSmi()) {
- // Since the stamp is not NaN, the value is also not NaN.
- int64_t local_time_ms =
- date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
- SetLocalFields(local_time_ms, date_cache);
- }
- switch (index) {
- case kYear: return year();
- case kMonth: return month();
- case kDay: return day();
- case kWeekday: return weekday();
- case kHour: return hour();
- case kMinute: return min();
- case kSecond: return sec();
- default: UNREACHABLE();
- }
- }
-
- if (index >= kFirstUTCField) {
- return GetUTCField(index, value()->Number(), date_cache);
- }
-
- double time = value()->Number();
- if (isnan(time)) return GetIsolate()->heap()->nan_value();
-
- int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
- int days = DateCache::DaysFromTime(local_time_ms);
-
- if (index == kDays) return Smi::FromInt(days);
-
- int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
- if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
- ASSERT(index == kTimeInDay);
- return Smi::FromInt(time_in_day_ms);
-}
-
-
-Object* JSDate::GetUTCField(FieldIndex index,
- double value,
- DateCache* date_cache) {
- ASSERT(index >= kFirstUTCField);
-
- if (isnan(value)) return GetIsolate()->heap()->nan_value();
-
- int64_t time_ms = static_cast<int64_t>(value);
-
- if (index == kTimezoneOffset) {
- return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
- }
-
- int days = DateCache::DaysFromTime(time_ms);
-
- if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
-
- if (index <= kDayUTC) {
- int year, month, day;
- date_cache->YearMonthDayFromDays(days, &year, &month, &day);
- if (index == kYearUTC) return Smi::FromInt(year);
- if (index == kMonthUTC) return Smi::FromInt(month);
- ASSERT(index == kDayUTC);
- return Smi::FromInt(day);
- }
-
- int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
- switch (index) {
- case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
- case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
- case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
- case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
- case kDaysUTC: return Smi::FromInt(days);
- case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
- default: UNREACHABLE();
- }
-
- UNREACHABLE();
- return NULL;
-}
-
-
-void JSDate::SetValue(Object* value, bool is_value_nan) {
- set_value(value);
- if (is_value_nan) {
- HeapNumber* nan = GetIsolate()->heap()->nan_value();
- set_cache_stamp(nan, SKIP_WRITE_BARRIER);
- set_year(nan, SKIP_WRITE_BARRIER);
- set_month(nan, SKIP_WRITE_BARRIER);
- set_day(nan, SKIP_WRITE_BARRIER);
- set_hour(nan, SKIP_WRITE_BARRIER);
- set_min(nan, SKIP_WRITE_BARRIER);
- set_sec(nan, SKIP_WRITE_BARRIER);
- set_weekday(nan, SKIP_WRITE_BARRIER);
- } else {
- set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
- }
-}
-
-
-void JSDate::SetLocalFields(int64_t local_time_ms, DateCache* date_cache) {
- int days = DateCache::DaysFromTime(local_time_ms);
- int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
- int year, month, day;
- date_cache->YearMonthDayFromDays(days, &year, &month, &day);
- int weekday = date_cache->Weekday(days);
- int hour = time_in_day_ms / (60 * 60 * 1000);
- int min = (time_in_day_ms / (60 * 1000)) % 60;
- int sec = (time_in_day_ms / 1000) % 60;
- set_cache_stamp(date_cache->stamp());
- set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
- set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
- set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
- set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
- set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
- set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
- set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
-}
-
} } // namespace v8::internal