Skip to content

Commit

Permalink
Introduce Opcode enum for efficient Operation type checks
Browse files Browse the repository at this point in the history
Currently, when determining which concrete operation an instruction
uses, Fuzzilli uses the following code pattern:

    switch instr.op {
        case is LoadInteger:
            ...
        case let op as CallMethod:
            ...
    }

However, this is inefficient as it will be compiled to code such as:

    if (dynamicTypeCast(instr.op, LoadInteger)) {
        // it's a LoadInteger operation
    } else if (dynamicTypeCast(instr.op, CallMethod)) {
        // it's a CallMethod operation
    } else if ...

and therefore require roughly linear time (in the number of operations).

With this change, there is now a new Opcode enum which allows these
switches to be rewritten as:

    switch instr.op.opcode {
        case .loadInteger:
            ...
        case .callMethod(let op):
            ...
    }

The code genererated for this switch is efficient as it uses the enum's
integer value to index into a jumptable.

On a simple benchmark that generates random programs, then lifts them to
JavaScript, this change appears to result in a ~1.5x speedup.
  • Loading branch information
Samuel Groß committed Jan 4, 2023
1 parent 75630d4 commit 9d6a18a
Show file tree
Hide file tree
Showing 19 changed files with 1,331 additions and 881 deletions.
28 changes: 14 additions & 14 deletions Sources/Fuzzilli/Base/ProgramBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1961,34 +1961,34 @@ public class ProgramBuilder {

/// Update value analysis. In particular the set of seen values and the variables that contain them for variable reuse.
private func updateValueAnalysis(_ instr: Instruction) {
switch instr.op {
case let op as LoadInteger:
switch instr.op.opcode {
case .loadInteger(let op):
seenIntegers.insert(op.value)
loadedIntegers[instr.output] = op.value
case let op as LoadBigInt:
case .loadBigInt(let op):
seenIntegers.insert(op.value)
case let op as LoadFloat:
case .loadFloat(let op):
seenFloats.insert(op.value)
loadedFloats[instr.output] = op.value
case let op as LoadBuiltin:
case .loadBuiltin(let op):
loadedBuiltins[instr.output] = op.builtinName
case let op as LoadProperty:
case .loadProperty(let op):
seenPropertyNames.insert(op.propertyName)
case let op as StoreProperty:
case .storeProperty(let op):
seenPropertyNames.insert(op.propertyName)
case let op as StorePropertyWithBinop:
case .storePropertyWithBinop(let op):
seenPropertyNames.insert(op.propertyName)
case let op as DeleteProperty:
case .deleteProperty(let op):
seenPropertyNames.insert(op.propertyName)
case let op as LoadElement:
case .loadElement(let op):
seenIntegers.insert(op.index)
case let op as StoreElement:
case .storeElement(let op):
seenIntegers.insert(op.index)
case let op as StoreElementWithBinop:
case .storeElementWithBinop(let op):
seenIntegers.insert(op.index)
case let op as DeleteElement:
case .deleteElement(let op):
seenIntegers.insert(op.index)
case let op as CreateObject:
case .createObject(let op):
seenPropertyNames.formUnion(op.propertyNames)
default:
break
Expand Down
4 changes: 2 additions & 2 deletions Sources/Fuzzilli/FuzzIL/Context.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

/// Current context in the program
public struct Context: OptionSet {
public let rawValue: Int
public let rawValue: UInt32

public init(rawValue: Int) {
public init(rawValue: UInt32) {
self.rawValue = rawValue
}

Expand Down
373 changes: 186 additions & 187 deletions Sources/Fuzzilli/FuzzIL/Instruction.swift

Large diffs are not rendered by default.

Loading

0 comments on commit 9d6a18a

Please sign in to comment.