Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(516)

Side by Side Diff: src/runtime.cc

Issue 10067010: Implement ES5 erratum: global declarations shadow inherited properties. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1271 matching lines...) Expand 10 before | Expand all | Expand 10 after
1282 // Traverse the name/value pairs and set the properties. 1282 // Traverse the name/value pairs and set the properties.
1283 int length = pairs->length(); 1283 int length = pairs->length();
1284 for (int i = 0; i < length; i += 2) { 1284 for (int i = 0; i < length; i += 2) {
1285 HandleScope scope(isolate); 1285 HandleScope scope(isolate);
1286 Handle<String> name(String::cast(pairs->get(i))); 1286 Handle<String> name(String::cast(pairs->get(i)));
1287 Handle<Object> value(pairs->get(i + 1), isolate); 1287 Handle<Object> value(pairs->get(i + 1), isolate);
1288 1288
1289 // We have to declare a global const property. To capture we only 1289 // We have to declare a global const property. To capture we only
1290 // assign to it when evaluating the assignment for "const x = 1290 // assign to it when evaluating the assignment for "const x =
1291 // <expr>" the initial value is the hole. 1291 // <expr>" the initial value is the hole.
1292 bool is_const_property = value->IsTheHole(); 1292 bool is_const = value->IsTheHole();
1293 bool is_function_declaration = false; 1293 bool is_function_declaration = false;
1294 if (value->IsUndefined() || is_const_property) { 1294 if (value->IsUndefined() || is_const) {
1295 // Lookup the property in the global object, and don't set the 1295 // Lookup the property in the global object, and don't set the
1296 // value of the variable if the property is already there. 1296 // value of the variable if the property is already there.
1297 // Do the lookup locally only, see ES5 errata.
1297 LookupResult lookup(isolate); 1298 LookupResult lookup(isolate);
1298 global->Lookup(*name, &lookup); 1299 global->LocalLookup(*name, &lookup);
1299 if (lookup.IsProperty()) { 1300 if (lookup.IsProperty()) {
1300 // We found an existing property. Unless it was an interceptor 1301 // We found an existing property. Unless it was an interceptor
1301 // that claims the property is absent, skip this declaration. 1302 // that claims the property is absent, skip this declaration.
1302 if (lookup.type() != INTERCEPTOR) { 1303 if (lookup.type() != INTERCEPTOR) {
1303 continue; 1304 continue;
1304 } 1305 }
1305 PropertyAttributes attributes = global->GetPropertyAttribute(*name); 1306 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1306 if (attributes != ABSENT) { 1307 if (attributes != ABSENT) {
1307 continue; 1308 continue;
1308 } 1309 }
(...skipping 17 matching lines...) Expand all
1326 1327
1327 // Compute the property attributes. According to ECMA-262, section 1328 // Compute the property attributes. According to ECMA-262, section
1328 // 13, page 71, the property must be read-only and 1329 // 13, page 71, the property must be read-only and
1329 // non-deletable. However, neither SpiderMonkey nor KJS creates the 1330 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1330 // property as read-only, so we don't either. 1331 // property as read-only, so we don't either.
1331 int attr = NONE; 1332 int attr = NONE;
1332 if (!DeclareGlobalsEvalFlag::decode(flags)) { 1333 if (!DeclareGlobalsEvalFlag::decode(flags)) {
1333 attr |= DONT_DELETE; 1334 attr |= DONT_DELETE;
1334 } 1335 }
1335 bool is_native = DeclareGlobalsNativeFlag::decode(flags); 1336 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
1336 if (is_const_property || (is_native && is_function_declaration)) { 1337 if (is_const || (is_native && is_function_declaration)) {
1337 attr |= READ_ONLY; 1338 attr |= READ_ONLY;
1338 } 1339 }
1339 1340
1340 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags); 1341 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1341 1342
1342 // Safari does not allow the invocation of callback setters for 1343 if (!lookup.IsProperty() || is_function_declaration) {
1343 // function declarations. To mimic this behavior, we do not allow 1344 // If the local property exists, check that we can either reconfigure it
Michael Starzinger 2012/04/16 11:32:30 This sentences is missing the "or" part of "either
rossberg 2012/04/16 13:15:44 Done.
1344 // the invocation of setters for function values. This makes a 1345 // as required for function declarations.
1345 // difference for global functions with the same names as event 1346 if (lookup.IsProperty() && lookup.IsDontDelete()) {
1346 // handlers such as "function onload() {}". Firefox does call the 1347 if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
1347 // onload setter in those case and Safari does not. We follow 1348 lookup.type() == CALLBACKS) {
1348 // Safari for compatibility. 1349 return ThrowRedeclarationError(isolate, "function", name);
1349 if (is_function_declaration) {
1350 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1351 // Do not overwrite READ_ONLY properties.
1352 if (lookup.GetAttributes() & READ_ONLY) {
1353 if (language_mode != CLASSIC_MODE) {
1354 Handle<Object> args[] = { name };
1355 return isolate->Throw(*isolate->factory()->NewTypeError(
1356 "strict_cannot_assign", HandleVector(args, ARRAY_SIZE(args))));
1357 }
1358 continue;
1359 } 1350 }
1360 // Do not change DONT_DELETE to false from true. 1351 // If the existing property is not configurable, keep its attributes.
1361 attr |= lookup.GetAttributes() & DONT_DELETE; 1352 attr = lookup.GetAttributes();
1362 } 1353 }
1363 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr); 1354 // Define or redefine own property.
1364 1355 RETURN_IF_EMPTY_HANDLE(isolate,
1365 RETURN_IF_EMPTY_HANDLE( 1356 JSObject::SetLocalPropertyIgnoreAttributes(
1366 isolate, 1357 global, name, value, static_cast<PropertyAttributes>(attr)));
1367 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1368 attributes));
1369 } else { 1358 } else {
1370 RETURN_IF_EMPTY_HANDLE( 1359 // Do a [[Put]] on the existing (own) property.
1371 isolate, 1360 RETURN_IF_EMPTY_HANDLE(isolate,
1372 JSReceiver::SetProperty(global, name, value, 1361 JSObject::SetProperty(
1373 static_cast<PropertyAttributes>(attr), 1362 global, name, value, static_cast<PropertyAttributes>(attr),
1374 language_mode == CLASSIC_MODE 1363 language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode));
1375 ? kNonStrictMode : kStrictMode));
1376 } 1364 }
1377 } 1365 }
1378 1366
1379 ASSERT(!isolate->has_pending_exception()); 1367 ASSERT(!isolate->has_pending_exception());
1380 return isolate->heap()->undefined_value(); 1368 return isolate->heap()->undefined_value();
1381 } 1369 }
1382 1370
1383 1371
1384 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) { 1372 RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
1385 HandleScope scope(isolate); 1373 HandleScope scope(isolate);
(...skipping 12 matching lines...) Expand all
1398 1386
1399 int index; 1387 int index;
1400 PropertyAttributes attributes; 1388 PropertyAttributes attributes;
1401 ContextLookupFlags flags = DONT_FOLLOW_CHAINS; 1389 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
1402 BindingFlags binding_flags; 1390 BindingFlags binding_flags;
1403 Handle<Object> holder = 1391 Handle<Object> holder =
1404 context->Lookup(name, flags, &index, &attributes, &binding_flags); 1392 context->Lookup(name, flags, &index, &attributes, &binding_flags);
1405 1393
1406 if (attributes != ABSENT) { 1394 if (attributes != ABSENT) {
1407 // The name was declared before; check for conflicting re-declarations. 1395 // The name was declared before; check for conflicting re-declarations.
1396 // Note: this is actually inconsistent with what happens for globals (where
1397 // we silently ignore such declarations).
1408 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) { 1398 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1409 // Functions are not read-only. 1399 // Functions are not read-only.
1410 ASSERT(mode != READ_ONLY || initial_value->IsTheHole()); 1400 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1411 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var"; 1401 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1412 return ThrowRedeclarationError(isolate, type, name); 1402 return ThrowRedeclarationError(isolate, type, name);
1413 } 1403 }
1414 1404
1415 // Initialize it if necessary. 1405 // Initialize it if necessary.
1416 if (*initial_value != NULL) { 1406 if (*initial_value != NULL) {
1417 if (index >= 0) { 1407 if (index >= 0) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1460 // SetProperty and no setters are invoked for those since they are 1450 // SetProperty and no setters are invoked for those since they are
1461 // not real JSObjects. 1451 // not real JSObjects.
1462 if (initial_value->IsTheHole() && 1452 if (initial_value->IsTheHole() &&
1463 !object->IsJSContextExtensionObject()) { 1453 !object->IsJSContextExtensionObject()) {
1464 LookupResult lookup(isolate); 1454 LookupResult lookup(isolate);
1465 object->Lookup(*name, &lookup); 1455 object->Lookup(*name, &lookup);
1466 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) { 1456 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
1467 return ThrowRedeclarationError(isolate, "const", name); 1457 return ThrowRedeclarationError(isolate, "const", name);
1468 } 1458 }
1469 } 1459 }
1470 RETURN_IF_EMPTY_HANDLE( 1460 if (object->IsJSGlobalObject()) {
1471 isolate, 1461 // Define own property on the global object.
1472 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode)); 1462 RETURN_IF_EMPTY_HANDLE(isolate,
1463 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode));
1464 } else {
1465 RETURN_IF_EMPTY_HANDLE(isolate,
1466 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
1467 }
1473 } 1468 }
1474 1469
1475 return isolate->heap()->undefined_value(); 1470 return isolate->heap()->undefined_value();
1476 } 1471 }
1477 1472
1478 1473
1479 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { 1474 RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
1480 NoHandleAllocation nha; 1475 NoHandleAllocation nha;
1481 // args[0] == name 1476 // args[0] == name
1482 // args[1] == language_mode 1477 // args[1] == language_mode
1483 // args[2] == value (optional) 1478 // args[2] == value (optional)
1484 1479
1485 // Determine if we need to assign to the variable if it already 1480 // Determine if we need to assign to the variable if it already
1486 // exists (based on the number of arguments). 1481 // exists (based on the number of arguments).
1487 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3); 1482 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1488 bool assign = args.length() == 3; 1483 bool assign = args.length() == 3;
1489 1484
1490 CONVERT_ARG_HANDLE_CHECKED(String, name, 0); 1485 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
1491 GlobalObject* global = isolate->context()->global(); 1486 GlobalObject* global = isolate->context()->global();
1492 RUNTIME_ASSERT(args[1]->IsSmi()); 1487 RUNTIME_ASSERT(args[1]->IsSmi());
1493 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1); 1488 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1494 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE) 1489 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1495 ? kNonStrictMode : kStrictMode; 1490 ? kNonStrictMode : kStrictMode;
1496 1491
1497 // According to ECMA-262, section 12.2, page 62, the property must 1492 // According to ECMA-262, section 12.2, page 62, the property must
1498 // not be deletable. 1493 // not be deletable.
1499 PropertyAttributes attributes = DONT_DELETE; 1494 PropertyAttributes attributes = DONT_DELETE;
1500 1495
1496 /*ERRATUM: no longer need to traverse the prototype chain?*/
Michael Starzinger 2012/04/16 11:32:30 This looks like a leftover, should that be a TODO?
rossberg 2012/04/16 13:15:44 Done.
1501 // Lookup the property locally in the global object. If it isn't 1497 // Lookup the property locally in the global object. If it isn't
1502 // there, there is a property with this name in the prototype chain. 1498 // there, there is a property with this name in the prototype chain.
1503 // We follow Safari and Firefox behavior and only set the property 1499 // We follow Safari and Firefox behavior and only set the property
1504 // locally if there is an explicit initialization value that we have 1500 // locally if there is an explicit initialization value that we have
1505 // to assign to the property. 1501 // to assign to the property.
1506 // Note that objects can have hidden prototypes, so we need to traverse 1502 // Note that objects can have hidden prototypes, so we need to traverse
1507 // the whole chain of hidden prototypes to do a 'local' lookup. 1503 // the whole chain of hidden prototypes to do a 'local' lookup.
1508 Object* object = global; 1504 Object* object = global;
1509 LookupResult lookup(isolate); 1505 LookupResult lookup(isolate);
1510 while (object->IsJSObject() && 1506 while (object->IsJSObject() &&
(...skipping 11835 matching lines...) Expand 10 before | Expand all | Expand 10 after
13346 // Handle last resort GC and make sure to allow future allocations 13342 // Handle last resort GC and make sure to allow future allocations
13347 // to grow the heap without causing GCs (if possible). 13343 // to grow the heap without causing GCs (if possible).
13348 isolate->counters()->gc_last_resort_from_js()->Increment(); 13344 isolate->counters()->gc_last_resort_from_js()->Increment();
13349 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, 13345 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13350 "Runtime::PerformGC"); 13346 "Runtime::PerformGC");
13351 } 13347 }
13352 } 13348 }
13353 13349
13354 13350
13355 } } // namespace v8::internal 13351 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/parser.cc ('k') | test/cctest/test-api.cc » ('j') | test/cctest/test-api.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698