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

Constant pool #160

Merged
merged 7 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions libraries/analysis-javascript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export * from "./lib/ast/defaultBabelConfig";
export * from "./lib/cfg/ControlFlowGraphFactory";
export * from "./lib/cfg/ControlFlowGraphVisitor";

export * from "./lib/constant/ConstantPool";
export * from "./lib/constant/ConstantPoolManager";
export * from "./lib/constant/ConstantVisitor";

export * from "./lib/dependency/DependencyFactory";
export * from "./lib/dependency/DependencyVisitor";

Expand Down
165 changes: 165 additions & 0 deletions libraries/analysis-javascript/lib/constant/ConstantPool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* Copyright 2020-2023 Delft University of Technology and SynTest contributors
*
* This file is part of SynTest Framework - SynTest JavaScript.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { prng } from "@syntest/prng";

export class ConstantPool {
protected _numericPool: Map<number, number>;
protected _integerPool: Map<number, number>;
protected _bigIntPool: Map<bigint, number>;
protected _stringPool: Map<string, number>;
protected _numericCount: number;
protected _integerCount: number;
protected _bigIntCount: number;
protected _stringCount: number;

constructor() {
this._numericPool = new Map();
this.addNumeric(Math.PI);
this.addNumeric(Math.E);
this.addNumeric(-1);
this.addNumeric(0);
this.addNumeric(+1);

this._integerPool = new Map();
this.addInteger(-1);
this.addInteger(0);
this.addInteger(+1);

this._bigIntPool = new Map();

this._stringPool = new Map();
this.addString("");
}

public addNumeric(value: number): void {
if (this._numericPool.has(value)) {
this._numericPool.set(value, this._numericPool.get(value) + 1);
} else {
this._numericPool.set(value, 1);
}
this._numericCount++;
}

public addInteger(value: number): void {
if (this._integerPool.has(value)) {
this._integerPool.set(value, this._integerPool.get(value) + 1);
} else {
this._integerPool.set(value, 1);
}
this._integerCount++;
}

public addBigInt(value: bigint): void {
if (this._bigIntPool.has(value)) {
this._bigIntPool.set(value, this._bigIntPool.get(value) + 1);
} else {
this._bigIntPool.set(value, 1);
}
this._bigIntCount++;
}

public addString(value: string): void {
if (this._stringPool.has(value)) {
this._stringPool.set(value, this._stringPool.get(value) + 1);
} else {
this._stringPool.set(value, 1);
}
this._stringCount++;
}

public getRandomNumeric(frequencyBased = false): number {
if (this._numericPool.size === 0) {
return undefined;
}

if (frequencyBased) {
let index = prng.nextDouble() * this._numericCount;
for (const [value, frequency] of this._numericPool.entries()) {
if (index >= frequency) {
return value;
} else {
index -= frequency;
}
}
return prng.pickOne([...this._numericPool.keys()]);
} else {
return prng.pickOne([...this._numericPool.keys()]);
}
}

public getRandomInteger(frequencyBased = false): number {
if (this._integerPool.size === 0) {
return undefined;
}

if (frequencyBased) {
let index = prng.nextDouble() * this._integerCount;
for (const [value, frequency] of this._integerPool.entries()) {
if (index >= frequency) {
return value;
} else {
index -= frequency;
}
}
return prng.pickOne([...this._integerPool.keys()]);
} else {
return prng.pickOne([...this._integerPool.keys()]);
}
}

public getRandomBigInt(frequencyBased = false): bigint {
if (this._bigIntPool.size === 0) {
return undefined;
}

if (frequencyBased) {
let index = prng.nextDouble() * this._bigIntCount;
for (const [value, frequency] of this._bigIntPool.entries()) {
if (index >= frequency) {
return value;
} else {
index -= frequency;
}
}
return prng.pickOne([...this._bigIntPool.keys()]);
} else {
return prng.pickOne([...this._bigIntPool.keys()]);
}
}

public getRandomString(frequencyBased = false): string {
if (this._stringPool.size === 0) {
return undefined;
}

if (frequencyBased) {
let index = prng.nextDouble() * this._stringCount;
for (const [value, frequency] of this._stringPool.entries()) {
if (index >= frequency) {
return value;
} else {
index -= frequency;
}
}
return prng.pickOne([...this._stringPool.keys()]);
} else {
return prng.pickOne([...this._stringPool.keys()]);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2020-2023 Delft University of Technology and SynTest contributors
*
* This file is part of SynTest Framework - SynTest JavaScript.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { ConstantPool } from "./ConstantPool";

export class ConstantPoolManager {
protected _targetConstantPool: ConstantPool;
protected _contextConstantPool: ConstantPool;
protected _dynamicConstantPool: ConstantPool;

constructor() {
this._targetConstantPool = new ConstantPool();
this._contextConstantPool = new ConstantPool();
this._dynamicConstantPool = new ConstantPool();
}

public get targetConstantPool(): ConstantPool {
return this._targetConstantPool;
}

public get contextConstantPool(): ConstantPool {
return this._contextConstantPool;
}

public get dynamicConstantPool(): ConstantPool {
return this._dynamicConstantPool;
}
}
75 changes: 75 additions & 0 deletions libraries/analysis-javascript/lib/constant/ConstantVisitor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2020-2023 Delft University of Technology and SynTest contributors
*
* This file is part of SynTest Framework - SynTest JavaScript.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { NodePath } from "@babel/core";
import * as t from "@babel/types";
import { AbstractSyntaxTreeVisitor } from "@syntest/ast-visitor-javascript";
import { ConstantPool } from "./ConstantPool";

export class ConstantVisitor extends AbstractSyntaxTreeVisitor {
protected _constantPool: ConstantPool;

constructor(filePath: string, constantPool: ConstantPool) {
super(filePath);
this._constantPool = constantPool;
}

public Literal: (path: NodePath<t.Literal>) => void = (
path: NodePath<t.Literal>
) => {
switch (path.node.type) {
case "StringLiteral": {
this._constantPool.addString(path.node.value);
break;
}
case "NumericLiteral": {
if (Number.isInteger(path.node.value)) {
this._constantPool.addInteger(path.node.value);
} else {
this._constantPool.addNumeric(path.node.value);
}
break;
}
case "NullLiteral": {
// Not useful for the constant pool
break;
}
case "BooleanLiteral": {
// Not useful for the constant pool
break;
}
case "RegExpLiteral": {
break;
}
case "TemplateLiteral": {
break;
}
case "BigIntLiteral": {
this._constantPool.addBigInt(BigInt(path.node.value));
break;
}
case "DecimalLiteral": {
this._constantPool.addNumeric(Number(path.node.value));
break;
}
default: {
// should never occur
throw new Error(`Unknown literal type`);
}
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import {
ClassTarget,
ConstantPoolManager,
FunctionTarget,
getRelationName,
isExported,
Expand Down Expand Up @@ -59,6 +60,9 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler {

constructor(
subject: JavaScriptSubject,
constantPoolManager: ConstantPoolManager,
constantPoolEnabled: boolean,
constantPoolProbability: number,
typeInferenceMode: string,
randomTypeProbability: number,
incorporateExecutionInformation: boolean,
Expand All @@ -71,6 +75,9 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler {
) {
super(
subject,
constantPoolManager,
constantPoolEnabled,
constantPoolProbability,
typeInferenceMode,
randomTypeProbability,
incorporateExecutionInformation,
Expand Down Expand Up @@ -774,11 +781,20 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler {
alphabet = this.stringAlphabet,
maxlength = this.stringMaxLength
): StringStatement {
const valueLength = prng.nextInt(0, maxlength - 1);
let value = "";
let value: string;
if (
this.constantPoolEnabled &&
prng.nextBoolean(this.constantPoolProbability)
) {
value = this.constantPoolManager.contextConstantPool.getRandomString();
}

for (let index = 0; index < valueLength; index++) {
value += prng.pickOne([...alphabet]);
if (value === undefined) {
const valueLength = prng.nextInt(0, maxlength - 1);

for (let index = 0; index < valueLength; index++) {
value += prng.pickOne([...alphabet]);
}
}

return new StringStatement(
Expand Down Expand Up @@ -812,12 +828,21 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler {
const max = 10;
const min = -10;

const value =
this.constantPoolEnabled && prng.nextBoolean(this.constantPoolProbability)
? this.constantPoolManager.contextConstantPool.getRandomNumeric()
: prng.nextDouble(min, max);

if (value === undefined) {
prng.nextDouble(min, max);
}

return new NumericStatement(
id,
name,
TypeEnum.NUMERIC,
prng.uniqueId(),
prng.nextDouble(min, max)
value
);
}

Expand All @@ -826,12 +851,21 @@ export class JavaScriptRandomSampler extends JavaScriptTestCaseSampler {
const max = 10;
const min = -10;

const value =
this.constantPoolEnabled && prng.nextBoolean(this.constantPoolProbability)
? this.constantPoolManager.contextConstantPool.getRandomInteger()
: prng.nextInt(min, max);

if (value === undefined) {
prng.nextInt(min, max);
}

return new IntegerStatement(
id,
name,
TypeEnum.INTEGER,
prng.uniqueId(),
prng.nextInt(min, max)
value
);
}

Expand Down
Loading
Loading