| Index: src/objects.cc
|
| ===================================================================
|
| --- src/objects.cc (revision 6941)
|
| +++ src/objects.cc (working copy)
|
| @@ -1863,9 +1863,10 @@
|
| // We only need to deal with CALLBACKS and INTERCEPTORS
|
| MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
|
| String* name,
|
| - Object* value) {
|
| + Object* value,
|
| + bool check_prototype) {
|
| Heap* heap = GetHeap();
|
| - if (!result->IsProperty()) {
|
| + if (check_prototype && !result->IsProperty()) {
|
| LookupCallbackSetterInPrototypes(name, result);
|
| }
|
|
|
| @@ -1891,7 +1892,8 @@
|
| LookupResult r;
|
| LookupRealNamedProperty(name, &r);
|
| if (r.IsProperty()) {
|
| - return SetPropertyWithFailedAccessCheck(&r, name, value);
|
| + return SetPropertyWithFailedAccessCheck(&r, name, value,
|
| + check_prototype);
|
| }
|
| break;
|
| }
|
| @@ -1933,7 +1935,7 @@
|
| // Check access rights if needed.
|
| if (IsAccessCheckNeeded()
|
| && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
|
| - return SetPropertyWithFailedAccessCheck(result, name, value);
|
| + return SetPropertyWithFailedAccessCheck(result, name, value, true);
|
| }
|
|
|
| if (IsJSGlobalProxy()) {
|
| @@ -2023,7 +2025,7 @@
|
| // callback setter removed. The two lines looking up the LookupResult
|
| // result are also added. If one of the functions is changed, the other
|
| // should be.
|
| -MaybeObject* JSObject::IgnoreAttributesAndSetLocalProperty(
|
| +MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
| String* name,
|
| Object* value,
|
| PropertyAttributes attributes) {
|
| @@ -2037,14 +2039,14 @@
|
| // Check access rights if needed.
|
| if (IsAccessCheckNeeded()
|
| && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
|
| - return SetPropertyWithFailedAccessCheck(&result, name, value);
|
| + return SetPropertyWithFailedAccessCheck(&result, name, value, false);
|
| }
|
|
|
| if (IsJSGlobalProxy()) {
|
| Object* proto = GetPrototype();
|
| if (proto->IsNull()) return value;
|
| ASSERT(proto->IsJSGlobalObject());
|
| - return JSObject::cast(proto)->IgnoreAttributesAndSetLocalProperty(
|
| + return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
|
| name,
|
| value,
|
| attributes);
|
| @@ -2999,7 +3001,6 @@
|
|
|
| uint32_t index = 0;
|
| bool is_element = name->AsArrayIndex(&index);
|
| - if (is_element && IsJSArray()) return heap->undefined_value();
|
|
|
| if (is_element) {
|
| switch (GetElementsKind()) {
|
| @@ -5234,6 +5235,26 @@
|
| }
|
|
|
|
|
| +bool String::IsAsciiEqualTo(Vector<const char> str) {
|
| + int slen = length();
|
| + if (str.length() != slen) return false;
|
| + for (int i = 0; i < slen; i++) {
|
| + if (Get(i) != static_cast<uint16_t>(str[i])) return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +
|
| +bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
|
| + int slen = length();
|
| + if (str.length() != slen) return false;
|
| + for (int i = 0; i < slen; i++) {
|
| + if (Get(i) != str[i]) return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +
|
| template <typename schar>
|
| static inline uint32_t HashSequentialString(const schar* chars, int length) {
|
| StringHasher hasher(length);
|
| @@ -6074,14 +6095,9 @@
|
| }
|
|
|
|
|
| -uint8_t* Code::GetSafepointEntry(Address pc) {
|
| +SafepointEntry Code::GetSafepointEntry(Address pc) {
|
| SafepointTable table(this);
|
| - unsigned pc_offset = static_cast<unsigned>(pc - instruction_start());
|
| - for (unsigned i = 0; i < table.length(); i++) {
|
| - // TODO(kasperl): Replace the linear search with binary search.
|
| - if (table.GetPcOffset(i) == pc_offset) return table.GetEntry(i);
|
| - }
|
| - return NULL;
|
| + return table.FindEntry(pc);
|
| }
|
|
|
|
|
| @@ -6352,12 +6368,15 @@
|
| PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
|
| table.PrintEntry(i);
|
| PrintF(out, " (sp -> fp)");
|
| - int deoptimization_index = table.GetDeoptimizationIndex(i);
|
| - if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
|
| - PrintF(out, " %6d", deoptimization_index);
|
| + SafepointEntry entry = table.GetEntry(i);
|
| + if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
|
| + PrintF(out, " %6d", entry.deoptimization_index());
|
| } else {
|
| PrintF(out, " <none>");
|
| }
|
| + if (entry.argument_count() > 0) {
|
| + PrintF(out, " argc: %d", entry.argument_count());
|
| + }
|
| PrintF(out, "\n");
|
| }
|
| PrintF(out, "\n");
|
| @@ -6893,7 +6912,8 @@
|
|
|
|
|
| MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
|
| - Object* value) {
|
| + Object* value,
|
| + bool check_prototype) {
|
| Isolate* isolate = GetIsolate();
|
| // Make sure that the top context does not change when doing
|
| // callbacks or interceptor calls.
|
| @@ -6918,7 +6938,9 @@
|
| if (!result.IsEmpty()) return *value_handle;
|
| }
|
| MaybeObject* raw_result =
|
| - this_handle->SetElementWithoutInterceptor(index, *value_handle);
|
| + this_handle->SetElementWithoutInterceptor(index,
|
| + *value_handle,
|
| + check_prototype);
|
| RETURN_IF_SCHEDULED_EXCEPTION(isolate);
|
| return raw_result;
|
| }
|
| @@ -7032,7 +7054,9 @@
|
| // Adding n elements in fast case is O(n*n).
|
| // Note: revisit design to have dual undefined values to capture absent
|
| // elements.
|
| -MaybeObject* JSObject::SetFastElement(uint32_t index, Object* value) {
|
| +MaybeObject* JSObject::SetFastElement(uint32_t index,
|
| + Object* value,
|
| + bool check_prototype) {
|
| ASSERT(HasFastElements());
|
|
|
| Object* elms_obj;
|
| @@ -7042,12 +7066,13 @@
|
| FixedArray* elms = FixedArray::cast(elms_obj);
|
| uint32_t elms_length = static_cast<uint32_t>(elms->length());
|
|
|
| - if (!IsJSArray() && (index >= elms_length || elms->get(index)->IsTheHole())) {
|
| - if (SetElementWithCallbackSetterInPrototypes(index, value)) {
|
| - return value;
|
| - }
|
| + if (check_prototype &&
|
| + (index >= elms_length || elms->get(index)->IsTheHole()) &&
|
| + SetElementWithCallbackSetterInPrototypes(index, value)) {
|
| + return value;
|
| }
|
|
|
| +
|
| // Check whether there is extra space in fixed array..
|
| if (index < elms_length) {
|
| elms->set(index, value);
|
| @@ -7085,11 +7110,13 @@
|
| if (!maybe_obj->ToObject(&obj)) return maybe_obj;
|
| }
|
| ASSERT(HasDictionaryElements());
|
| - return SetElement(index, value);
|
| + return SetElement(index, value, check_prototype);
|
| }
|
|
|
|
|
| -MaybeObject* JSObject::SetElement(uint32_t index, Object* value) {
|
| +MaybeObject* JSObject::SetElement(uint32_t index,
|
| + Object* value,
|
| + bool check_prototype) {
|
| Heap* heap = GetHeap();
|
| // Check access rights if needed.
|
| if (IsAccessCheckNeeded() &&
|
| @@ -7104,25 +7131,26 @@
|
| Object* proto = GetPrototype();
|
| if (proto->IsNull()) return value;
|
| ASSERT(proto->IsJSGlobalObject());
|
| - return JSObject::cast(proto)->SetElement(index, value);
|
| + return JSObject::cast(proto)->SetElement(index, value, check_prototype);
|
| }
|
|
|
| // Check for lookup interceptor
|
| if (HasIndexedInterceptor()) {
|
| - return SetElementWithInterceptor(index, value);
|
| + return SetElementWithInterceptor(index, value, check_prototype);
|
| }
|
|
|
| - return SetElementWithoutInterceptor(index, value);
|
| + return SetElementWithoutInterceptor(index, value, check_prototype);
|
| }
|
|
|
|
|
| MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
|
| - Object* value) {
|
| + Object* value,
|
| + bool check_prototype) {
|
| Heap* heap = GetHeap();
|
| switch (GetElementsKind()) {
|
| case FAST_ELEMENTS:
|
| // Fast case.
|
| - return SetFastElement(index, value);
|
| + return SetFastElement(index, value, check_prototype);
|
| case PIXEL_ELEMENTS: {
|
| PixelArray* pixels = PixelArray::cast(elements());
|
| return pixels->SetValue(index, value);
|
| @@ -7175,10 +7203,9 @@
|
| }
|
| } else {
|
| // Index not already used. Look for an accessor in the prototype chain.
|
| - if (!IsJSArray()) {
|
| - if (SetElementWithCallbackSetterInPrototypes(index, value)) {
|
| - return value;
|
| - }
|
| + if (check_prototype &&
|
| + SetElementWithCallbackSetterInPrototypes(index, value)) {
|
| + return value;
|
| }
|
| // When we set the is_extensible flag to false we always force
|
| // the element into dictionary mode (and force them to stay there).
|
| @@ -8176,6 +8203,85 @@
|
| };
|
|
|
|
|
| +template <typename Char>
|
| +class SequentialSymbolKey : public HashTableKey {
|
| + public:
|
| + explicit SequentialSymbolKey(Vector<const Char> string)
|
| + : string_(string), hash_field_(0) { }
|
| +
|
| + uint32_t Hash() {
|
| + StringHasher hasher(string_.length());
|
| +
|
| + // Very long strings have a trivial hash that doesn't inspect the
|
| + // string contents.
|
| + if (hasher.has_trivial_hash()) {
|
| + hash_field_ = hasher.GetHashField();
|
| + } else {
|
| + int i = 0;
|
| + // Do the iterative array index computation as long as there is a
|
| + // chance this is an array index.
|
| + while (i < string_.length() && hasher.is_array_index()) {
|
| + hasher.AddCharacter(static_cast<uc32>(string_[i]));
|
| + i++;
|
| + }
|
| +
|
| + // Process the remaining characters without updating the array
|
| + // index.
|
| + while (i < string_.length()) {
|
| + hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
|
| + i++;
|
| + }
|
| + hash_field_ = hasher.GetHashField();
|
| + }
|
| +
|
| + uint32_t result = hash_field_ >> String::kHashShift;
|
| + ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
|
| + return result;
|
| + }
|
| +
|
| +
|
| + uint32_t HashForObject(Object* other) {
|
| + return String::cast(other)->Hash();
|
| + }
|
| +
|
| + Vector<const Char> string_;
|
| + uint32_t hash_field_;
|
| +};
|
| +
|
| +
|
| +
|
| +class AsciiSymbolKey : public SequentialSymbolKey<char> {
|
| + public:
|
| + explicit AsciiSymbolKey(Vector<const char> str)
|
| + : SequentialSymbolKey<char>(str) { }
|
| +
|
| + bool IsMatch(Object* string) {
|
| + return String::cast(string)->IsAsciiEqualTo(string_);
|
| + }
|
| +
|
| + MaybeObject* AsObject() {
|
| + if (hash_field_ == 0) Hash();
|
| + return HEAP->AllocateAsciiSymbol(string_, hash_field_);
|
| + }
|
| +};
|
| +
|
| +
|
| +class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
|
| + public:
|
| + explicit TwoByteSymbolKey(Vector<const uc16> str)
|
| + : SequentialSymbolKey<uc16>(str) { }
|
| +
|
| + bool IsMatch(Object* string) {
|
| + return String::cast(string)->IsTwoByteEqualTo(string_);
|
| + }
|
| +
|
| + MaybeObject* AsObject() {
|
| + if (hash_field_ == 0) Hash();
|
| + return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
|
| + }
|
| +};
|
| +
|
| +
|
| // SymbolKey carries a string/symbol object as key.
|
| class SymbolKey : public HashTableKey {
|
| public:
|
| @@ -8912,6 +9018,19 @@
|
| }
|
|
|
|
|
| +MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
|
| + Object** s) {
|
| + AsciiSymbolKey key(str);
|
| + return LookupKey(&key, s);
|
| +}
|
| +
|
| +
|
| +MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
|
| + Object** s) {
|
| + TwoByteSymbolKey key(str);
|
| + return LookupKey(&key, s);
|
| +}
|
| +
|
| MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
|
| int entry = FindEntry(key);
|
|
|
|
|