handle the special snowflakes that are Integer Indexed Exotic objects
the implementation doesn't yet throw on strict mode assignment BUG= Review URL: https://codereview.chromium.org/992913002 Cr-Commit-Position: refs/heads/master@{#27121}
This commit is contained in:
parent
fd012f1080
commit
040225a315
@ -9,6 +9,7 @@
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/assert-scope.h"
|
||||
#include "src/char-predicates-inl.h"
|
||||
#include "src/conversions-inl.h"
|
||||
#include "src/conversions.h"
|
||||
#include "src/dtoa.h"
|
||||
@ -502,4 +503,54 @@ double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
|
||||
}
|
||||
|
||||
|
||||
bool IsNonArrayIndexInteger(String* string) {
|
||||
const int kBufferSize = 64;
|
||||
const int kUint32MaxChars = 11;
|
||||
uint16_t buffer[kBufferSize];
|
||||
int offset = 0;
|
||||
const int length = string->length();
|
||||
DCHECK_NE(0, length);
|
||||
// First iteration, check for minus, 0 followed by anything else, etc.
|
||||
int to = std::min(offset + kUint32MaxChars, length);
|
||||
{
|
||||
String::WriteToFlat(string, buffer, offset, to);
|
||||
bool negative = false;
|
||||
if (buffer[offset] == '-') {
|
||||
negative = true;
|
||||
++offset;
|
||||
if (offset == to) return false; // Just '-' is bad.
|
||||
}
|
||||
if (buffer[offset] == '0') {
|
||||
return to == 2 && negative; // Match just '-0'.
|
||||
}
|
||||
// Process positive integers.
|
||||
if (!negative) {
|
||||
uint64_t acc = 0;
|
||||
for (; offset < to; ++offset) {
|
||||
uint64_t digit = buffer[offset] - '0';
|
||||
if (digit > 9) return false;
|
||||
acc = 10 * acc + digit;
|
||||
}
|
||||
// String is consumed. Evaluate what we have.
|
||||
if (offset == length) {
|
||||
return acc >
|
||||
static_cast<uint64_t>(std::numeric_limits<uint32_t>::max());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Consume rest of string. If we get here, we're way out of uint32_t bounds
|
||||
// or negative.
|
||||
int i = offset;
|
||||
while (true) {
|
||||
for (; offset < to; ++offset, ++i) {
|
||||
if (!IsDecimalDigit(buffer[i])) return false;
|
||||
}
|
||||
if (offset == length) break;
|
||||
// Read next chunk.
|
||||
to = std::min(offset + kBufferSize, length);
|
||||
String::WriteToFlat(string, buffer, offset, to);
|
||||
i = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} } // namespace v8::internal
|
||||
|
@ -236,6 +236,8 @@ inline size_t NumberToSize(Isolate* isolate,
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool IsNonArrayIndexInteger(String* string);
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_CONVERSIONS_H_
|
||||
|
@ -5266,6 +5266,7 @@ HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it,
|
||||
case LookupIterator::ACCESSOR:
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
return kUseGeneric;
|
||||
case LookupIterator::DATA:
|
||||
@ -6071,6 +6072,12 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
|
||||
}
|
||||
|
||||
|
||||
bool HOptimizedGraphBuilder::PropertyAccessInfo::IsIntegerIndexedExotic() {
|
||||
InstanceType instance_type = map_->instance_type();
|
||||
return instance_type == JS_TYPED_ARRAY_TYPE && IsNonArrayIndexInteger(*name_);
|
||||
}
|
||||
|
||||
|
||||
bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
|
||||
if (!CanInlinePropertyAccess(map_)) return false;
|
||||
if (IsJSObjectFieldAccessor()) return IsLoad();
|
||||
@ -6080,6 +6087,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
|
||||
}
|
||||
if (!LookupDescriptor()) return false;
|
||||
if (IsFound()) return IsLoad() || !IsReadOnly();
|
||||
if (IsIntegerIndexedExotic()) return false;
|
||||
if (!LookupInPrototypes()) return false;
|
||||
if (IsLoad()) return true;
|
||||
|
||||
|
@ -2641,6 +2641,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
void LoadFieldMaps(Handle<Map> map);
|
||||
bool LookupDescriptor();
|
||||
bool LookupInPrototypes();
|
||||
bool IsIntegerIndexedExotic();
|
||||
bool IsCompatible(PropertyAccessInfo* other);
|
||||
|
||||
void GeneralizeRepresentation(Representation r) {
|
||||
|
@ -280,6 +280,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
break;
|
||||
case LookupIterator::DATA:
|
||||
inline_followup =
|
||||
@ -346,6 +347,7 @@ void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
case LookupIterator::TRANSITION:
|
||||
UNREACHABLE();
|
||||
case LookupIterator::DATA: {
|
||||
|
@ -262,6 +262,7 @@ static void LookupForRead(LookupIterator* it) {
|
||||
}
|
||||
return;
|
||||
case LookupIterator::ACCESSOR:
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
case LookupIterator::DATA:
|
||||
return;
|
||||
}
|
||||
@ -1316,6 +1317,8 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
||||
lookup->GetConstantIndex());
|
||||
}
|
||||
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
return slow_stub();
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
@ -1506,6 +1509,8 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
|
||||
break;
|
||||
case LookupIterator::ACCESSOR:
|
||||
return !it->IsReadOnly();
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
return false;
|
||||
case LookupIterator::DATA: {
|
||||
if (it->IsReadOnly()) return false;
|
||||
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
||||
@ -1530,7 +1535,6 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
|
||||
}
|
||||
}
|
||||
|
||||
if (it->IsSpecialNumericIndex()) return false;
|
||||
it->PrepareTransitionToDataProperty(value, NONE, store_mode);
|
||||
return it->IsCacheableTransition();
|
||||
}
|
||||
@ -1835,6 +1839,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
||||
break;
|
||||
}
|
||||
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
|
@ -44,6 +44,10 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* map,
|
||||
}
|
||||
// Fall through.
|
||||
case ACCESS_CHECK:
|
||||
if (exotic_index_state_ != ExoticIndexState::kNoIndex &&
|
||||
IsIntegerIndexedExotic(holder)) {
|
||||
return INTEGER_INDEXED_EXOTIC;
|
||||
}
|
||||
if (check_interceptor() && map->has_named_interceptor()) {
|
||||
return INTERCEPTOR;
|
||||
}
|
||||
@ -75,6 +79,7 @@ LookupIterator::State LookupIterator::LookupInHolder(Map* map,
|
||||
case ACCESSOR:
|
||||
case DATA:
|
||||
return NOT_FOUND;
|
||||
case INTEGER_INDEXED_EXOTIC:
|
||||
case JSPROXY:
|
||||
case TRANSITION:
|
||||
UNREACHABLE();
|
||||
|
@ -120,9 +120,9 @@ void LookupIterator::PrepareTransitionToDataProperty(
|
||||
Handle<Object> value, PropertyAttributes attributes,
|
||||
Object::StoreFromKeyed store_mode) {
|
||||
if (state_ == TRANSITION) return;
|
||||
DCHECK(state_ != LookupIterator::ACCESSOR);
|
||||
DCHECK_NE(LookupIterator::ACCESSOR, state_);
|
||||
DCHECK_NE(LookupIterator::INTEGER_INDEXED_EXOTIC, state_);
|
||||
DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype());
|
||||
DCHECK(!IsSpecialNumericIndex());
|
||||
// Can only be called when the receiver is a JSObject. JSProxy has to be
|
||||
// handled via a trap. Adding properties to primitive values is not
|
||||
// observable.
|
||||
@ -333,25 +333,23 @@ Handle<Object> LookupIterator::WriteDataValue(Handle<Object> value) {
|
||||
}
|
||||
|
||||
|
||||
bool LookupIterator::IsSpecialNumericIndex() const {
|
||||
if (GetStoreTarget()->IsJSTypedArray() && name()->IsString()) {
|
||||
bool LookupIterator::IsIntegerIndexedExotic(JSReceiver* holder) {
|
||||
DCHECK(exotic_index_state_ != ExoticIndexState::kNoIndex);
|
||||
// Currently typed arrays are the only such objects.
|
||||
if (!holder->IsJSTypedArray()) return false;
|
||||
if (exotic_index_state_ == ExoticIndexState::kIndex) return true;
|
||||
DCHECK(exotic_index_state_ == ExoticIndexState::kUninitialized);
|
||||
bool result = false;
|
||||
// Compute and cache result.
|
||||
if (name()->IsString()) {
|
||||
Handle<String> name_string = Handle<String>::cast(name());
|
||||
if (name_string->length() > 0) {
|
||||
double d =
|
||||
StringToDouble(isolate()->unicode_cache(), name_string, NO_FLAGS);
|
||||
if (!std::isnan(d)) {
|
||||
if (String::Equals(isolate()->factory()->minus_zero_string(),
|
||||
name_string))
|
||||
return true;
|
||||
|
||||
Factory* factory = isolate()->factory();
|
||||
Handle<Object> num = factory->NewNumber(d);
|
||||
Handle<String> roundtrip_string = factory->NumberToString(num);
|
||||
if (String::Equals(name_string, roundtrip_string)) return true;
|
||||
}
|
||||
if (name_string->length() != 0) {
|
||||
result = IsNonArrayIndexInteger(*name_string);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
exotic_index_state_ =
|
||||
result ? ExoticIndexState::kIndex : ExoticIndexState::kNoIndex;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
12
src/lookup.h
12
src/lookup.h
@ -31,6 +31,7 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
|
||||
enum State {
|
||||
ACCESS_CHECK,
|
||||
INTEGER_INDEXED_EXOTIC,
|
||||
INTERCEPTOR,
|
||||
JSPROXY,
|
||||
NOT_FOUND,
|
||||
@ -46,6 +47,7 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
Configuration configuration = PROTOTYPE_CHAIN)
|
||||
: configuration_(ComputeConfiguration(configuration, name)),
|
||||
state_(NOT_FOUND),
|
||||
exotic_index_state_(ExoticIndexState::kUninitialized),
|
||||
property_details_(NONE, v8::internal::DATA, 0),
|
||||
isolate_(name->GetIsolate()),
|
||||
name_(name),
|
||||
@ -61,6 +63,7 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
Configuration configuration = PROTOTYPE_CHAIN)
|
||||
: configuration_(ComputeConfiguration(configuration, name)),
|
||||
state_(NOT_FOUND),
|
||||
exotic_index_state_(ExoticIndexState::kUninitialized),
|
||||
property_details_(NONE, v8::internal::DATA, 0),
|
||||
isolate_(name->GetIsolate()),
|
||||
name_(name),
|
||||
@ -140,11 +143,6 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
// Usually returns the value that was passed in, but may perform
|
||||
// non-observable modifications on it, such as internalize strings.
|
||||
Handle<Object> WriteDataValue(Handle<Object> value);
|
||||
|
||||
// Checks whether the receiver is an indexed exotic object
|
||||
// and name is a special numeric index.
|
||||
bool IsSpecialNumericIndex() const;
|
||||
|
||||
void InternalizeName();
|
||||
|
||||
private:
|
||||
@ -185,11 +183,15 @@ class LookupIterator FINAL BASE_EMBEDDED {
|
||||
}
|
||||
}
|
||||
|
||||
enum class ExoticIndexState { kUninitialized, kNoIndex, kIndex };
|
||||
bool IsIntegerIndexedExotic(JSReceiver* holder);
|
||||
|
||||
// If configuration_ becomes mutable, update
|
||||
// HolderIsReceiverOrHiddenPrototype.
|
||||
Configuration configuration_;
|
||||
State state_;
|
||||
bool has_property_;
|
||||
ExoticIndexState exotic_index_state_;
|
||||
PropertyDetails property_details_;
|
||||
Isolate* isolate_;
|
||||
Handle<Name> name_;
|
||||
|
@ -133,6 +133,8 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
|
||||
return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
|
||||
it->GetHolder<JSObject>(),
|
||||
it->GetAccessors());
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
return it->factory()->undefined_value();
|
||||
case LookupIterator::DATA:
|
||||
return it->GetDataValue();
|
||||
}
|
||||
@ -168,6 +170,8 @@ Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
|
||||
// relevant.
|
||||
it->NotFound();
|
||||
return it->isolate()->factory()->undefined_value();
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
return it->isolate()->factory()->undefined_value();
|
||||
case LookupIterator::DATA:
|
||||
return it->GetDataValue();
|
||||
}
|
||||
@ -3130,6 +3134,10 @@ MaybeHandle<Object> Object::SetPropertyInternal(LookupIterator* it,
|
||||
it->GetHolder<JSObject>(),
|
||||
it->GetAccessors(), language_mode);
|
||||
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
done = true;
|
||||
break;
|
||||
|
||||
case LookupIterator::DATA:
|
||||
if (it->property_details().IsReadOnly()) {
|
||||
return WriteToReadOnlyProperty(it, value, language_mode);
|
||||
@ -3192,6 +3200,9 @@ MaybeHandle<Object> Object::SetSuperProperty(LookupIterator* it,
|
||||
return JSObject::AddDataProperty(&own_lookup, value, NONE, language_mode,
|
||||
store_mode);
|
||||
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
return result;
|
||||
|
||||
case LookupIterator::DATA: {
|
||||
PropertyDetails details = own_lookup.property_details();
|
||||
if (details.IsConfigurable() || !details.IsReadOnly()) {
|
||||
@ -3321,16 +3332,14 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
|
||||
return WriteToReadOnlyProperty(it, value, language_mode);
|
||||
}
|
||||
|
||||
if (it->state() == LookupIterator::INTEGER_INDEXED_EXOTIC) return value;
|
||||
|
||||
Handle<JSObject> receiver = it->GetStoreTarget();
|
||||
|
||||
// If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
|
||||
// instead. If the prototype is Null, the proxy is detached.
|
||||
if (receiver->IsJSGlobalProxy()) return value;
|
||||
|
||||
// If the receiver is Indexed Exotic object (currently only typed arrays),
|
||||
// disallow adding properties with numeric names.
|
||||
if (it->IsSpecialNumericIndex()) return value;
|
||||
|
||||
// Possibly migrate to the most up-to-date map that will be able to store
|
||||
// |value| under it->name() with |attributes|.
|
||||
it->PrepareTransitionToDataProperty(value, attributes, store_mode);
|
||||
@ -4158,6 +4167,7 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
|
||||
!it.isolate()->IsInternallyUsedPropertyName(name);
|
||||
for (; it.IsFound(); it.Next()) {
|
||||
switch (it.state()) {
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
@ -4336,6 +4346,8 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
if (it->HasAccess()) break;
|
||||
return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
return Just(ABSENT);
|
||||
case LookupIterator::ACCESSOR:
|
||||
case LookupIterator::DATA:
|
||||
return Just(it->property_details().attributes());
|
||||
@ -5337,6 +5349,8 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
||||
if (it.isolate()->has_pending_exception()) return maybe_result;
|
||||
break;
|
||||
}
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
return it.isolate()->factory()->true_value();
|
||||
case LookupIterator::DATA:
|
||||
if (is_observed) {
|
||||
old_value = it.GetDataValue();
|
||||
@ -6764,6 +6778,8 @@ MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
|
||||
case LookupIterator::JSPROXY:
|
||||
return isolate->factory()->undefined_value();
|
||||
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
return isolate->factory()->undefined_value();
|
||||
case LookupIterator::DATA:
|
||||
continue;
|
||||
case LookupIterator::ACCESSOR: {
|
||||
|
@ -72,6 +72,7 @@ static Handle<Object> DebugGetProperty(LookupIterator* it,
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
// Ignore access checks.
|
||||
break;
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
case LookupIterator::INTERCEPTOR:
|
||||
case LookupIterator::JSPROXY:
|
||||
return it->isolate()->factory()->undefined_value();
|
||||
|
@ -362,3 +362,57 @@ TEST(BitField64) {
|
||||
CHECK(x == MiddleBits::encode(3));
|
||||
CHECK_EQ(3, MiddleBits::decode(x));
|
||||
}
|
||||
|
||||
|
||||
static void CheckNonArrayIndex(bool expected, const char* chars) {
|
||||
auto isolate = CcTest::i_isolate();
|
||||
auto string = isolate->factory()->NewStringFromAsciiChecked(chars);
|
||||
CHECK_EQ(expected, IsNonArrayIndexInteger(*string));
|
||||
}
|
||||
|
||||
|
||||
TEST(NonArrayIndexParsing) {
|
||||
auto isolate = CcTest::i_isolate();
|
||||
HandleScope scope(isolate);
|
||||
CheckNonArrayIndex(false, "-");
|
||||
CheckNonArrayIndex(false, "0");
|
||||
CheckNonArrayIndex(false, "01");
|
||||
CheckNonArrayIndex(false, "-01");
|
||||
CheckNonArrayIndex(false, "4294967295");
|
||||
CheckNonArrayIndex(false, "429496.7295");
|
||||
CheckNonArrayIndex(false, "43s3");
|
||||
CheckNonArrayIndex(true, "-0");
|
||||
CheckNonArrayIndex(true, "-1");
|
||||
CheckNonArrayIndex(true, "4294967296");
|
||||
CheckNonArrayIndex(true, "-4294967296");
|
||||
CheckNonArrayIndex(
|
||||
true,
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296");
|
||||
CheckNonArrayIndex(
|
||||
true,
|
||||
"-429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296"
|
||||
"429496729642949672964294967296429496729642949672964294967296");
|
||||
}
|
||||
|
56
test/mjsunit/es6/indexed-integer-exotics.js
Normal file
56
test/mjsunit/es6/indexed-integer-exotics.js
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
Object.prototype["10"] = "unreachable";
|
||||
Object.prototype["7"] = "unreachable";
|
||||
Object.prototype["-1"] = "unreachable";
|
||||
Object.prototype["-0"] = "unreachable";
|
||||
Object.prototype["4294967296"] = "unreachable";
|
||||
|
||||
var array = new Int32Array(10);
|
||||
|
||||
function check() {
|
||||
for (var i = 0; i < 4; i++) {
|
||||
assertEquals(undefined, array["-1"]);
|
||||
assertEquals(undefined, array["-0"]);
|
||||
assertEquals(undefined, array["10"]);
|
||||
assertEquals(undefined, array["4294967296"]);
|
||||
}
|
||||
assertEquals("unreachable", array.__proto__["-1"]);
|
||||
assertEquals("unreachable", array.__proto__["-0"]);
|
||||
assertEquals("unreachable", array.__proto__["10"]);
|
||||
assertEquals("unreachable", array.__proto__["4294967296"]);
|
||||
}
|
||||
|
||||
check();
|
||||
|
||||
array["-1"] = "unreachable";
|
||||
array["-0"] = "unreachable";
|
||||
array["10"] = "unreachable";
|
||||
array["4294967296"] = "unreachable";
|
||||
|
||||
check();
|
||||
|
||||
delete array["-0"];
|
||||
delete array["-1"];
|
||||
delete array["10"];
|
||||
delete array["4294967296"];
|
||||
|
||||
assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "-1"));
|
||||
assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "-0"));
|
||||
assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "10"));
|
||||
assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "4294967296"));
|
||||
assertEquals(10, Object.keys(array).length);
|
||||
|
||||
check();
|
||||
|
||||
function f() { return array["-1"]; }
|
||||
|
||||
for (var i = 0; i < 3; i++) {
|
||||
assertEquals(undefined, f());
|
||||
}
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
assertEquals(undefined, f());
|
@ -530,7 +530,7 @@ function TestTypedArraysWithIllegalIndices() {
|
||||
* assertEquals(undefined, a[-Infinity]);
|
||||
*/
|
||||
a[1.5] = 10;
|
||||
assertEquals(undefined, a[1.5]);
|
||||
assertEquals(10, a[1.5]);
|
||||
var nan = Math.sqrt(-1);
|
||||
a[nan] = 5;
|
||||
assertEquals(5, a[nan]);
|
||||
@ -579,7 +579,7 @@ function TestTypedArraysWithIllegalIndicesStrict() {
|
||||
* assertEquals(undefined, a[-Infinity]);
|
||||
*/
|
||||
a[1.5] = 10;
|
||||
assertEquals(undefined, a[1.5]);
|
||||
assertEquals(10, a[1.5]);
|
||||
var nan = Math.sqrt(-1);
|
||||
a[nan] = 5;
|
||||
assertEquals(5, a[nan]);
|
||||
|
Loading…
Reference in New Issue
Block a user