Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index 2637281f080ed9f7f32fba93701c4da068a4f34e..c07d49768f0f14144f998cf3cf6a654456fe20fa 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -3012,6 +3012,126 @@ Handle<Object> Parser::GetBoilerplateValue(Expression* expression) { |
return Factory::undefined_value(); |
} |
+// Defined in ast.cc |
+bool IsEqualString(void* first, void* second); |
+bool IsEqualSmi(void* first, void* second); |
+ |
+ |
+// Validation per 11.1.5 Object Initialiser |
+class ObjectLiteralPropertyChecker { |
+ public: |
+ ObjectLiteralPropertyChecker(Parser* parser, bool strict) : |
+ props(&IsEqualString), |
+ elems(&IsEqualSmi), |
+ parser_(parser), |
+ strict_(strict) { |
+ } |
+ |
+ void CheckProperty( |
+ ObjectLiteral::Property* property, |
+ Scanner::Location loc, |
+ bool* ok); |
+ |
+ private: |
+ enum PropertyKind { |
+ kGetAccessor = 0x01, |
+ kSetAccessor = 0x02, |
+ kAccessor = kGetAccessor | kSetAccessor, |
+ kData = 0x04 |
+ }; |
+ |
+ static intptr_t GetPropertyKind(ObjectLiteral::Property* property) { |
+ switch (property->kind()) { |
+ case ObjectLiteral::Property::GETTER: |
+ return kGetAccessor; |
+ case ObjectLiteral::Property::SETTER: |
+ return kSetAccessor; |
+ default: |
+ return kData; |
+ } |
+ } |
+ |
+ HashMap props; |
+ HashMap elems; |
+ Parser* parser_; |
+ bool strict_; |
+}; |
+ |
+ |
+void ObjectLiteralPropertyChecker::CheckProperty( |
+ ObjectLiteral::Property* property, |
+ Scanner::Location loc, |
+ bool* ok) { |
+ |
+ ASSERT(property != NULL); |
+ |
+ Literal *lit = property->key(); |
+ Handle<Object> handle = lit->handle(); |
+ |
+ uint32_t hash; |
+ HashMap* map; |
+ void* key; |
+ Smi* smi_key_location; |
+ |
+ if (handle->IsSymbol()) { |
+ Handle<String> name(String::cast(*handle)); |
+ if (name->AsArrayIndex(&hash)) { |
+ smi_key_location = Smi::FromInt(hash); |
+ key = &smi_key_location; |
+ map = &elems; |
+ } else { |
+ key = handle.location(); |
+ hash = name->Hash(); |
+ map = &props; |
+ } |
+ } else if (handle->ToArrayIndex(&hash)) { |
+ key = handle.location(); |
+ map = &elems; |
+ } else { |
+ ASSERT(handle->IsNumber()); |
+ double num = handle->Number(); |
+ char arr[100]; |
+ Vector<char> buffer(arr, ARRAY_SIZE(arr)); |
+ const char* str = DoubleToCString(num, buffer); |
+ Handle<String> name = Factory::NewStringFromAscii(CStrVector(str)); |
+ key = name.location(); |
+ hash = name->Hash(); |
+ map = &props; |
+ } |
+ |
+ // Lookup property previously defined, if any. |
+ HashMap::Entry* entry = map->Lookup(key, hash, true); |
+ intptr_t prev = reinterpret_cast<intptr_t> (entry->value); |
+ intptr_t curr = GetPropertyKind(property); |
+ |
+ // Duplicate data properties are illegal in strict mode. |
+ if (strict_ && (curr & prev & kData) != 0) { |
+ parser_->ReportMessageAt(loc, "strict_duplicate_property", |
+ Vector<const char*>::empty()); |
+ *ok = false; |
+ return; |
+ } |
+ // Data property conflicting with an accessor. |
+ if (((curr & kData) && (prev & kAccessor)) || |
+ ((prev & kData) && (curr & kAccessor))) { |
+ parser_->ReportMessageAt(loc, "accessor_data_property", |
+ Vector<const char*>::empty()); |
+ *ok = false; |
+ return; |
+ } |
+ // Two accessors of the same type conflicting |
+ if ((curr & prev & kAccessor) != 0) { |
+ parser_->ReportMessageAt(loc, "accessor_get_set", |
+ Vector<const char*>::empty()); |
+ *ok = false; |
+ return; |
+ } |
+ |
+ // Update map |
+ entry->value = reinterpret_cast<void*> (prev | curr); |
+ *ok = true; |
+} |
+ |
void Parser::BuildObjectLiteralConstantProperties( |
ZoneList<ObjectLiteral::Property*>* properties, |
@@ -3117,12 +3237,20 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { |
new ZoneList<ObjectLiteral::Property*>(4); |
int number_of_boilerplate_properties = 0; |
+ ObjectLiteralPropertyChecker checker(this, temp_scope_->StrictMode()); |
+ |
Expect(Token::LBRACE, CHECK_OK); |
+ Scanner::Location loc = scanner().location(); |
+ |
while (peek() != Token::RBRACE) { |
if (fni_ != NULL) fni_->Enter(); |
Literal* key = NULL; |
Token::Value next = peek(); |
+ |
+ // Location of the property name token |
+ Scanner::Location loc = scanner().peek_location(); |
+ |
switch (next) { |
case Token::IDENTIFIER: { |
bool is_getter = false; |
@@ -3132,11 +3260,15 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { |
if (fni_ != NULL) fni_->PushLiteralName(id); |
if ((is_getter || is_setter) && peek() != Token::COLON) { |
+ // Update loc to point to the identifier |
+ loc = scanner().peek_location(); |
ObjectLiteral::Property* property = |
ParseObjectLiteralGetSet(is_getter, CHECK_OK); |
if (IsBoilerplateProperty(property)) { |
number_of_boilerplate_properties++; |
} |
+ // Validate the property. |
+ checker.CheckProperty(property, loc, CHECK_OK); |
properties->Add(property); |
if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK); |
@@ -3193,6 +3325,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { |
// Count CONSTANT or COMPUTED properties to maintain the enumeration order. |
if (IsBoilerplateProperty(property)) number_of_boilerplate_properties++; |
+ // Validate the property |
+ checker.CheckProperty(property, loc, CHECK_OK); |
properties->Add(property); |
// TODO(1240767): Consider allowing trailing comma. |
@@ -3204,6 +3338,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { |
} |
} |
Expect(Token::RBRACE, CHECK_OK); |
+ |
// Computation of literal_index must happen before pre parse bailout. |
int literal_index = temp_scope_->NextMaterializedLiteralIndex(); |