support computed property name in object literal (#4268)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sun, 8 Nov 2020 15:38:32 +0000 (15:38 +0000)
committerGitHub <noreply@github.com>
Sun, 8 Nov 2020 15:38:32 +0000 (23:38 +0800)
lib/ast.js
lib/compress.js
lib/mozilla-ast.js
lib/output.js
lib/parse.js
lib/propmangle.js
lib/transform.js
test/compress/objects.js
test/mocha/tokens.js
test/ufuzz/index.js

index ad58ec2..02a38b9 100644 (file)
@@ -1015,24 +1015,28 @@ var AST_Object = DEFNODE("Object", "properties", {
 var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
     $documentation: "Base class for literal object properties",
     $propdoc: {
-        key: "[string|AST_SymbolAccessor] property name. For ObjectKeyVal this is a string. For getters and setters this is an AST_SymbolAccessor.",
-        value: "[AST_Node] property value.  For getters and setters this is an AST_Accessor."
+        key: "[string|AST_Node] property name.  For computed property this is an AST_Node.",
+        value: "[AST_Node] property value.  For getters and setters this is an AST_Accessor.",
     },
     walk: function(visitor) {
         var node = this;
         visitor.visit(node, function() {
+            if (node.key instanceof AST_Node) node.key.walk(visitor);
             node.value.walk(visitor);
         });
-    }
+    },
+    _validate: function() {
+        if (typeof this.key != "string") {
+            if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
+            must_be_expression(this, "key");
+        }
+        if (!(this.value instanceof AST_Node)) throw new Error("value must be AST_Node");
+    },
 });
 
-var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
+var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
     $documentation: "A key: value object property",
-    $propdoc: {
-        quote: "[string] the original quote character"
-    },
     _validate: function() {
-        if (typeof this.key != "string") throw new Error("key must be string");
         must_be_expression(this, "value");
     },
 }, AST_ObjectProperty);
@@ -1040,7 +1044,6 @@ var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
 var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
     $documentation: "An object setter property",
     _validate: function() {
-        if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
         if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
     },
 }, AST_ObjectProperty);
@@ -1048,7 +1051,6 @@ var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
 var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
     $documentation: "An object getter property",
     _validate: function() {
-        if (!(this.key instanceof AST_SymbolAccessor)) throw new Error("key must be AST_SymbolAccessor");
         if (!(this.value instanceof AST_Accessor)) throw new Error("value must be AST_Accessor");
     },
 }, AST_ObjectProperty);
@@ -1065,10 +1067,6 @@ var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
     },
 });
 
-var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
-    $documentation: "The name of a property accessor (setter/getter function)"
-}, AST_Symbol);
-
 var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
     $documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
 }, AST_Symbol);
index 47eba90..87e26f8 100644 (file)
@@ -1749,11 +1749,10 @@ merge(Compressor.prototype, {
                     }
                 } else if (expr instanceof AST_Object) {
                     expr.properties.forEach(function(prop) {
-                        if (prop instanceof AST_ObjectKeyVal) {
-                            hit_stack.push(prop);
-                            extract_candidates(prop.value);
-                            hit_stack.pop();
-                        }
+                        hit_stack.push(prop);
+                        if (prop.key instanceof AST_Node) extract_candidates(prop.key);
+                        if (prop instanceof AST_ObjectKeyVal) extract_candidates(prop.value);
+                        hit_stack.pop();
                     });
                 } else if (expr instanceof AST_Sequence) {
                     expr.expressions.forEach(extract_candidates);
@@ -1799,7 +1798,7 @@ merge(Compressor.prototype, {
                 if (parent instanceof AST_Exit) return node;
                 if (parent instanceof AST_If) return node;
                 if (parent instanceof AST_IterationStatement) return node;
-                if (parent instanceof AST_ObjectKeyVal) return node;
+                if (parent instanceof AST_ObjectProperty) return node;
                 if (parent instanceof AST_PropAccess) return node;
                 if (parent instanceof AST_Sequence) {
                     return (parent.tail_node() === node ? find_stop : find_stop_unused)(parent, level + 1);
@@ -1857,7 +1856,7 @@ merge(Compressor.prototype, {
                     if (parent.condition !== node) return node;
                     return find_stop_value(parent, level + 1);
                 }
-                if (parent instanceof AST_ObjectKeyVal) {
+                if (parent instanceof AST_ObjectProperty) {
                     var obj = scanner.parent(level + 1);
                     return all(obj.properties, function(prop) {
                         return prop instanceof AST_ObjectKeyVal;
@@ -1905,7 +1904,7 @@ merge(Compressor.prototype, {
                 if (parent instanceof AST_Exit) return find_stop_unused(parent, level + 1);
                 if (parent instanceof AST_If) return find_stop_unused(parent, level + 1);
                 if (parent instanceof AST_IterationStatement) return node;
-                if (parent instanceof AST_ObjectKeyVal) {
+                if (parent instanceof AST_ObjectProperty) {
                     var obj = scanner.parent(level + 1);
                     return all(obj.properties, function(prop) {
                         return prop instanceof AST_ObjectKeyVal;
@@ -2699,9 +2698,12 @@ merge(Compressor.prototype, {
                 if (prop instanceof AST_Node) break;
                 prop = "" + prop;
                 var diff = prop == "__proto__" || compressor.has_directive("use strict") ? function(node) {
-                    return node.key != prop && node.key.name != prop;
+                    return typeof node.key == "string" && node.key != prop;
                 } : function(node) {
-                    return node.key.name != prop;
+                    if (node instanceof AST_ObjectGetter || node instanceof AST_ObjectSetter) {
+                        return typeof node.key == "string" && node.key != prop;
+                    }
+                    return true;
                 };
                 if (!all(value.properties, diff)) break;
                 value.properties.push(make_node(AST_ObjectKeyVal, node, {
@@ -2986,10 +2988,9 @@ merge(Compressor.prototype, {
         def(AST_Lambda, return_false);
         def(AST_Null, return_true);
         def(AST_Object, function(compressor) {
-            if (!is_strict(compressor)) return false;
-            for (var i = this.properties.length; --i >=0;)
-                if (this.properties[i].value instanceof AST_Accessor) return true;
-            return false;
+            return is_strict(compressor) && !all(this.properties, function(prop) {
+                return prop instanceof AST_ObjectKeyVal;
+            });
         });
         def(AST_Sequence, function(compressor) {
             return this.tail_node()._dot_throw(compressor);
@@ -3585,8 +3586,12 @@ merge(Compressor.prototype, {
                 var val = {};
                 for (var i = 0; i < this.properties.length; i++) {
                     var prop = this.properties[i];
+                    if (!(prop instanceof AST_ObjectKeyVal)) return this;
                     var key = prop.key;
-                    if (key instanceof AST_Symbol) key = key.name;
+                    if (key instanceof AST_Node) {
+                        key = key._eval(compressor, ignore_side_effects, cached, depth);
+                        if (key === prop.key) return this;
+                    }
                     if (prop.value instanceof AST_Function) {
                         if (typeof Object.prototype[key] == "function") return this;
                         continue;
@@ -4108,7 +4113,8 @@ merge(Compressor.prototype, {
             return any(this.properties, compressor);
         });
         def(AST_ObjectProperty, function(compressor) {
-            return this.value.has_side_effects(compressor);
+            return this.key instanceof AST_Node && this.key.has_side_effects(compressor)
+                || this.value.has_side_effects(compressor);
         });
         def(AST_Sub, function(compressor) {
             return this.expression.may_throw_on_access(compressor)
@@ -4220,7 +4226,8 @@ merge(Compressor.prototype, {
             return any(this.properties, compressor);
         });
         def(AST_ObjectProperty, function(compressor) {
-            return this.value.may_throw(compressor);
+            return this.key instanceof AST_Node && this.key.may_throw(compressor)
+                || this.value.may_throw(compressor);
         });
         def(AST_Return, function(compressor) {
             return this.value && this.value.may_throw(compressor);
@@ -4316,7 +4323,7 @@ merge(Compressor.prototype, {
             return all(this.properties);
         });
         def(AST_ObjectProperty, function() {
-            return this.value.is_constant_expression();
+            return typeof this.key == "string" && this.value.is_constant_expression();
         });
         def(AST_Unary, function() {
             return this.expression.is_constant_expression();
@@ -5742,7 +5749,7 @@ merge(Compressor.prototype, {
             return right instanceof AST_Object
                 && right.properties.length > 0
                 && all(right.properties, function(prop) {
-                    return prop instanceof AST_ObjectKeyVal;
+                    return prop instanceof AST_ObjectKeyVal && typeof prop.key == "string";
                 })
                 && all(def.references, function(ref) {
                     return ref.fixed_value() === right;
@@ -5932,12 +5939,14 @@ merge(Compressor.prototype, {
             return safe_to_drop(this, compressor) ? null : this;
         });
         def(AST_Object, function(compressor, first_in_statement) {
-            var values = trim(this.properties, compressor, first_in_statement);
+            var exprs = [];
+            this.properties.forEach(function(prop) {
+                if (prop.key instanceof AST_Node) exprs.push(prop.key);
+                exprs.push(prop.value);
+            });
+            var values = trim(exprs, compressor, first_in_statement);
             return values && make_sequence(this, values);
         });
-        def(AST_ObjectProperty, function(compressor, first_in_statement) {
-            return this.value.drop_side_effect_free(compressor, first_in_statement);
-        });
         def(AST_Sequence, function(compressor, first_in_statement) {
             var expressions = trim(this.expressions, compressor, first_in_statement);
             if (!expressions) return null;
@@ -9317,22 +9326,21 @@ merge(Compressor.prototype, {
             var props = expr.properties;
             for (var i = props.length; --i >= 0;) {
                 var prop = props[i];
-                if ("" + prop.key == key) {
-                    if (!all(props, function(prop) {
-                        return prop instanceof AST_ObjectKeyVal;
-                    })) break;
-                    if (!safe_to_flatten(prop.value, compressor)) break;
-                    return make_node(AST_Sub, this, {
-                        expression: make_node(AST_Array, expr, {
-                            elements: props.map(function(prop) {
-                                return prop.value;
-                            })
-                        }),
-                        property: make_node(AST_Number, this, {
-                            value: i
+                if (prop.key != key) continue;
+                if (!all(props, function(prop) {
+                    return prop instanceof AST_ObjectKeyVal && typeof prop.key == "string";
+                })) break;
+                if (!safe_to_flatten(prop.value, compressor)) break;
+                return make_node(AST_Sub, this, {
+                    expression: make_node(AST_Array, expr, {
+                        elements: props.map(function(prop) {
+                            return prop.value;
                         })
-                    });
-                }
+                    }),
+                    property: make_node(AST_Number, this, {
+                        value: i
+                    })
+                });
             }
         }
     });
@@ -9402,22 +9410,22 @@ merge(Compressor.prototype, {
         var keys = new Dictionary();
         var values = [];
         self.properties.forEach(function(prop) {
-            if (typeof prop.key != "string") {
-                flush();
-                values.push(prop);
-                return;
+            if (prop.key instanceof AST_Node) {
+                var key = prop.key.evaluate(compressor);
+                if (key !== prop.key) prop.key = "" + key;
             }
-            if (prop.value.has_side_effects(compressor)) {
+            if (prop instanceof AST_ObjectKeyVal && typeof prop.key == "string") {
+                if (prop.value.has_side_effects(compressor)) flush();
+                keys.add(prop.key, prop.value);
+            } else {
                 flush();
+                values.push(prop);
             }
-            keys.add(prop.key, prop.value);
         });
         flush();
-        if (self.properties.length != values.length) {
-            return make_node(AST_Object, self, {
-                properties: values
-            });
-        }
+        if (self.properties.length != values.length) return make_node(AST_Object, self, {
+            properties: values
+        });
         return self;
 
         function flush() {
index 1ce1692..3ceaf58 100644 (file)
                 value    : from_moz(M.value)
             };
             if (M.kind == "init") return new AST_ObjectKeyVal(args);
-            args.key = new AST_SymbolAccessor({
-                name: args.key
-            });
             args.value = new AST_Accessor(args.value);
             if (M.kind == "get") return new AST_ObjectGetter(args);
             if (M.kind == "set") return new AST_ObjectSetter(args);
     def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
         var key = {
             type: "Literal",
-            value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key
+            value: M.key
         };
         var kind;
         if (M instanceof AST_ObjectKeyVal) {
index ef1d41f..884cafc 100644 (file)
@@ -699,6 +699,7 @@ function OutputStream(options) {
             // (false, true) ? (a = 10, b = 20) : (c = 30)
             // ==> 20 (side effect, set a := 10 and b := 20)
             || p instanceof AST_Conditional
+            // { [(1, 2)]: 3 }[2] ==> 3
             // { foo: (1, 2) }.foo ==> 2
             || p instanceof AST_ObjectProperty
             // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
@@ -1289,25 +1290,33 @@ function OutputStream(options) {
         else print_braced_empty(this, output);
     });
 
-    function print_property_name(key, quote, output) {
-        if (output.option("quote_keys")) {
+    function print_property_key(self, output) {
+        var key = self.key;
+        if (key instanceof AST_Node) {
+            output.with_square(function() {
+                key.print(output);
+            });
+        } else if (output.option("quote_keys")) {
             output.print_string(key);
         } else if ("" + +key == key && key >= 0) {
             output.print(make_num(key));
-        } else if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
-            if (quote && output.option("keep_quoted_props")) {
-                output.print_string(key, quote);
+        } else {
+            var quote = self.start && self.start.quote;
+            if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
+                if (quote && output.option("keep_quoted_props")) {
+                    output.print_string(key, quote);
+                } else {
+                    output.print_name(key);
+                }
             } else {
-                output.print_name(key);
+                output.print_string(key, quote);
             }
-        } else {
-            output.print_string(key, quote);
         }
     }
 
     DEFPRINT(AST_ObjectKeyVal, function(output) {
         var self = this;
-        print_property_name(self.key, self.quote, output);
+        print_property_key(self, output);
         output.colon();
         self.value.print(output);
     });
@@ -1316,7 +1325,7 @@ function OutputStream(options) {
             var self = this;
             output.print(type);
             output.space();
-            print_property_name(self.key.name, self.quote, output);
+            print_property_key(self, output);
             self.value._codegen(output, true);
         };
     }
@@ -1488,14 +1497,7 @@ function OutputStream(options) {
         output.add_mapping(this.start);
     });
 
-    DEFMAP([
-        AST_ObjectGetter,
-        AST_ObjectSetter,
-     ], function(output) {
-        output.add_mapping(this.start, this.key.name);
-    });
-
     DEFMAP([ AST_ObjectProperty ], function(output) {
-        output.add_mapping(this.start, this.key);
+        if (typeof this.key == "string") output.add_mapping(this.start, this.key);
     });
 })();
index 84b1443..c91fb73 100644 (file)
@@ -1340,8 +1340,7 @@ function parse($TEXT, options) {
             // allow trailing comma
             if (!options.strict && is("punc", "}")) break;
             var start = S.token;
-            var type = start.type;
-            var name = as_property_name();
+            var key = as_property_key();
             if (is("punc", "(")) {
                 var func_start = S.token;
                 var func = function_(AST_Function);
@@ -1349,22 +1348,17 @@ function parse($TEXT, options) {
                 func.end = prev();
                 a.push(new AST_ObjectKeyVal({
                     start: start,
-                    quote: start.quote,
-                    key: "" + name,
+                    key: key,
                     value: func,
                     end: prev(),
                 }));
                 continue;
             }
-            if (!is("punc", ":") && type == "name") switch (name) {
+            if (!is("punc", ":") && start.type == "name") switch (key) {
               case "get":
                 a.push(new AST_ObjectGetter({
                     start: start,
-                    key: new AST_SymbolAccessor({
-                        start: S.token,
-                        name: "" + as_property_name(),
-                        end: prev(),
-                    }),
+                    key: as_property_key(),
                     value: create_accessor(),
                     end: prev(),
                 }));
@@ -1372,11 +1366,7 @@ function parse($TEXT, options) {
               case "set":
                 a.push(new AST_ObjectSetter({
                     start: start,
-                    key: new AST_SymbolAccessor({
-                        start: S.token,
-                        name: "" + as_property_name(),
-                        end: prev(),
-                    }),
+                    key: as_property_key(),
                     value: create_accessor(),
                     end: prev(),
                 }));
@@ -1384,8 +1374,7 @@ function parse($TEXT, options) {
               default:
                 a.push(new AST_ObjectKeyVal({
                     start: start,
-                    quote: start.quote,
-                    key: "" + name,
+                    key: key,
                     value: _make_symbol(AST_SymbolRef, start),
                     end: prev(),
                 }));
@@ -1394,8 +1383,7 @@ function parse($TEXT, options) {
             expect(":");
             a.push(new AST_ObjectKeyVal({
                 start: start,
-                quote: start.quote,
-                key: "" + name,
+                key: key,
                 value: expression(false),
                 end: prev(),
             }));
@@ -1404,7 +1392,7 @@ function parse($TEXT, options) {
         return new AST_Object({ properties: a });
     });
 
-    function as_property_name() {
+    function as_property_key() {
         var tmp = S.token;
         switch (tmp.type) {
           case "operator":
@@ -1415,7 +1403,13 @@ function parse($TEXT, options) {
           case "keyword":
           case "atom":
             next();
-            return tmp.value;
+            return "" + tmp.value;
+          case "punc":
+            if (tmp.value != "[") unexpected();
+            next();
+            var key = expression(false);
+            expect("]");
+            return key;
           default:
             unexpected();
         }
index e47497d..8079759 100644 (file)
@@ -81,8 +81,8 @@ var builtins = function() {
 
 function reserve_quoted_keys(ast, reserved) {
     ast.walk(new TreeWalker(function(node) {
-        if (node instanceof AST_ObjectKeyVal) {
-            if (node.quote) add(node.key);
+        if (node instanceof AST_ObjectProperty) {
+            if (node.start && node.start.quote) add(node.key);
         } else if (node instanceof AST_Sub) {
             addStrings(node.property, add);
         }
@@ -165,11 +165,8 @@ function mangle_properties(ast, options) {
             }
         } else if (node instanceof AST_Dot) {
             add(node.property);
-        } else if (node instanceof AST_ObjectKeyVal) {
-            add(node.key);
         } else if (node instanceof AST_ObjectProperty) {
-            // setter or getter, since KeyVal is handled above
-            add(node.key.name);
+            if (typeof node.key == "string") add(node.key);
         } else if (node instanceof AST_Sub) {
             addStrings(node.property, add);
         }
@@ -198,11 +195,8 @@ function mangle_properties(ast, options) {
             }
         } else if (node instanceof AST_Dot) {
             node.property = mangle(node.property);
-        } else if (node instanceof AST_ObjectKeyVal) {
-            node.key = mangle(node.key);
         } else if (node instanceof AST_ObjectProperty) {
-            // setter or getter
-            node.key.name = mangle(node.key.name);
+            if (typeof node.key == "string") node.key = mangle(node.key);
         } else if (node instanceof AST_Sub) {
             if (!options.keep_quoted) mangleStrings(node.property);
         }
index 13598ea..4aeb0f0 100644 (file)
@@ -164,6 +164,7 @@ TreeTransformer.prototype = new TreeWalker;
         self.properties = do_list(self.properties, tw);
     });
     DEF(AST_ObjectProperty, function(self, tw) {
+        if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
         self.value = self.value.transform(tw);
     });
 })(function(node, descend) {
index fb1e586..3fb6ec0 100644 (file)
@@ -221,3 +221,38 @@ numeric_literal: {
         "8 7 8",
     ]
 }
+
+evaluate_computed_key: {
+    options = {
+        evaluate: true,
+        objects: true,
+    }
+    input: {
+        console.log({
+            ["foo" + "bar"]: "PASS",
+        }.foobar);
+    }
+    expect: {
+        console.log({
+            foobar: "PASS",
+        }.foobar);
+    }
+    expect_stdout: "PASS"
+    node_version: ">=4"
+}
+
+keep_computed_key: {
+    options = {
+        side_effects: true,
+    }
+    input: {
+        ({
+            [console.log("PASS")]: 42,
+        });
+    }
+    expect: {
+        console.log("PASS");
+    }
+    expect_stdout: "PASS"
+    node_version: ">=4"
+}
index 6241f25..4a495b5 100644 (file)
@@ -5,7 +5,7 @@ describe("tokens", function() {
     it("Should give correct positions for accessors", function() {
         // location               0         1         2         3         4
         //                        01234567890123456789012345678901234567890123456789
-        var ast = UglifyJS.parse("var obj = { get latest() { return undefined; } }");
+        var ast = UglifyJS.parse("var obj = { get [prop]() { return undefined; } }");
         // test all AST_ObjectProperty tokens are set as expected
         var found = false;
         ast.walk(new UglifyJS.TreeWalker(function(node) {
@@ -13,9 +13,9 @@ describe("tokens", function() {
                 found = true;
                 assert.equal(node.start.pos, 12);
                 assert.equal(node.end.endpos, 46);
-                assert(node.key instanceof UglifyJS.AST_SymbolAccessor);
-                assert.equal(node.key.start.pos, 16);
-                assert.equal(node.key.end.endpos, 22);
+                assert(node.key instanceof UglifyJS.AST_SymbolRef);
+                assert.equal(node.key.start.pos, 17);
+                assert.equal(node.key.end.endpos, 21);
                 assert(node.value instanceof UglifyJS.AST_Accessor);
                 assert.equal(node.value.start.pos, 22);
                 assert.equal(node.value.end.endpos, 46);
index f158854..82fdc37 100644 (file)
@@ -913,14 +913,18 @@ function getDotKey(assign) {
     return key;
 }
 
-function createObjectFunction(type, recurmax, stmtDepth, canThrow) {
+function createObjectKey(recurmax, stmtDepth, canThrow) {
+    return rng(10) ? KEYS[rng(KEYS.length)] : "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]";
+}
+
+function createObjectFunction(recurmax, stmtDepth, canThrow) {
     var namesLenBefore = VAR_NAMES.length;
     var s;
     createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
-        switch (type) {
-          case "get":
+        switch (rng(3)) {
+          case 0:
             s = [
-                "get " + getDotKey() + "(){",
+                "get " + createObjectKey(recurmax, stmtDepth, canThrow) + "(){",
                 strictMode(),
                 defns(),
                 _createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
@@ -928,8 +932,8 @@ function createObjectFunction(type, recurmax, stmtDepth, canThrow) {
                 "},",
             ];
             break;
-          case "set":
-            var prop1 = getDotKey();
+          case 1:
+            var prop1 = createObjectKey(recurmax, stmtDepth, canThrow);
             var prop2;
             do {
                 prop2 = getDotKey();
@@ -945,7 +949,7 @@ function createObjectFunction(type, recurmax, stmtDepth, canThrow) {
             break;
           default:
             s = [
-                type + "(" + createParams(NO_DUPLICATE) + "){",
+                createObjectKey(recurmax, stmtDepth, canThrow) + "(" + createParams(NO_DUPLICATE) + "){",
                 strictMode(),
                 defns(),
                 _createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
@@ -961,21 +965,15 @@ function createObjectFunction(type, recurmax, stmtDepth, canThrow) {
 function createObjectLiteral(recurmax, stmtDepth, canThrow) {
     recurmax--;
     var obj = ["({"];
-    for (var i = rng(6); --i >= 0;) switch (rng(50)) {
+    for (var i = rng(6); --i >= 0;) switch (rng(30)) {
       case 0:
-        obj.push(createObjectFunction("get", recurmax, stmtDepth, canThrow));
+        obj.push(createObjectFunction(recurmax, stmtDepth, canThrow));
         break;
       case 1:
-        obj.push(createObjectFunction("set", recurmax, stmtDepth, canThrow));
-        break;
-      case 2:
-        obj.push(createObjectFunction(KEYS[rng(KEYS.length)], recurmax, stmtDepth, canThrow));
-        break;
-      case 3:
         obj.push(getVarName() + ",");
         break;
       default:
-        obj.push(KEYS[rng(KEYS.length)] + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
+        obj.push(createObjectKey(recurmax, stmtDepth, canThrow) + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "),");
         break;
     }
     obj.push("})");