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

Side by Side Diff: src/runtime.cc

Issue 7811015: Change global const handling to silently ignore redeclarations (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 3 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
« no previous file with comments | « no previous file | src/v8natives.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 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 1166 matching lines...) Expand 10 before | Expand all | Expand 10 after
1177 // assign to it when evaluating the assignment for "const x = 1177 // assign to it when evaluating the assignment for "const x =
1178 // <expr>" the initial value is the hole. 1178 // <expr>" the initial value is the hole.
1179 bool is_const_property = value->IsTheHole(); 1179 bool is_const_property = value->IsTheHole();
1180 1180
1181 if (value->IsUndefined() || is_const_property) { 1181 if (value->IsUndefined() || is_const_property) {
1182 // Lookup the property in the global object, and don't set the 1182 // Lookup the property in the global object, and don't set the
1183 // value of the variable if the property is already there. 1183 // value of the variable if the property is already there.
1184 LookupResult lookup; 1184 LookupResult lookup;
1185 global->Lookup(*name, &lookup); 1185 global->Lookup(*name, &lookup);
1186 if (lookup.IsProperty()) { 1186 if (lookup.IsProperty()) {
1187 // Determine if the property is local by comparing the holder
1188 // against the global object. The information will be used to
1189 // avoid throwing re-declaration errors when declaring
1190 // variables or constants that exist in the prototype chain.
1191 bool is_local = (*global == lookup.holder());
1192 // Get the property attributes and determine if the property is
1193 // read-only.
1194 PropertyAttributes attributes = global->GetPropertyAttribute(*name); 1187 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
Kevin Millikin (Chromium) 2011/09/08 12:06:02 I think you could probably simplify this code a bi
Jakob Kummerow 2011/09/09 15:42:43 Done.
1195 bool is_read_only = (attributes & READ_ONLY) != 0; 1188 if (lookup.type() == INTERCEPTOR && attributes == ABSENT) {
1196 if (lookup.type() == INTERCEPTOR) {
1197 // If the interceptor says the property is there, we
1198 // just return undefined without overwriting the property.
1199 // Otherwise, we continue to setting the property.
1200 if (attributes != ABSENT) {
1201 // Check if the existing property conflicts with regards to const.
1202 if (is_local && (is_read_only || is_const_property)) {
1203 const char* type = (is_read_only) ? "const" : "var";
1204 return ThrowRedeclarationError(isolate, type, name);
1205 };
1206 // The property already exists without conflicting: Go to
1207 // the next declaration.
1208 continue;
1209 }
1210 // Fall-through and introduce the absent property by using 1189 // Fall-through and introduce the absent property by using
1211 // SetProperty. 1190 // SetProperty.
1212 } else { 1191 } else {
1213 // For const properties, we treat a callback with this name 1192 // The property already exists: Go to the next declaration.
1214 // even in the prototype as a conflicting declaration.
1215 if (is_const_property && (lookup.type() == CALLBACKS)) {
1216 return ThrowRedeclarationError(isolate, "const", name);
1217 }
1218 // Otherwise, we check for locally conflicting declarations.
1219 if (is_local && (is_read_only || is_const_property)) {
1220 const char* type = (is_read_only) ? "const" : "var";
1221 return ThrowRedeclarationError(isolate, type, name);
1222 }
1223 // The property already exists without conflicting: Go to
1224 // the next declaration.
1225 continue; 1193 continue;
1226 } 1194 }
1227 } 1195 }
1228 } else { 1196 } else {
1229 // Copy the function and update its context. Use it as value. 1197 // Copy the function and update its context. Use it as value.
1230 Handle<SharedFunctionInfo> shared = 1198 Handle<SharedFunctionInfo> shared =
1231 Handle<SharedFunctionInfo>::cast(value); 1199 Handle<SharedFunctionInfo>::cast(value);
1232 Handle<JSFunction> function = 1200 Handle<JSFunction> function =
1233 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, 1201 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1234 context, 1202 context,
(...skipping 11 matching lines...) Expand all
1246 // There's a local property that we need to overwrite because 1214 // There's a local property that we need to overwrite because
1247 // we're either declaring a function or there's an interceptor 1215 // we're either declaring a function or there's an interceptor
1248 // that claims the property is absent. 1216 // that claims the property is absent.
1249 // 1217 //
1250 // Check for conflicting re-declarations. We cannot have 1218 // Check for conflicting re-declarations. We cannot have
1251 // conflicting types in case of intercepted properties because 1219 // conflicting types in case of intercepted properties because
1252 // they are absent. 1220 // they are absent.
1253 if (lookup.IsProperty() && 1221 if (lookup.IsProperty() &&
1254 (lookup.type() != INTERCEPTOR) && 1222 (lookup.type() != INTERCEPTOR) &&
1255 (lookup.IsReadOnly() || is_const_property)) { 1223 (lookup.IsReadOnly() || is_const_property)) {
1256 const char* type = (lookup.IsReadOnly()) ? "const" : "var"; 1224 continue;
Kevin Millikin (Chromium) 2011/09/08 12:06:02 I don't think this is what we intend. Won't we sk
Jakob Kummerow 2011/09/09 15:42:43 Done.
1257 return ThrowRedeclarationError(isolate, type, name);
1258 } 1225 }
1259 1226
1260 // Safari does not allow the invocation of callback setters for 1227 // Safari does not allow the invocation of callback setters for
1261 // function declarations. To mimic this behavior, we do not allow 1228 // function declarations. To mimic this behavior, we do not allow
1262 // the invocation of setters for function values. This makes a 1229 // the invocation of setters for function values. This makes a
1263 // difference for global functions with the same names as event 1230 // difference for global functions with the same names as event
1264 // handlers such as "function onload() {}". Firefox does call the 1231 // handlers such as "function onload() {}". Firefox does call the
1265 // onload setter in those case and Safari does not. We follow 1232 // onload setter in those case and Safari does not. We follow
1266 // Safari for compatibility. 1233 // Safari for compatibility.
1267 if (value->IsJSFunction()) { 1234 if (value->IsJSFunction()) {
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
1422 // We follow Safari and Firefox behavior and only set the property 1389 // We follow Safari and Firefox behavior and only set the property
1423 // locally if there is an explicit initialization value that we have 1390 // locally if there is an explicit initialization value that we have
1424 // to assign to the property. 1391 // to assign to the property.
1425 // Note that objects can have hidden prototypes, so we need to traverse 1392 // Note that objects can have hidden prototypes, so we need to traverse
1426 // the whole chain of hidden prototypes to do a 'local' lookup. 1393 // the whole chain of hidden prototypes to do a 'local' lookup.
1427 JSObject* real_holder = global; 1394 JSObject* real_holder = global;
1428 LookupResult lookup; 1395 LookupResult lookup;
1429 while (true) { 1396 while (true) {
1430 real_holder->LocalLookup(*name, &lookup); 1397 real_holder->LocalLookup(*name, &lookup);
1431 if (lookup.IsProperty()) { 1398 if (lookup.IsProperty()) {
1432 // Determine if this is a redeclaration of something read-only. 1399 // Determine if this is a redeclaration of something read-only.
Kevin Millikin (Chromium) 2011/09/08 12:06:02 Let's change all the mentions of declaration, rede
Jakob Kummerow 2011/09/09 15:42:43 Done.
1433 if (lookup.IsReadOnly()) { 1400 if (lookup.IsReadOnly()) {
1434 // If we found readonly property on one of hidden prototypes, 1401 // If we found readonly property on one of hidden prototypes,
1435 // just shadow it. 1402 // just shadow it.
1436 if (real_holder != isolate->context()->global()) break; 1403 if (real_holder != isolate->context()->global()) break;
1437 return ThrowRedeclarationError(isolate, "const", name); 1404 return isolate->heap()->undefined_value();
1438 } 1405 }
1439 1406
1440 // Determine if this is a redeclaration of an intercepted read-only 1407 // Determine if this is a redeclaration of an intercepted read-only
1441 // property and figure out if the property exists at all. 1408 // property and figure out if the property exists at all.
Kevin Millikin (Chromium) 2011/09/08 12:06:02 This code is pretty complicated. I think what it'
Jakob Kummerow 2011/09/09 15:42:43 Done.
1442 bool found = true; 1409 bool found = true;
1443 PropertyType type = lookup.type(); 1410 PropertyType type = lookup.type();
1444 if (type == INTERCEPTOR) { 1411 if (type == INTERCEPTOR) {
1445 HandleScope handle_scope(isolate); 1412 HandleScope handle_scope(isolate);
1446 Handle<JSObject> holder(real_holder); 1413 Handle<JSObject> holder(real_holder);
1447 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name); 1414 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1448 real_holder = *holder; 1415 real_holder = *holder;
1449 if (intercepted == ABSENT) { 1416 if (intercepted == ABSENT) {
1450 // The interceptor claims the property isn't there. We need to 1417 // The interceptor claims the property isn't there. We need to
1451 // make sure to introduce it. 1418 // make sure to introduce it.
1452 found = false; 1419 found = false;
1453 } else if ((intercepted & READ_ONLY) != 0) { 1420 } else if ((intercepted & READ_ONLY) != 0) {
1454 // The property is present, but read-only. Since we're trying to 1421 // The property is present, but read-only, so we ignore the
1455 // overwrite it with a variable declaration we must throw a 1422 // re-declaration. However if we found readonly property
1456 // re-declaration error. However if we found readonly property
1457 // on one of hidden prototypes, just shadow it. 1423 // on one of hidden prototypes, just shadow it.
1458 if (real_holder != isolate->context()->global()) break; 1424 if (real_holder != isolate->context()->global()) break;
1459 return ThrowRedeclarationError(isolate, "const", name); 1425 return isolate->heap()->undefined_value();
1460 } 1426 }
1461 } 1427 }
1462 1428
1463 if (found && !assign) { 1429 if (found && !assign) {
1464 // The global property is there and we're not assigning any value 1430 // The global property is there and we're not assigning any value
1465 // to it. Just return. 1431 // to it. Just return.
1466 return isolate->heap()->undefined_value(); 1432 return isolate->heap()->undefined_value();
1467 } 1433 }
1468 1434
1469 // Assign the value (or undefined) to the property. 1435 // Assign the value (or undefined) to the property.
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1512 // prototype chain (this rules out using SetProperty). 1478 // prototype chain (this rules out using SetProperty).
1513 // We use SetLocalPropertyIgnoreAttributes instead 1479 // We use SetLocalPropertyIgnoreAttributes instead
1514 LookupResult lookup; 1480 LookupResult lookup;
1515 global->LocalLookup(*name, &lookup); 1481 global->LocalLookup(*name, &lookup);
1516 if (!lookup.IsProperty()) { 1482 if (!lookup.IsProperty()) {
1517 return global->SetLocalPropertyIgnoreAttributes(*name, 1483 return global->SetLocalPropertyIgnoreAttributes(*name,
1518 *value, 1484 *value,
1519 attributes); 1485 attributes);
1520 } 1486 }
1521 1487
1522 // Determine if this is a redeclaration of something not 1488 // Determine if this is a redeclaration of something not
Kevin Millikin (Chromium) 2011/09/08 12:06:02 Not your code, but the comments that mention 'decl
Jakob Kummerow 2011/09/09 15:42:43 Done.
1523 // read-only. In case the result is hidden behind an interceptor we 1489 // read-only. In case the result is hidden behind an interceptor we
1524 // need to ask it for the property attributes. 1490 // need to ask it for the property attributes.
1525 if (!lookup.IsReadOnly()) { 1491 if (!lookup.IsReadOnly()) {
1526 if (lookup.type() != INTERCEPTOR) { 1492 if (lookup.type() != INTERCEPTOR) {
1527 return ThrowRedeclarationError(isolate, "var", name); 1493 return isolate->heap()->undefined_value();
Kevin Millikin (Chromium) 2011/09/08 12:06:02 I'm not sure this is our intended semantics. Do w
Jakob Kummerow 2011/09/09 15:42:43 Done.
1528 } 1494 }
1529 1495
1530 PropertyAttributes intercepted = global->GetPropertyAttribute(*name); 1496 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1531 1497
1532 // Throw re-declaration error if the intercepted property is present 1498 // Ignore the re-declaration if the intercepted property is present
1533 // but not read-only. 1499 // but not read-only.
1534 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) { 1500 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1535 return ThrowRedeclarationError(isolate, "var", name); 1501 return isolate->heap()->undefined_value();
1536 } 1502 }
1537 1503
1538 // Restore global object from context (in case of GC) and continue 1504 // Restore global object from context (in case of GC) and continue
1539 // with setting the value because the property is either absent or 1505 // with setting the value because the property is either absent or
1540 // read-only. We also have to do redo the lookup. 1506 // read-only. We also have to do redo the lookup.
1541 HandleScope handle_scope(isolate); 1507 HandleScope handle_scope(isolate);
1542 Handle<GlobalObject> global(isolate->context()->global()); 1508 Handle<GlobalObject> global(isolate->context()->global());
1543 1509
1544 // BUG 1213575: Handle the case where we have to set a read-only 1510 // BUG 1213575: Handle the case where we have to set a read-only
1545 // property through an interceptor and only do it if it's 1511 // property through an interceptor and only do it if it's
1546 // uninitialized, e.g. the hole. Nirk... 1512 // uninitialized, e.g. the hole. Nirk...
Kevin Millikin (Chromium) 2011/09/08 12:06:02 I'm not sure how to interpret "nirk", but it doesn
Jakob Kummerow 2011/09/09 15:42:43 I could change it to "nurk", which I think sounds
1547 // Passing non-strict mode because the property is writable. 1513 // Passing non-strict mode because the property is writable.
1548 RETURN_IF_EMPTY_HANDLE(isolate, 1514 RETURN_IF_EMPTY_HANDLE(isolate,
1549 SetProperty(global, 1515 SetProperty(global,
1550 name, 1516 name,
1551 value, 1517 value,
1552 attributes, 1518 attributes,
1553 kNonStrictMode)); 1519 kNonStrictMode));
1554 return *value; 1520 return *value;
1555 } 1521 }
1556 1522
(...skipping 11430 matching lines...) Expand 10 before | Expand all | Expand 10 after
12987 } else { 12953 } else {
12988 // Handle last resort GC and make sure to allow future allocations 12954 // Handle last resort GC and make sure to allow future allocations
12989 // to grow the heap without causing GCs (if possible). 12955 // to grow the heap without causing GCs (if possible).
12990 isolate->counters()->gc_last_resort_from_js()->Increment(); 12956 isolate->counters()->gc_last_resort_from_js()->Increment();
12991 isolate->heap()->CollectAllGarbage(false); 12957 isolate->heap()->CollectAllGarbage(false);
12992 } 12958 }
12993 } 12959 }
12994 12960
12995 12961
12996 } } // namespace v8::internal 12962 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | src/v8natives.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698