Commit 0190dc8c authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

[torque] Unify lookup and hanlding of operators and calls

In the process:
 - Make it possible to add 'otherwise' labels to operators
 - operators can be defined by non-external macros

Bug: v8:7793
Change-Id: Ia16ae7c95a4719703c80a927dee44c74b65c170b
Reviewed-on: https://chromium-review.googlesource.com/1100826
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53754}
parent e1deb9b2
......@@ -276,7 +276,7 @@ externalMacro : EXTERN ('operator' STRING_LITERAL)? MACRO IDENTIFIER optionalGen
externalRuntime : EXTERN RUNTIME IDENTIFIER typeListMaybeVarArgs optionalType ';';
builtinDeclaration : JAVASCRIPT? BUILTIN IDENTIFIER optionalGenericTypeList parameterList optionalType (helperBody | ';');
genericSpecialization: IDENTIFIER genericSpecializationTypeList parameterList optionalType optionalLabelList helperBody;
macroDeclaration : MACRO IDENTIFIER optionalGenericTypeList parameterList optionalType optionalLabelList (helperBody | ';');
macroDeclaration : ('operator' STRING_LITERAL)? MACRO IDENTIFIER optionalGenericTypeList parameterList optionalType optionalLabelList (helperBody | ';');
constDeclaration : 'const' IDENTIFIER ':' type '=' STRING_LITERAL ';';
declaration
......
This diff is collapsed.
......@@ -1387,6 +1387,7 @@ class TorqueParser : public antlr4::Parser {
OptionalTypeContext* optionalType();
OptionalLabelListContext* optionalLabelList();
HelperBodyContext* helperBody();
antlr4::tree::TerminalNode* STRING_LITERAL();
void enterRule(antlr4::tree::ParseTreeListener* listener) override;
void exitRule(antlr4::tree::ParseTreeListener* listener) override;
......
......@@ -175,6 +175,9 @@ antlrcpp::Any AstGenerator::visitMacroDeclaration(
GetOptionalParameterList(context->parameterList()),
GetOptionalType(context->optionalType()),
GetOptionalLabelAndTypeList(context->optionalLabelList())});
if (auto* op = context->STRING_LITERAL()) {
macro->op = StringLiteralUnquote(op->getSymbol()->getText());
}
base::Optional<Statement*> body;
if (context->helperBody())
body = context->helperBody()->accept(this).as<Statement*>();
......
......@@ -129,17 +129,7 @@ void DeclarationVisitor::Visit(ExternalMacroDeclaration* decl,
std::string generated_name = GetGeneratedCallableName(
decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
declarations()->DeclareMacro(generated_name, signature);
if (decl->op) {
OperationHandler handler(
{decl->name, signature.parameter_types, signature.return_type});
auto i = global_context_.op_handlers_.find(*decl->op);
if (i == global_context_.op_handlers_.end()) {
global_context_.op_handlers_[*decl->op] = std::vector<OperationHandler>();
i = global_context_.op_handlers_.find(*decl->op);
}
i->second.push_back(handler);
}
declarations()->DeclareMacro(generated_name, signature, decl->op);
}
void DeclarationVisitor::Visit(TorqueBuiltinDeclaration* decl,
......@@ -160,7 +150,8 @@ void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl,
const Signature& signature, Statement* body) {
std::string generated_name = GetGeneratedCallableName(
decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
Macro* macro = declarations()->DeclareMacro(generated_name, signature);
Macro* macro =
declarations()->DeclareMacro(generated_name, signature, decl->op);
CurrentCallableActivator activator(global_context_, macro, decl);
......
......@@ -234,7 +234,7 @@ Label* Declarations::DeclareLabel(const std::string& name) {
return result;
}
Macro* Declarations::DeclareMacro(const std::string& name,
MacroList* Declarations::GetMacroListForName(const std::string& name,
const Signature& signature) {
auto previous = chain_.Lookup(name);
MacroList* macro_list = nullptr;
......@@ -260,8 +260,17 @@ Macro* Declarations::DeclareMacro(const std::string& name,
ReportError(s.str());
}
}
return macro_list->AddMacro(
RegisterDeclarable(std::unique_ptr<Macro>(new Macro(name, signature))));
return macro_list;
}
Macro* Declarations::DeclareMacro(const std::string& name,
const Signature& signature,
base::Optional<std::string> op) {
Macro* macro =
RegisterDeclarable(std::unique_ptr<Macro>(new Macro(name, signature)));
GetMacroListForName(name, signature)->AddMacro(macro);
if (op) GetMacroListForName(*op, signature)->AddMacro(macro);
return macro;
}
Builtin* Declarations::DeclareBuiltin(const std::string& name,
......
......@@ -77,7 +77,8 @@ class Declarations {
Label* DeclareLabel(const std::string& name);
Macro* DeclareMacro(const std::string& name, const Signature& signature);
Macro* DeclareMacro(const std::string& name, const Signature& signature,
base::Optional<std::string> op = {});
Builtin* DeclareBuiltin(const std::string& name, Builtin::Kind kind,
bool external, const Signature& signature);
......@@ -128,6 +129,9 @@ class Declarations {
return ptr;
}
MacroList* GetMacroListForName(const std::string& name,
const Signature& signature);
void Declare(const std::string& name, std::unique_ptr<Declarable> d) {
chain_.Declare(name, RegisterDeclarable(std::move(d)));
}
......
......@@ -26,8 +26,9 @@ Signature FileVisitor::MakeSignature(const CallableNodeSignature* signature) {
}
Callable* FileVisitor::LookupCall(const std::string& name,
const TypeVector& parameter_types) {
const Arguments& arguments) {
Callable* result = nullptr;
TypeVector parameter_types(arguments.parameters.GetTypeVector());
Declarable* declarable = declarations()->Lookup(name);
if (declarable->IsBuiltin()) {
result = Builtin::cast(declarable);
......@@ -36,8 +37,8 @@ Callable* FileVisitor::LookupCall(const std::string& name,
} else if (declarable->IsMacroList()) {
std::vector<Macro*> candidates;
for (Macro* m : MacroList::cast(declarable)->list()) {
if (IsCompatibleSignature(m->signature().parameter_types,
parameter_types)) {
if (IsCompatibleSignature(m->signature(), parameter_types,
arguments.labels)) {
candidates.push_back(m);
}
}
......@@ -48,7 +49,9 @@ Callable* FileVisitor::LookupCall(const std::string& name,
.StrictlyBetterThan(ParameterDifference(
b->signature().parameter_types.types, parameter_types));
};
if (!candidates.empty()) {
if (candidates.empty()) {
return nullptr;
}
Macro* best = *std::min_element(candidates.begin(), candidates.end(),
is_better_candidate);
for (Macro* candidate : candidates) {
......@@ -63,11 +66,7 @@ Callable* FileVisitor::LookupCall(const std::string& name,
ReportError(s.str());
}
}
return best;
}
std::stringstream stream;
stream << "cannot find macro with name \"" << name << "\"";
ReportError(stream.str());
result = best;
} else {
std::stringstream stream;
stream << "can't call " << declarable->type_name() << " " << name
......
......@@ -67,8 +67,7 @@ class FileVisitor {
return std::string("p_") + name;
}
Callable* LookupCall(const std::string& name,
const TypeVector& parameter_types);
Callable* LookupCall(const std::string& name, const Arguments& arguments);
Signature MakeSignature(const CallableNodeSignature* signature);
......
......@@ -38,13 +38,6 @@ class Module {
std::stringstream source_stream_;
};
class OperationHandler {
public:
std::string macro_name;
ParameterTypes parameter_types;
const Type* result_type;
};
struct SourceFileContext {
std::string name;
std::unique_ptr<antlr4::ANTLRFileStream> stream;
......@@ -112,8 +105,6 @@ class GlobalContext {
return break_continue_stack_.back().second;
}
std::map<std::string, std::vector<OperationHandler>> op_handlers_;
Declarations* declarations() { return &declarations_; }
Ast* ast() { return &ast_; }
......
......@@ -448,7 +448,7 @@ VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) {
VisitResult one = {TypeOracle::GetConstInt31Type(), "1"};
Arguments args;
args.parameters = {current_value, one};
VisitResult assignment_value = GenerateOperation(
VisitResult assignment_value = GenerateCall(
expr->op == IncrementDecrementOperator::kIncrement ? "+" : "-", args);
GenerateAssignToLocation(expr->location, location_ref, assignment_value);
return expr->postfix ? value_copy : assignment_value;
......@@ -463,7 +463,7 @@ VisitResult ImplementationVisitor::Visit(AssignmentExpression* expr) {
assignment_value = Visit(expr->value);
Arguments args;
args.parameters = {assignment_value, assignment_value};
assignment_value = GenerateOperation(*expr->op, args);
assignment_value = GenerateCall(*expr->op, args);
GenerateAssignToLocation(expr->location, location_ref, assignment_value);
} else {
assignment_value = Visit(expr->value);
......@@ -822,9 +822,9 @@ const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
? Visit(*stmt->begin)
: VisitResult(TypeOracle::GetConstInt31Type(), "0");
VisitResult end =
stmt->end ? Visit(*stmt->end)
: GenerateOperation(".length", {{expression_result}, {}});
VisitResult end = stmt->end
? Visit(*stmt->end)
: GenerateCall(".length", {{expression_result}, {}});
Label* body_label = declarations()->DeclarePrivateLabel("body");
GenerateLabelDefinition(body_label);
......@@ -851,12 +851,12 @@ const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
BreakContinueActivator activator(global_context_, exit_label,
increment_label);
VisitResult result = GenerateOperation("<", {{index_for_read, end}, {}});
VisitResult result = GenerateCall("<", {{index_for_read, end}, {}});
GenerateBranch(result, body_label, exit_label);
GenerateLabelBind(body_label);
VisitResult element_result =
GenerateOperation("[]", {{expression_result, index_for_read}, {}});
GenerateCall("[]", {{expression_result, index_for_read}, {}});
GenerateVariableDeclaration(stmt->var_declaration,
stmt->var_declaration->name, {}, element_result);
Visit(stmt->body);
......@@ -866,7 +866,7 @@ const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
Arguments increment_args;
increment_args.parameters = {index_for_read,
{TypeOracle::GetConstInt31Type(), "1"}};
VisitResult increment_result = GenerateOperation("+", increment_args);
VisitResult increment_result = GenerateCall("+", increment_args);
GenerateAssignToVariable(index_var, increment_result);
......@@ -1090,61 +1090,6 @@ void ImplementationVisitor::GenerateMacroFunctionDeclaration(
o << ")";
}
VisitResult ImplementationVisitor::GenerateOperation(
const std::string& operation, Arguments arguments,
base::Optional<const Type*> return_type) {
TypeVector parameter_types(arguments.parameters.GetTypeVector());
auto i = global_context_.op_handlers_.find(operation);
if (i != global_context_.op_handlers_.end()) {
std::vector<OperationHandler*> candidates;
for (OperationHandler& handler : i->second) {
if (IsCompatibleSignature(handler.parameter_types, parameter_types)) {
if (!return_type || *return_type == handler.result_type) {
candidates.push_back(&handler);
}
}
}
auto is_better_candidate = [&](OperationHandler* a, OperationHandler* b) {
return ParameterDifference(a->parameter_types.types, parameter_types)
.StrictlyBetterThan(
ParameterDifference(b->parameter_types.types, parameter_types));
};
if (!candidates.empty()) {
OperationHandler* best = *std::min_element(
candidates.begin(), candidates.end(), is_better_candidate);
for (OperationHandler* candidate : candidates) {
if (candidate != best && !is_better_candidate(best, candidate)) {
std::stringstream s;
s << "ambiguous operation \"" << operation << "\" with types ("
<< parameter_types << "), candidates:";
for (OperationHandler* handler : candidates) {
s << "\n (" << handler->parameter_types << ") => "
<< handler->result_type;
}
ReportError(s.str());
}
}
// Operators used in a bit context can also be function calls that never
// return but have a True and False label
if (!return_type && best->result_type->IsNever()) {
if (arguments.labels.size() == 0) {
Label* true_label = declarations()->LookupLabel(kTrueLabelName);
arguments.labels.push_back(true_label);
Label* false_label = declarations()->LookupLabel(kFalseLabelName);
arguments.labels.push_back(false_label);
}
}
return GenerateCall(best->macro_name, arguments, false);
}
}
std::stringstream s;
s << "cannot find implementation of operation \"" << operation
<< "\" with types " << parameter_types;
ReportError(s.str());
}
void ImplementationVisitor::GenerateChangedVarsFromControlSplit(AstNode* node) {
const std::set<const Variable*>& changed_vars =
global_context_.GetControlSplitChangedVariables(
......@@ -1242,12 +1187,12 @@ void ImplementationVisitor::GenerateAssignToLocation(
Variable* var = Variable::cast(value);
GenerateAssignToVariable(var, assignment_value);
} else if (auto access = FieldAccessExpression::cast(location)) {
GenerateOperation(std::string(".") + access->field + "=",
GenerateCall(std::string(".") + access->field + "=",
{{reference.base, assignment_value}, {}});
} else {
DCHECK_NOT_NULL(ElementAccessExpression::cast(location));
GenerateOperation(
"[]=", {{reference.base, reference.index, assignment_value}, {}});
GenerateCall("[]=",
{{reference.base, reference.index, assignment_value}, {}});
}
}
......@@ -1341,7 +1286,9 @@ VisitResult ImplementationVisitor::GeneratePointerCall(
}
ParameterTypes types{type->parameter_types(), false};
if (!IsCompatibleSignature(types, parameter_types)) {
Signature sig;
sig.parameter_types = types;
if (!IsCompatibleSignature(sig, parameter_types, {})) {
std::stringstream stream;
stream << "parameters do not match function pointer signature. Expected: ("
<< type->parameter_types() << ") but got: (" << parameter_types
......@@ -1395,10 +1342,29 @@ VisitResult ImplementationVisitor::GeneratePointerCall(
}
VisitResult ImplementationVisitor::GenerateCall(
const std::string& callable_name, const Arguments& arguments,
bool is_tailcall) {
TypeVector parameter_types(arguments.parameters.GetTypeVector());
Callable* callable = LookupCall(callable_name, parameter_types);
const std::string& callable_name, Arguments arguments, bool is_tailcall) {
Callable* callable = LookupCall(callable_name, arguments);
// Operators used in a bit context can also be function calls that never
// return but have a True and False label
if (callable == nullptr && arguments.labels.size() == 0) {
Label* true_label = declarations()->LookupLabel(kTrueLabelName);
arguments.labels.push_back(true_label);
Label* false_label = declarations()->LookupLabel(kFalseLabelName);
arguments.labels.push_back(false_label);
callable = LookupCall(callable_name, arguments);
if (callable == nullptr) {
std::stringstream stream;
stream << "no matching declaration found for callable " << callable_name;
ReportError(stream.str());
}
if (!callable->signature().return_type->IsNever()) {
std::stringstream stream;
stream << "macthing macro declaration for " << callable_name
<< " matches if-branch protocol but isn't of type 'never'";
ReportError(stream.str());
}
}
const Type* result_type = callable->signature().return_type;
std::vector<std::string> variables;
......@@ -1562,14 +1528,6 @@ VisitResult ImplementationVisitor::Visit(CallExpression* expr,
for (Expression* arg : expr->arguments)
arguments.parameters.push_back(Visit(arg));
arguments.labels = LabelsFromIdentifiers(expr->labels);
if (expr->is_operator) {
if (is_tailcall) {
std::stringstream s;
s << "can't tail call an operator";
ReportError(s.str());
}
return GenerateOperation(name, arguments);
}
VisitResult result;
if (!has_template_arguments &&
declarations()->Lookup(expr->callee.name)->IsValue()) {
......
......@@ -64,13 +64,13 @@ class ImplementationVisitor : public FileVisitor {
LocationReference reference) {
Arguments arguments;
arguments.parameters = {reference.base};
return GenerateOperation(std::string(".") + expr->field, arguments);
return GenerateCall(std::string(".") + expr->field, arguments);
}
VisitResult GenerateFetchFromLocation(ElementAccessExpression* expr,
LocationReference reference) {
Arguments arguments;
arguments.parameters = {reference.base, reference.index};
return GenerateOperation("[]", arguments);
return GenerateCall("[]", arguments);
}
VisitResult GetBuiltinCode(Builtin* builtin);
......@@ -195,7 +195,7 @@ class ImplementationVisitor : public FileVisitor {
void GenerateParameterList(const NameVector& list, size_t first = 0);
VisitResult GenerateCall(const std::string& callable_name,
const Arguments& parameters, bool tail_call);
Arguments parameters, bool tail_call = false);
VisitResult GeneratePointerCall(Expression* callee,
const Arguments& parameters, bool tail_call);
......@@ -215,10 +215,6 @@ class ImplementationVisitor : public FileVisitor {
const std::string& macro_prefix,
Macro* macro);
VisitResult GenerateOperation(const std::string& operation,
Arguments arguments,
base::Optional<const Type*> return_type = {});
VisitResult GenerateImplicitConvert(const Type* destination_type,
VisitResult source);
......
......@@ -210,11 +210,17 @@ bool IsAssignableFrom(const Type* to, const Type* from) {
return TypeOracle::IsImplicitlyConverableFrom(to, from);
}
bool IsCompatibleSignature(const ParameterTypes& to, const TypeVector& from) {
auto i = to.types.begin();
for (auto current : from) {
if (i == to.types.end()) {
if (!to.var_args) return false;
bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
const std::vector<Label*>& labels) {
auto i = sig.parameter_types.types.begin();
// TODO(danno): The test below is actually insufficient. The labels'
// parameters must be checked too. ideally, the named part of
// LabelDeclarationVector would be factored out so that the label count and
// parameter types could be passed separately.
if (sig.labels.size() != labels.size()) return false;
for (auto current : types) {
if (i == sig.parameter_types.types.end()) {
if (!sig.parameter_types.var_args) return false;
if (!IsAssignableFrom(TypeOracle::GetObjectType(), current)) return false;
} else {
if (!IsAssignableFrom(*i++, current)) return false;
......
......@@ -347,7 +347,8 @@ struct Arguments {
std::ostream& operator<<(std::ostream& os, const Signature& sig);
bool IsAssignableFrom(const Type* to, const Type* from);
bool IsCompatibleSignature(const ParameterTypes& to, const TypeVector& from);
bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
const std::vector<Label*>& labels);
} // namespace torque
} // namespace internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment