Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-12070] Fixed a bug with calling new Object(void 0) #234

Merged
merged 11 commits into from
Aug 22, 2013
Merged
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
* Fixed a bug where eval, parseInt, etc had a prototype when they weren't supposed to.
* Fixed a bug where passing a hex string into parseInt was being parsed as decimal
* Fixed a bug with decode/encode URI methods not handling exceptions properly
* Fixed a bug where explicitly passing null or undefined to new Object() improperly threw an exception
* Fixed a bug where the builtin global constructors had their prototype defined twice
* Fixed a bug where strings were not handling numerical property access correctly
* Fixed a bug where the built-in global object's properties enumerable flags weren't being set properly

### Miscellany
* Merged the require-provider and common-globals plugins into the ti-api-provider
Expand Down
168 changes: 108 additions & 60 deletions lib/Base.js
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,8 @@ function NumberType(initialValue, className) {

Object.defineProperty(this, 'objectPrototype', {
get: function () {
return proto || prototypes.Number;
var p = proto || prototypes.Number;
return p == this ? undefined : p;
},
set: function (value) {
proto = value;
Expand Down Expand Up @@ -470,7 +471,8 @@ function BooleanType(initialValue, className) {

Object.defineProperty(this, 'objectPrototype', {
get: function () {
return proto || prototypes.Boolean;
var p = proto || prototypes.Boolean;
return p == this ? undefined : p;
},
set: function (value) {
proto = value;
Expand Down Expand Up @@ -529,7 +531,8 @@ function StringType(initialValue, className) {

Object.defineProperty(this, 'objectPrototype', {
get: function () {
return proto || prototypes.String;
var p = proto || prototypes.String;
return p == this ? undefined : p;
},
set: function (value) {
proto = value;
Expand Down Expand Up @@ -730,7 +733,8 @@ function ObjectType(className, value) {
// Step 4
Object.defineProperty(this, 'objectPrototype', {
get: function () {
return proto || prototypes.Object;
var p = proto || prototypes.Object;
return p == this ? undefined : p;
},
set: function (value) {
proto = value;
Expand Down Expand Up @@ -1268,7 +1272,8 @@ function ArrayType(className) {

Object.defineProperty(this, 'objectPrototype', {
get: function () {
return proto || prototypes.Array;
var p = proto || prototypes.Array;
return p == this ? undefined : p;
},
set: function (value) {
proto = value;
Expand Down Expand Up @@ -1358,7 +1363,8 @@ function RegExpType(pattern, flags, className) {

Object.defineProperty(this, 'objectPrototype', {
get: function () {
return proto || prototypes.RegExp;
var p = proto || prototypes.RegExp;
return p == this ? undefined : p;
},
set: function (value) {
proto = value;
Expand Down Expand Up @@ -1451,7 +1457,8 @@ function FunctionTypeBase(length, className, dontCreatePrototype) {
// Step 4
Object.defineProperty(this, 'objectPrototype', {
get: function () {
return proto || prototypes.Function;
var p = proto || prototypes.Function;
return p == this ? undefined : p;
},
set: function (value) {
proto = value;
Expand Down Expand Up @@ -6282,7 +6289,7 @@ wrapNativeCall
* @see ECMA-262 Spec Chapter 15.7
*/
function NumberConstructor(className) {
FunctionTypeBase.call(this, 1, className || 'Function');
FunctionTypeBase.call(this, 1, className || 'Function', true);

this.defineOwnProperty('prototype', {
value: prototypes.Number
Expand Down Expand Up @@ -6358,7 +6365,7 @@ wrapNativeCall
* @see ECMA-262 Spec Chapter 15.6
*/
function BooleanConstructor(className) {
FunctionTypeBase.call(this, 1, className || 'Function');
FunctionTypeBase.call(this, 1, className || 'Function', true);

this.defineOwnProperty('prototype', {
value: prototypes.Boolean
Expand Down Expand Up @@ -6413,7 +6420,8 @@ StringType,
toString,
ObjectType,
NumberType,
wrapNativeCall
wrapNativeCall,
addNonEnumerableProperty
*/

/*****************************************
Expand Down Expand Up @@ -6455,16 +6463,16 @@ StringFromCharCodeFunc.prototype.callFunction = wrapNativeCall(function callFunc
* String constructor function
*
* @private
* @see ECMA-262 Spec Chapter 15.5
* @see ECMA-262 Spec Chapter 15.5, 15.5.5.2
*/
function StringConstructor(className) {
FunctionTypeBase.call(this, 1, className || 'Function');
FunctionTypeBase.call(this, 1, className || 'Function', true);

this.defineOwnProperty('prototype', {
value: prototypes.String
}, false, true);

this.put('fromCharCode', new StringFromCharCodeFunc(), false, true);
addNonEnumerableProperty(this, 'fromCharCode', new StringFromCharCodeFunc());
}
util.inherits(StringConstructor, FunctionTypeBase);
StringConstructor.prototype.callFunction = wrapNativeCall(function callFunction(thisVal, args) {
Expand Down Expand Up @@ -6496,6 +6504,42 @@ StringConstructor.prototype.construct = wrapNativeCall(function construct(args)

obj.defineOwnProperty('length', { value: new NumberType(obj.primitiveValue.length) }, false, true);

obj._getOwnProperty = obj.getOwnProperty;

// From the spec 15.5.5.2
obj.getOwnProperty = function getOwnProperty(p) {

// Step 1
var desc = this._getOwnProperty(p),
index;

// Step 2
if (desc) {
return desc;
}

// Step 5
index = +p;

// Step 4
if (Math.abs(index) + '' !== p) {
return;
}

// Step 7
if (index >= this.primitiveValue.length) {
return;
}

// Steps 8-9
return {
value: new StringType(this.primitiveValue[index]),
enumerable: true,
writable: true,
configurable: true
};
};

Object.defineProperty(obj, 'objectPrototype', {
get: function () {
return prototypes.String;
Expand All @@ -6515,7 +6559,6 @@ BooleanType,
prototypes,
type,
handleRecoverableNativeException,
UndefinedType,
toString,
fromPropertyDescriptor,
ArrayType,
Expand All @@ -6525,7 +6568,9 @@ toObject,
isDataDescriptor,
StringType,
isType,
wrapNativeCall
wrapNativeCall,
addNonEnumerableProperty,
NullType
*/

/*****************************************
Expand Down Expand Up @@ -6558,7 +6603,7 @@ ObjectGetPrototypeOfFunc.prototype.callFunction = wrapNativeCall(function callFu
handleRecoverableNativeException('TypeError', 'Value is not an object');
return new UnknownType();
}
return o.objectPrototype ? o.objectPrototype : new UndefinedType();
return o.objectPrototype ? o.objectPrototype : new NullType();
});

/**
Expand Down Expand Up @@ -7054,25 +7099,25 @@ ObjectKeysFunc.prototype.callFunction = wrapNativeCall(function callFunction(thi
* @see ECMA-262 Spec Chapter 15.2
*/
function ObjectConstructor(className) {
FunctionTypeBase.call(this, 1, className || 'Function');
FunctionTypeBase.call(this, 1, className || 'Function', true);

this.defineOwnProperty('prototype', {
value: prototypes.Object
}, false, true);

this.put('getPrototypeOf', new ObjectGetPrototypeOfFunc(), false, true);
this.put('getOwnPropertyDescriptor', new ObjectGetOwnPropertyDescriptorFunc(), false, true);
this.put('getOwnPropertyNames', new ObjectGetOwnPropertyNamesFunc(), false, true);
this.put('create', new ObjectCreateFunc(), false, true);
this.put('defineProperty', new ObjectDefinePropertyFunc(), false, true);
this.put('defineProperties', new ObjectDefinePropertiesFunc(), false, true);
this.put('seal', new ObjectSealFunc(), false, true);
this.put('freeze', new ObjectFreezeFunc(), false, true);
this.put('preventExtensions', new ObjectPreventExtensionsFunc(), false, true);
this.put('isSealed', new ObjectIsSealedFunc(), false, true);
this.put('isFrozen', new ObjectIsFrozenFunc(), false, true);
this.put('isExtensible', new ObjectIsExtensibleFunc(), false, true);
this.put('keys', new ObjectKeysFunc(), false, true);
addNonEnumerableProperty(this, 'getPrototypeOf', new ObjectGetPrototypeOfFunc());
addNonEnumerableProperty(this, 'getOwnPropertyDescriptor', new ObjectGetOwnPropertyDescriptorFunc());
addNonEnumerableProperty(this, 'getOwnPropertyNames', new ObjectGetOwnPropertyNamesFunc());
addNonEnumerableProperty(this, 'create', new ObjectCreateFunc());
addNonEnumerableProperty(this, 'defineProperty', new ObjectDefinePropertyFunc());
addNonEnumerableProperty(this, 'defineProperties', new ObjectDefinePropertiesFunc());
addNonEnumerableProperty(this, 'seal', new ObjectSealFunc());
addNonEnumerableProperty(this, 'freeze', new ObjectFreezeFunc());
addNonEnumerableProperty(this, 'preventExtensions', new ObjectPreventExtensionsFunc());
addNonEnumerableProperty(this, 'isSealed', new ObjectIsSealedFunc());
addNonEnumerableProperty(this, 'isFrozen', new ObjectIsFrozenFunc());
addNonEnumerableProperty(this, 'isExtensible', new ObjectIsExtensibleFunc());
addNonEnumerableProperty(this, 'keys', new ObjectKeysFunc());
}
util.inherits(ObjectConstructor, FunctionTypeBase);
ObjectConstructor.prototype.callFunction = wrapNativeCall(function callFunction(thisVal, args) {
Expand Down Expand Up @@ -7104,7 +7149,7 @@ ObjectConstructor.prototype.construct = wrapNativeCall(function construct(args)
}

// Step 1
if (value && (isType(value, ['Undefined', 'Null']))) {
if (value && (!isType(value, ['Undefined', 'Null']))) {
if (type(value) === 'Object') {
return value;
} else {
Expand All @@ -7127,6 +7172,7 @@ prototypes,
ArrayType,
toUint32,
handleRecoverableNativeException,
addNonEnumerableProperty,
NumberType,
wrapNativeCall
*/
Expand Down Expand Up @@ -7168,13 +7214,13 @@ ArrayIsArrayFunc.prototype.callFunction = wrapNativeCall(function callFunction(t
* @see ECMA-262 Spec Chapter 15.4
*/
function ArrayConstructor(className) {
FunctionTypeBase.call(this, 1, className || 'Function');
FunctionTypeBase.call(this, 1, className || 'Function', true);

this.defineOwnProperty('prototype', {
value: prototypes.Array
}, false, true);

this.put('isArray', new ArrayIsArrayFunc(), false, true);
addNonEnumerableProperty(this, 'isArray', new ArrayIsArrayFunc());
}
util.inherits(ArrayConstructor, FunctionTypeBase);
ArrayConstructor.prototype.callFunction = wrapNativeCall(function callFunction(thisVal, args) {
Expand Down Expand Up @@ -7258,7 +7304,7 @@ wrapNativeCall
* @see ECMA-262 Spec Chapter 15.10
*/
function RegExpConstructor(className) {
FunctionTypeBase.call(this, 2, className || 'Function');
FunctionTypeBase.call(this, 2, className || 'Function', true);

this.defineOwnProperty('prototype', {
value: prototypes.RegExp
Expand Down Expand Up @@ -7340,7 +7386,7 @@ wrapNativeCall
* @see ECMA-262 Spec Chapter 15.3
*/
function FunctionConstructor(className) {
FunctionTypeBase.call(this, 1, className || 'Function');
FunctionTypeBase.call(this, 1, className || 'Function', true);

this.defineOwnProperty('prototype', {
value: prototypes.Function
Expand Down Expand Up @@ -7435,7 +7481,7 @@ wrapNativeCall
*/
exports.ErrorConstructor = ErrorConstructor;
function ErrorConstructor(errorType, className) {
FunctionTypeBase.call(this, 1, className || 'Function');
FunctionTypeBase.call(this, 1, className || 'Function', true);

this.defineOwnProperty('prototype', {
value: prototypes[errorType]
Expand Down Expand Up @@ -7486,6 +7532,7 @@ ErrorConstructor.prototype.construct = wrapNativeCall(function construct(args) {
util,
Runtime,
FunctionTypeBase,
addNonEnumerableProperty,
UnknownType,
prototypes,
NumberType,
Expand Down Expand Up @@ -7555,15 +7602,15 @@ DateNowFunc.prototype.callFunction = wrapNativeCall(function callFunction() {
* @see ECMA-262 Spec Chapter 15.9
*/
function DateConstructor(className) {
FunctionTypeBase.call(this, 7, className || 'Function');
FunctionTypeBase.call(this, 7, className || 'Function', true);

this.defineOwnProperty('prototype', {
value: prototypes.Date
}, false, true);

this.put('parse', new DateParseFunc(), false, true);
this.put('UTC', new DateUTCFunc(), false, true);
this.put('now', new DateNowFunc(), false, true);
addNonEnumerableProperty(this, 'parse', new DateParseFunc());
addNonEnumerableProperty(this, 'UTC', new DateUTCFunc());
addNonEnumerableProperty(this, 'now', new DateNowFunc());
}
util.inherits(DateConstructor, FunctionTypeBase);
DateConstructor.prototype.callFunction = wrapNativeCall(function callFunction() {
Expand Down Expand Up @@ -9491,6 +9538,7 @@ toNumber,
StringType,
ObjectType,
addReadOnlyProperty,
addNonEnumerableProperty,
NullType,
ArrayType,
isCallable,
Expand Down Expand Up @@ -10328,24 +10376,24 @@ function MathObject(className) {
addReadOnlyProperty(this, 'SQRT2', new NumberType(Math.SQRT2));

// Methods
this.put('abs', new MathAbsFunc(), false, true);
this.put('acos', new MathAcosFunc(), false, true);
this.put('asin', new MathAsinFunc(), false, true);
this.put('atan', new MathAtanFunc(), false, true);
this.put('atan2', new MathAtan2Func(), false, true);
this.put('ceil', new MathCeilFunc(), false, true);
this.put('cos', new MathCosFunc(), false, true);
this.put('exp', new MathExpFunc(), false, true);
this.put('floor', new MathFloorFunc(), false, true);
this.put('log', new MathLogFunc(), false, true);
this.put('max', new MathMaxFunc(), false, true);
this.put('min', new MathMinFunc(), false, true);
this.put('pow', new MathPowFunc(), false, true);
this.put('random', new MathRandomFunc(), false, true);
this.put('round', new MathRoundFunc(), false, true);
this.put('sin', new MathSinFunc(), false, true);
this.put('sqrt', new MathSqrtFunc(), false, true);
this.put('tan', new MathTanFunc(), false, true);
addNonEnumerableProperty(this, 'abs', new MathAbsFunc());
addNonEnumerableProperty(this, 'acos', new MathAcosFunc());
addNonEnumerableProperty(this, 'asin', new MathAsinFunc());
addNonEnumerableProperty(this, 'atan', new MathAtanFunc());
addNonEnumerableProperty(this, 'atan2', new MathAtan2Func());
addNonEnumerableProperty(this, 'ceil', new MathCeilFunc());
addNonEnumerableProperty(this, 'cos', new MathCosFunc());
addNonEnumerableProperty(this, 'exp', new MathExpFunc());
addNonEnumerableProperty(this, 'floor', new MathFloorFunc());
addNonEnumerableProperty(this, 'log', new MathLogFunc());
addNonEnumerableProperty(this, 'max', new MathMaxFunc());
addNonEnumerableProperty(this, 'min', new MathMinFunc());
addNonEnumerableProperty(this, 'pow', new MathPowFunc());
addNonEnumerableProperty(this, 'random', new MathRandomFunc());
addNonEnumerableProperty(this, 'round', new MathRoundFunc());
addNonEnumerableProperty(this, 'sin', new MathSinFunc());
addNonEnumerableProperty(this, 'sqrt', new MathSqrtFunc());
addNonEnumerableProperty(this, 'tan', new MathTanFunc());
}
util.inherits(MathObject, ObjectType);

Expand Down Expand Up @@ -10734,8 +10782,8 @@ JSONStringifyFunc.prototype.callFunction = wrapNativeCall(function callFunction(
function JSONObject(className) {
ObjectType.call(this, className);

this.put('parse', new JSONParseFunc(), false, true);
this.put('stringify', new JSONStringifyFunc(), false, true);
addNonEnumerableProperty(this, 'parse', new JSONParseFunc());
addNonEnumerableProperty(this, 'stringify', new JSONStringifyFunc());
}
util.inherits(JSONObject, ObjectType);

Expand Down