/* * E5.1 updated the algorithm in Section 10.5, declaration binding instantiation. * Step 5.e is a new step (compared to E5) and restores compatibility to an E3 * idiom. See E5.1 Annex F. * * This testcase tests for the the updated E5.1 behavior for eval() calls. * Eval creates configurable bindings. * * Tests for Program execution context are in individual separate files, * because function declarations are "hoisted" to program entry. Thus, * controlling test execution is a bit tricky. Program code creates * non-configurable bindings. * * V8 does not pass these tests. */ /* * Notes: * * - The new behavior only applies if a function is being re-declared in the * global environment record. This is the case with: * * + Program code * + Indirect eval * * - An existing property of the same name exists in the global object. * Such a name can be: * * + Another function * + Any other value (like a constant) * * - The existing property may have various attribute combinations, and may * even be an accessor (set/get). * * - The purpose of step 5.e is to ensure that the resulting property is * a plain data property, with [[Writable]] and [[Enumerable]] true; * [[Configurable]] final value depends on execution context. * * + If configurable, the property is converted to a plain data property * and [[Writable]] and [[Enumerable]] are set to true. [[Configurable]] * is set based on whether configurable bindings are enabled. * * + If not configurable, the property must be a plain data property and * have [[Writable]] and [[Enumerable]] set. If not, a TypeError occurs. * * - Note that re-declaring a global function automatically makes the property * enumerable even if it earlier wasn't. */ function printProps(name) { var indirectEval = eval; var global = indirectEval('this;'); // indirect eval -> this = global object var desc = Object.getOwnPropertyDescriptor(global, name); if (desc.get || desc.set) { // Note: typeof will invoke getter here print(name + ': ' + 'typeof=' + typeof global[name] + ', ' + 'enumerable=' + desc.enumerable + ', ' + 'configurable=' + desc.configurable); } else { print(name + ': ' + 'typeof=' + typeof global[name] + ', ' + 'writable=' + desc.writable + ', ' + 'enumerable=' + desc.enumerable + ', ' + 'configurable=' + desc.configurable); } } function defineProp(name, attrs) { var indirectEval = eval; var global = indirectEval('this;'); // indirect eval -> this = global object Object.defineProperty(global, name, attrs); } /*=== RegExp: typeof=function, writable=true, enumerable=false, configurable=true 123 RegExp: typeof=function, writable=true, enumerable=true, configurable=true ===*/ /* Existing configurable data property. * * Note that the property should become enumerable (but does not in current * V8). */ printProps('RegExp'); try { eval("function RegExp() { return 123; }"); print(RegExp()); } catch (e) { print(e.name); } printProps('RegExp'); /*=== NaN: typeof=number, writable=false, enumerable=false, configurable=false TypeError NaN: typeof=number, writable=false, enumerable=false, configurable=false ===*/ /* Existing non-configurable data property. */ printProps('NaN'); try { // non-configurable and does not match requirements of step 5.e.iv -> TypeError */ eval("function NaN() { return 234; }"); print('never here'); } catch (e) { print(e.name); } printProps('NaN'); /*=== getter configurableAccessor: typeof=undefined, enumerable=false, configurable=true 345 configurableAccessor: typeof=function, writable=true, enumerable=true, configurable=true ===*/ /* Existing configurable accessor. * * Need to create ourselves. */ defineProp('configurableAccessor', { get: function() { print('getter'); }, set: function(x) { print('setter'); }, enumerable: false, configurable: true }) // Note: printProps() will invoke getter here (but not below) printProps('configurableAccessor'); try { eval("function configurableAccessor() { return 345; }"); print(configurableAccessor()); } catch (e) { print(e.name); } printProps('configurableAccessor'); /*=== getter nonconfigurableAccessor: typeof=undefined, enumerable=false, configurable=false TypeError getter nonconfigurableAccessor: typeof=undefined, enumerable=false, configurable=false ===*/ /* Existing non-configurable accessor. */ defineProp('nonconfigurableAccessor', { get: function() { print('getter'); }, set: function(x) { print('setter'); }, enumerable: false, configurable: false, }) // Note: printProps() will invoke getter here and again below printProps('nonconfigurableAccessor'); try { eval("function nonconfigurableAccessor() { return 456; }"); } catch (e) { print(e.name); } printProps('nonconfigurableAccessor');