268 lines
6.2 KiB
JavaScript
268 lines
6.2 KiB
JavaScript
|
// Copyright 2015 the V8 project authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
// Flags: --strong-mode --allow-natives-syntax
|
||
|
|
||
|
function getSloppyArguments() {
|
||
|
return arguments;
|
||
|
}
|
||
|
|
||
|
function getObjects() {
|
||
|
"use strict";
|
||
|
return [
|
||
|
{},
|
||
|
Object(""),
|
||
|
[],
|
||
|
(function(){}),
|
||
|
(class Foo {}),
|
||
|
getSloppyArguments(),
|
||
|
arguments,
|
||
|
new Date()
|
||
|
];
|
||
|
}
|
||
|
|
||
|
//TODO(conradw): add tests for non-inheritance once semantics are implemented.
|
||
|
function getNonInheritingObjects() {
|
||
|
"use strong";
|
||
|
return [
|
||
|
Object(""),
|
||
|
[],
|
||
|
new Uint32Array(0)
|
||
|
];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementSloppy(o) {
|
||
|
return o[0];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementSparseSloppy(o) {
|
||
|
return o[100000];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementNonSmiSloppy(o) {
|
||
|
return o[3000000000];
|
||
|
}
|
||
|
|
||
|
function readFromObjectNonIndexSloppy(o) {
|
||
|
return o[5000000000];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementVarSloppy(o) {
|
||
|
var a = 0;
|
||
|
return o[a];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementSparseVarSloppy(o) {
|
||
|
var a = 100000;
|
||
|
return o[a];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementNonSmiVarSloppy(o) {
|
||
|
var a = 3000000000;
|
||
|
return o[a];
|
||
|
}
|
||
|
|
||
|
function readFromObjectNonIndexVarSloppy(o) {
|
||
|
var a = 5000000000;
|
||
|
return o[a];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementStrong(o) {
|
||
|
"use strong";
|
||
|
return o[0];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementSparseStrong(o) {
|
||
|
"use strong";
|
||
|
return o[100000];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementNonSmiStrong(o) {
|
||
|
"use strong";
|
||
|
return o[3000000000];
|
||
|
}
|
||
|
|
||
|
function readFromObjectNonIndexStrong(o) {
|
||
|
"use strong";
|
||
|
return o[5000000000];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementLetStrong(o) {
|
||
|
"use strong";
|
||
|
let a = 0;
|
||
|
return o[a];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementSparseLetStrong(o) {
|
||
|
"use strong";
|
||
|
let a = 100000;
|
||
|
return o[a];
|
||
|
}
|
||
|
|
||
|
function readFromObjectElementNonSmiLetStrong(o) {
|
||
|
"use strong";
|
||
|
let a = 3000000000;
|
||
|
return o[a];
|
||
|
}
|
||
|
|
||
|
function readFromObjectNonIndexLetStrong(o) {
|
||
|
"use strong";
|
||
|
let a = 5000000000;
|
||
|
return o[a];
|
||
|
}
|
||
|
|
||
|
function getDescs(x) {
|
||
|
return [
|
||
|
{value: x},
|
||
|
{configurable: true, enumerable: true, writable: true, value: x},
|
||
|
{configurable: true, enumerable: true, get: (function() {return x}) },
|
||
|
];
|
||
|
}
|
||
|
|
||
|
function assertStrongSemantics(func, object) {
|
||
|
%DeoptimizeFunction(func);
|
||
|
%ClearFunctionTypeFeedback(func);
|
||
|
assertThrows(function(){func(object)}, TypeError);
|
||
|
assertThrows(function(){func(object)}, TypeError);
|
||
|
assertThrows(function(){func(object)}, TypeError);
|
||
|
%OptimizeFunctionOnNextCall(func);
|
||
|
assertThrows(function(){func(object)}, TypeError);
|
||
|
%DeoptimizeFunction(func);
|
||
|
assertThrows(function(){func(object)}, TypeError);
|
||
|
}
|
||
|
|
||
|
function assertSloppySemantics(func, object) {
|
||
|
%DeoptimizeFunction(func);
|
||
|
%ClearFunctionTypeFeedback(func);
|
||
|
assertDoesNotThrow(function(){func(object)});
|
||
|
assertDoesNotThrow(function(){func(object)});
|
||
|
assertDoesNotThrow(function(){func(object)});
|
||
|
%OptimizeFunctionOnNextCall(func);
|
||
|
assertDoesNotThrow(function(){func(object)});
|
||
|
%DeoptimizeFunction(func);
|
||
|
assertDoesNotThrow(function(){func(object)});
|
||
|
}
|
||
|
|
||
|
(function () {
|
||
|
"use strict";
|
||
|
|
||
|
let goodKeys = [
|
||
|
"0",
|
||
|
"100000",
|
||
|
"3000000000",
|
||
|
"5000000000"
|
||
|
]
|
||
|
|
||
|
let badKeys = [
|
||
|
"bar",
|
||
|
"1",
|
||
|
"100001",
|
||
|
"3000000001",
|
||
|
"5000000001"
|
||
|
];
|
||
|
|
||
|
let values = [
|
||
|
"string",
|
||
|
1,
|
||
|
100001,
|
||
|
30000000001,
|
||
|
50000000001,
|
||
|
NaN,
|
||
|
{},
|
||
|
undefined
|
||
|
];
|
||
|
|
||
|
let literals = [0, NaN, true, ""];
|
||
|
|
||
|
let badAccessorDescs = [
|
||
|
{ set: (function(){}) },
|
||
|
{ configurable: true, enumerable: true, set: (function(){}) }
|
||
|
];
|
||
|
|
||
|
let readSloppy = [
|
||
|
readFromObjectElementSloppy,
|
||
|
readFromObjectElementSparseSloppy,
|
||
|
readFromObjectElementNonSmiSloppy,
|
||
|
readFromObjectNonIndexSloppy,
|
||
|
readFromObjectElementVarSloppy,
|
||
|
readFromObjectElementSparseVarSloppy,
|
||
|
readFromObjectElementNonSmiVarSloppy,
|
||
|
readFromObjectNonIndexVarSloppy
|
||
|
];
|
||
|
|
||
|
let readStrong = [
|
||
|
readFromObjectElementStrong,
|
||
|
readFromObjectElementSparseStrong,
|
||
|
readFromObjectElementNonSmiStrong,
|
||
|
readFromObjectNonIndexStrong,
|
||
|
readFromObjectElementLetStrong,
|
||
|
readFromObjectElementSparseLetStrong,
|
||
|
readFromObjectElementNonSmiLetStrong,
|
||
|
readFromObjectNonIndexLetStrong
|
||
|
];
|
||
|
|
||
|
let dummyProto = {};
|
||
|
for (let key of goodKeys) {
|
||
|
Object.defineProperty(dummyProto, key, { value: undefined });
|
||
|
}
|
||
|
|
||
|
let dummyAccessorProto = {};
|
||
|
for (let key of goodKeys) {
|
||
|
Object.defineProperty(dummyAccessorProto, key, { set: (function(){}) })
|
||
|
}
|
||
|
|
||
|
// String literals/objects should not throw on character index access
|
||
|
assertDoesNotThrow(function() {"use strong"; return "string"[0]; });
|
||
|
assertDoesNotThrow(function() {"use strong"; return Object("string")[0]; });
|
||
|
|
||
|
// Attempting to access a property on an object with no defined properties
|
||
|
// should throw.
|
||
|
for (let object of getObjects().concat(getNonInheritingObjects(), literals)) {
|
||
|
for (let func of readStrong) {
|
||
|
assertStrongSemantics(func, object);
|
||
|
}
|
||
|
for (let func of readSloppy) {
|
||
|
assertSloppySemantics(func, object);
|
||
|
}
|
||
|
}
|
||
|
for (let object of getObjects()) {
|
||
|
// Accessing a property which is on the prototype chain of the object should
|
||
|
// not throw.
|
||
|
object.__proto__ = dummyProto;
|
||
|
for (let key of goodKeys) {
|
||
|
for (let func of readStrong.concat(readSloppy)) {
|
||
|
assertSloppySemantics(func, object);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Properties with accessor descriptors missing 'get' should throw on access.
|
||
|
for (let desc of badAccessorDescs) {
|
||
|
for (let key of goodKeys) {
|
||
|
for (let object of getObjects()) {
|
||
|
Object.defineProperty(object, key, desc);
|
||
|
for (let func of readStrong) {
|
||
|
assertStrongSemantics(func, object);
|
||
|
}
|
||
|
for (let func of readSloppy) {
|
||
|
assertSloppySemantics(func, object);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// The same behaviour should be expected for bad accessor properties on the
|
||
|
// prototype chain.
|
||
|
for (let object of getObjects()) {
|
||
|
object.__proto__ = dummyAccessorProto;
|
||
|
for (let func of readStrong) {
|
||
|
assertStrongSemantics(func, object);
|
||
|
}
|
||
|
for (let func of readSloppy) {
|
||
|
assertSloppySemantics(func, object);
|
||
|
}
|
||
|
}
|
||
|
assertThrows(function(){"use strong"; typeof ({})[1];}, TypeError);
|
||
|
assertThrows(
|
||
|
function(){"use strong"; typeof ({})[1] === "undefined"}, TypeError);
|
||
|
})();
|