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

Feature/super expression #468

Merged
merged 5 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
72 changes: 72 additions & 0 deletions Sources/Fuzzilli/Compiler/Compiler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,30 @@ public class JavaScriptCompiler {
}
}
}
case .superMemberExpression(let superMemberExpression):
guard superMemberExpression.isOptional == false else {
throw CompilerError.unsupportedFeatureError("Optional chaining is not supported in super member expressions")
}

guard let property = superMemberExpression.property else {
throw CompilerError.invalidNodeError("Missing property in super member expression")
}

switch property {
case .name(let name):
if let op = assignmentOperator {
// Example: super.foo += 1
emit(UpdateSuperProperty(propertyName: name, operator: op), withInputs: [rhs])
} else {
// Example: super.foo = 1
emit(SetSuperProperty(propertyName: name), withInputs: [rhs])
}

case .expression(let expr):
let property = try compileExpression(expr)
// Example: super[expr] = 1
emit(SetComputedSuperProperty(), withInputs: [property, rhs])
}


case .identifier(let identifier):
Expand Down Expand Up @@ -924,6 +948,7 @@ public class JavaScriptCompiler {

// See if this is a function or a method call
if case .memberExpression(let memberExpression) = callExpression.callee.expression {
// obj.foo(...) or obj[expr](...)
let object = try compileExpression(memberExpression.object)
guard let property = memberExpression.property else { throw CompilerError.invalidNodeError("missing property in member expression in call expression") }
switch property {
Expand All @@ -941,6 +966,18 @@ public class JavaScriptCompiler {
return emit(CallComputedMethod(numArguments: arguments.count, isGuarded: callExpression.isOptional), withInputs: [object, method] + arguments).output
}
}
} else if case .superMemberExpression(let superMemberExpression) = callExpression.callee.expression {
// super.foo(...)
guard !isSpreading else {
throw CompilerError.unsupportedFeatureError("Spread calls with super are not supported")
}
guard case .name(let methodName) = superMemberExpression.property else {
throw CompilerError.invalidNodeError("Super method calls must use a property name")
}
guard !callExpression.isOptional else {
throw CompilerError.unsupportedFeatureError("Optional chaining with super method calls is not supported")
}
return emit(CallSuperMethod(methodName: methodName, numArguments: arguments.count), withInputs: arguments).output
// Now check if it is a V8 intrinsic function
} else if case .v8IntrinsicIdentifier(let v8Intrinsic) = callExpression.callee.expression {
guard !isSpreading else { throw CompilerError.unsupportedFeatureError("Not currently supporting spread calls to V8 intrinsics") }
Expand All @@ -957,6 +994,20 @@ public class JavaScriptCompiler {
}
}

case .callSuperConstructor(let callSuperConstructor):
let (arguments, spreads) = try compileCallArguments(callSuperConstructor.arguments)
let isSpreading = spreads.contains(true)

if isSpreading {
throw CompilerError.unsupportedFeatureError("Spread arguments are not supported in super constructor calls")
}
guard !callSuperConstructor.isOptional else {
throw CompilerError.unsupportedFeatureError("Optional chaining is not supported in super constructor calls")
}
emit(CallSuperConstructor(numArguments: arguments.count), withInputs: arguments)
return lookupIdentifier("this")! // we can force unwrap because |this| always exists in the context where |super| exists
saelo marked this conversation as resolved.
Show resolved Hide resolved


case .newExpression(let newExpression):
let callee = try compileExpression(newExpression.callee)
let (arguments, spreads) = try compileCallArguments(newExpression.arguments)
Expand All @@ -981,6 +1032,27 @@ public class JavaScriptCompiler {
return emit(GetComputedProperty(isGuarded: memberExpression.isOptional), withInputs: [object, property]).output
}
}

case .superMemberExpression(let superMemberExpression):
guard superMemberExpression.isOptional == false else {
throw CompilerError.unsupportedFeatureError("Optional chaining is not supported in super member expressions")
}
guard let property = superMemberExpression.property else {
throw CompilerError.invalidNodeError("Missing property in super member expression")
}

switch property {
case .name(let name):
return emit(GetSuperProperty(propertyName: name), withInputs: []).output

case .expression(let expr):
if case .numberLiteral(let literal) = expr.expression, let _ = Int64(exactly: literal.value) {
throw CompilerError.unsupportedFeatureError("GetElement is not supported in super member expressions")
} else {
let compiledProperty = try compileExpression(expr)
return emit(GetComputedSuperProperty(), withInputs: [compiledProperty]).output
}
}

case .unaryExpression(let unaryExpression):
let argument = try compileExpression(unaryExpression.argument)
Expand Down
18 changes: 18 additions & 0 deletions Sources/Fuzzilli/Compiler/Parser/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,12 @@ function parse(script, proto) {
}
case 'CallExpression':
case 'OptionalCallExpression': {
if (node.callee.type === 'Super') {
let arguments = node.arguments.map(visitExpression);
let isOptional = node.type === 'OptionalCallExpression';
return makeExpression('CallSuperConstructor', { arguments, isOptional });
}

let callee = visitExpression(node.callee);
let arguments = node.arguments.map(visitExpression);
let isOptional = node.type === 'OptionalCallExpression';
Expand All @@ -524,6 +530,18 @@ function parse(script, proto) {
}
case 'MemberExpression':
case 'OptionalMemberExpression': {
if (node.object && node.object.type === 'Super') {
let out = {};
if (node.computed) {
out.expression = visitExpression(node.property);
} else {
assert(node.property.type === 'Identifier', "Expected node.property.type to be exactly 'Identifier'");
assert(node.property.name != 'Super', "super.super(...) is not allowed");
out.name = node.property.name;
}
out.isOptional = node.type === 'OptionalMemberExpression';
return makeExpression('SuperMemberExpression', out);
}
let object = visitExpression(node.object);
let out = { object };
if (node.computed) {
Expand Down
Loading
Loading