| 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();
|
|
|
|
|