Commit 06f2a5c2 authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

[torque] Implement parameter overloading in generics

This allows redifinitions of generics with the same name but differing parameter
type lists, e.g.

  macro coerce<Dest: type>(from: HeapObject): Dest;
  coerce<int32>(from: HeapObject): int32 {...}
  macro coerce<Dest: type>(from: Smi): Dest;
  coerce<int32>(from: Smi): int32 {...}

In order to allow multiple overloads of generic macros with the same name,
a more nuanced lookup of calls has been implemented using the
ParameterDifference utility class. There is still work to be done to unify
when ParameterDifference is used for lookup (e.g. removing it from operator
lookup when operators become simple aliases for macro names), but that work
will be done in a separate CL.

As part of this CL, the custom handling of "cast<>" operator in the .g4
grammar has been removed and replaced by a handful of equivalent overloads of
a generic "cast" macro.

Bug: v8:7793
Change-Id: Ibb2cdd3d58632b7f7f7ba683499f9688ae07f4f8
Reviewed-on: https://chromium-review.googlesource.com/1087873
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53562}
parent 81666f7f
......@@ -235,32 +235,54 @@ extern operator '!' macro Word32BinaryNot(bool): bool;
extern operator '.map' macro LoadMap(HeapObject): Map;
extern operator '.map=' macro StoreMap(HeapObject, Map);
extern operator
'.instanceType' macro LoadInstanceType(HeapObject): InstanceType;
'.instanceType' macro LoadInstanceType(HeapObject): InstanceType;
extern operator '.length' macro LoadStringLengthAsWord(String): intptr;
extern operator '.length' macro GetArgumentsLength(constexpr Arguments): intptr;
extern operator
'[]' macro GetArgumentValue(constexpr Arguments, intptr): Object;
'[]' macro GetArgumentValue(constexpr Arguments, intptr): Object;
extern operator 'is<Smi>' macro TaggedIsSmi(Object): bool;
extern operator 'isnt<Smi>' macro TaggedIsNotSmi(Object): bool;
extern operator
'cast<>' macro TaggedToJSDataView(Object): JSDataView labels CastError;
extern operator
'cast<>' macro TaggedToHeapObject(Object): HeapObject labels CastError;
extern operator 'cast<>' macro TaggedToSmi(Object): Smi labels CastError;
extern operator
'cast<>' macro TaggedToJSArray(Object): JSArray labels CastError;
extern operator
'cast<>' macro TaggedToCallable(Object): Callable labels CastError;
extern operator 'cast<>' macro ConvertFixedArrayBaseToFixedArray(
extern macro TaggedToJSDataView(Object): JSDataView labels CastError;
extern macro TaggedToHeapObject(Object): HeapObject labels CastError;
extern macro TaggedToSmi(Object): Smi labels CastError;
extern macro TaggedToJSArray(Object): JSArray labels CastError;
extern macro TaggedToCallable(Object): Callable labels CastError;
extern macro ConvertFixedArrayBaseToFixedArray(
FixedArrayBase): FixedArray labels CastError;
extern operator 'cast<>' macro ConvertFixedArrayBaseToFixedDoubleArray(
extern macro ConvertFixedArrayBaseToFixedDoubleArray(
FixedArrayBase): FixedDoubleArray labels CastError;
extern operator 'cast<>' macro TaggedToNumber(
Object): Number labels CastError;
extern macro TaggedToNumber(Object): Number labels CastError;
macro cast<A : type>(o: Object): A labels CastError;
cast<Number>(o: Object): Number labels CastError {
return TaggedToNumber(o) otherwise CastError;
}
cast<HeapObject>(o: Object): HeapObject labels CastError {
return TaggedToHeapObject(o) otherwise CastError;
}
cast<Smi>(o: Object): Smi labels CastError {
return TaggedToSmi(o) otherwise CastError;
}
cast<JSDataView>(o: Object): JSDataView labels CastError {
return TaggedToJSDataView(o) otherwise CastError;
}
cast<Callable>(o: Object): Callable labels CastError {
return TaggedToCallable(o) otherwise CastError;
}
cast<JSArray>(o: Object): JSArray labels CastError {
return TaggedToJSArray(o) otherwise CastError;
}
macro cast<A : type>(o: FixedArrayBase): A labels CastError;
cast<FixedArray>(o: FixedArrayBase): FixedArray labels CastError {
return ConvertFixedArrayBaseToFixedArray(o) otherwise CastError;
}
cast<FixedDoubleArray>(o: FixedArrayBase): FixedDoubleArray labels CastError {
return ConvertFixedArrayBaseToFixedDoubleArray(o) otherwise CastError;
}
extern macro AllocateHeapNumberWithValue(float64): HeapNumber;
......@@ -399,9 +421,10 @@ labels IfHole {
}
macro HasPropertyObject(
o: Object, p: Object, c: Context, f: constexpr HasPropertyLookupMode): Oddball {
o: Object, p: Object, c: Context,
f: constexpr HasPropertyLookupMode): Oddball {
try {
return HasProperty(cast<HeapObject>(o) otherwise CastError, p, c, f);
return HasProperty((cast<HeapObject>(o) otherwise CastError), p, c, f);
}
label CastError {
return False;
......
......@@ -5,16 +5,16 @@
#ifndef V8_BUILTINS_BUILTINS_DATA_VIEW_GEN_H_
#define V8_BUILTINS_BUILTINS_DATA_VIEW_GEN_H_
#include "src/code-stub-assembler.h"
#include "src/elements-kind.h"
#include "torque-generated/builtins-base-from-dsl-gen.h"
namespace v8 {
namespace internal {
class DataViewBuiltinsAssembler : public CodeStubAssembler {
class DataViewBuiltinsAssembler : public BaseBuiltinsFromDSLAssembler {
public:
explicit DataViewBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
: BaseBuiltinsFromDSLAssembler(state) {}
TNode<Smi> LoadDataViewByteOffset(TNode<JSDataView> data_view) {
return LoadObjectField<Smi>(data_view, JSDataView::kByteOffsetOffset);
......
......@@ -5,15 +5,15 @@
#ifndef V8_BUILTINS_BUILTINS_TYPED_ARRAY_GEN_H_
#define V8_BUILTINS_BUILTINS_TYPED_ARRAY_GEN_H_
#include "src/code-stub-assembler.h"
#include "torque-generated/builtins-base-from-dsl-gen.h"
namespace v8 {
namespace internal {
class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
class TypedArrayBuiltinsAssembler : public BaseBuiltinsFromDSLAssembler {
public:
explicit TypedArrayBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
: BaseBuiltinsFromDSLAssembler(state) {}
TNode<JSTypedArray> SpeciesCreateByLength(TNode<Context> context,
TNode<JSTypedArray> exemplar,
......
......@@ -17,7 +17,6 @@ JAVASCRIPT: 'javascript';
IMPLICIT: 'implicit';
DEFERRED: 'deferred';
IF: 'if';
CAST_KEYWORD: 'cast';
UNSAFE_CAST_KEYWORD: 'unsafe_cast';
CONVERT_KEYWORD: 'convert';
FOR: 'for';
......@@ -216,7 +215,6 @@ primaryExpression
: helperCall
| DECIMAL_LITERAL
| STRING_LITERAL
| CAST_KEYWORD '<' type '>' '(' expression ')' OTHERWISE IDENTIFIER
| UNSAFE_CAST_KEYWORD '<' type '>' '(' expression ')'
| CONVERT_KEYWORD '<' type '>' '(' expression ')'
| ('(' expression ')');
......
This diff is collapsed.
......@@ -42,61 +42,60 @@ class TorqueLexer : public antlr4::Lexer {
IMPLICIT = 27,
DEFERRED = 28,
IF = 29,
CAST_KEYWORD = 30,
UNSAFE_CAST_KEYWORD = 31,
CONVERT_KEYWORD = 32,
FOR = 33,
WHILE = 34,
RETURN = 35,
CONSTEXPR = 36,
CONTINUE = 37,
BREAK = 38,
GOTO = 39,
OTHERWISE = 40,
TRY = 41,
LABEL = 42,
LABELS = 43,
TAIL = 44,
ISNT = 45,
IS = 46,
LET = 47,
EXTERN = 48,
ASSERT_TOKEN = 49,
CHECK_TOKEN = 50,
UNREACHABLE_TOKEN = 51,
DEBUG_TOKEN = 52,
ASSIGNMENT = 53,
ASSIGNMENT_OPERATOR = 54,
EQUAL = 55,
PLUS = 56,
MINUS = 57,
MULTIPLY = 58,
DIVIDE = 59,
MODULO = 60,
BIT_OR = 61,
BIT_AND = 62,
BIT_NOT = 63,
MAX = 64,
MIN = 65,
NOT_EQUAL = 66,
LESS_THAN = 67,
LESS_THAN_EQUAL = 68,
GREATER_THAN = 69,
GREATER_THAN_EQUAL = 70,
SHIFT_LEFT = 71,
SHIFT_RIGHT = 72,
SHIFT_RIGHT_ARITHMETIC = 73,
VARARGS = 74,
EQUALITY_OPERATOR = 75,
INCREMENT = 76,
DECREMENT = 77,
NOT = 78,
STRING_LITERAL = 79,
IDENTIFIER = 80,
WS = 81,
BLOCK_COMMENT = 82,
LINE_COMMENT = 83,
DECIMAL_LITERAL = 84
UNSAFE_CAST_KEYWORD = 30,
CONVERT_KEYWORD = 31,
FOR = 32,
WHILE = 33,
RETURN = 34,
CONSTEXPR = 35,
CONTINUE = 36,
BREAK = 37,
GOTO = 38,
OTHERWISE = 39,
TRY = 40,
LABEL = 41,
LABELS = 42,
TAIL = 43,
ISNT = 44,
IS = 45,
LET = 46,
EXTERN = 47,
ASSERT_TOKEN = 48,
CHECK_TOKEN = 49,
UNREACHABLE_TOKEN = 50,
DEBUG_TOKEN = 51,
ASSIGNMENT = 52,
ASSIGNMENT_OPERATOR = 53,
EQUAL = 54,
PLUS = 55,
MINUS = 56,
MULTIPLY = 57,
DIVIDE = 58,
MODULO = 59,
BIT_OR = 60,
BIT_AND = 61,
BIT_NOT = 62,
MAX = 63,
MIN = 64,
NOT_EQUAL = 65,
LESS_THAN = 66,
LESS_THAN_EQUAL = 67,
GREATER_THAN = 68,
GREATER_THAN_EQUAL = 69,
SHIFT_LEFT = 70,
SHIFT_RIGHT = 71,
SHIFT_RIGHT_ARITHMETIC = 72,
VARARGS = 73,
EQUALITY_OPERATOR = 74,
INCREMENT = 75,
DECREMENT = 76,
NOT = 77,
STRING_LITERAL = 78,
IDENTIFIER = 79,
WS = 80,
BLOCK_COMMENT = 81,
LINE_COMMENT = 82,
DECIMAL_LITERAL = 83
};
explicit TorqueLexer(antlr4::CharStream* input);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -42,61 +42,60 @@ class TorqueParser : public antlr4::Parser {
IMPLICIT = 27,
DEFERRED = 28,
IF = 29,
CAST_KEYWORD = 30,
UNSAFE_CAST_KEYWORD = 31,
CONVERT_KEYWORD = 32,
FOR = 33,
WHILE = 34,
RETURN = 35,
CONSTEXPR = 36,
CONTINUE = 37,
BREAK = 38,
GOTO = 39,
OTHERWISE = 40,
TRY = 41,
LABEL = 42,
LABELS = 43,
TAIL = 44,
ISNT = 45,
IS = 46,
LET = 47,
EXTERN = 48,
ASSERT_TOKEN = 49,
CHECK_TOKEN = 50,
UNREACHABLE_TOKEN = 51,
DEBUG_TOKEN = 52,
ASSIGNMENT = 53,
ASSIGNMENT_OPERATOR = 54,
EQUAL = 55,
PLUS = 56,
MINUS = 57,
MULTIPLY = 58,
DIVIDE = 59,
MODULO = 60,
BIT_OR = 61,
BIT_AND = 62,
BIT_NOT = 63,
MAX = 64,
MIN = 65,
NOT_EQUAL = 66,
LESS_THAN = 67,
LESS_THAN_EQUAL = 68,
GREATER_THAN = 69,
GREATER_THAN_EQUAL = 70,
SHIFT_LEFT = 71,
SHIFT_RIGHT = 72,
SHIFT_RIGHT_ARITHMETIC = 73,
VARARGS = 74,
EQUALITY_OPERATOR = 75,
INCREMENT = 76,
DECREMENT = 77,
NOT = 78,
STRING_LITERAL = 79,
IDENTIFIER = 80,
WS = 81,
BLOCK_COMMENT = 82,
LINE_COMMENT = 83,
DECIMAL_LITERAL = 84
UNSAFE_CAST_KEYWORD = 30,
CONVERT_KEYWORD = 31,
FOR = 32,
WHILE = 33,
RETURN = 34,
CONSTEXPR = 35,
CONTINUE = 36,
BREAK = 37,
GOTO = 38,
OTHERWISE = 39,
TRY = 40,
LABEL = 41,
LABELS = 42,
TAIL = 43,
ISNT = 44,
IS = 45,
LET = 46,
EXTERN = 47,
ASSERT_TOKEN = 48,
CHECK_TOKEN = 49,
UNREACHABLE_TOKEN = 50,
DEBUG_TOKEN = 51,
ASSIGNMENT = 52,
ASSIGNMENT_OPERATOR = 53,
EQUAL = 54,
PLUS = 55,
MINUS = 56,
MULTIPLY = 57,
DIVIDE = 58,
MODULO = 59,
BIT_OR = 60,
BIT_AND = 61,
BIT_NOT = 62,
MAX = 63,
MIN = 64,
NOT_EQUAL = 65,
LESS_THAN = 66,
LESS_THAN_EQUAL = 67,
GREATER_THAN = 68,
GREATER_THAN_EQUAL = 69,
SHIFT_LEFT = 70,
SHIFT_RIGHT = 71,
SHIFT_RIGHT_ARITHMETIC = 72,
VARARGS = 73,
EQUALITY_OPERATOR = 74,
INCREMENT = 75,
DECREMENT = 76,
NOT = 77,
STRING_LITERAL = 78,
IDENTIFIER = 79,
WS = 80,
BLOCK_COMMENT = 81,
LINE_COMMENT = 82,
DECIMAL_LITERAL = 83
};
enum {
......@@ -732,12 +731,9 @@ class TorqueParser : public antlr4::Parser {
HelperCallContext* helperCall();
antlr4::tree::TerminalNode* DECIMAL_LITERAL();
antlr4::tree::TerminalNode* STRING_LITERAL();
antlr4::tree::TerminalNode* CAST_KEYWORD();
antlr4::tree::TerminalNode* UNSAFE_CAST_KEYWORD();
TypeContext* type();
ExpressionContext* expression();
antlr4::tree::TerminalNode* OTHERWISE();
antlr4::tree::TerminalNode* IDENTIFIER();
antlr4::tree::TerminalNode* UNSAFE_CAST_KEYWORD();
antlr4::tree::TerminalNode* CONVERT_KEYWORD();
void enterRule(antlr4::tree::ParseTreeListener* listener) override;
......
......@@ -546,11 +546,6 @@ antlrcpp::Any AstGenerator::visitPrimaryExpression(
return implicit_cast<Expression*>(RegisterNode(new UnsafeCastExpression{
Pos(context), GetType(context->type()),
context->expression()->accept(this).as<Expression*>()}));
if (context->CAST_KEYWORD())
return implicit_cast<Expression*>(RegisterNode(new CastExpression{
Pos(context), GetType(context->type()),
context->IDENTIFIER()->getSymbol()->getText(),
context->expression()->accept(this).as<Expression*>()}));
return context->expression()->accept(this);
}
......
......@@ -39,7 +39,6 @@ DECLARE_CONTEXTUAL_VARIABLE(CurrentSourcePosition, SourcePosition)
V(ElementAccessExpression) \
V(AssignmentExpression) \
V(IncrementDecrementExpression) \
V(CastExpression) \
V(UnsafeCastExpression) \
V(ConvertExpression)
......@@ -302,16 +301,6 @@ struct NumberLiteralExpression : Expression {
std::string number;
};
struct CastExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(CastExpression)
CastExpression(SourcePosition p, TypeExpression* t, std::string o,
Expression* v)
: Expression(kKind, p), type(t), otherwise(o), value(v) {}
TypeExpression* type;
std::string otherwise;
Expression* value;
};
struct ConvertExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ConvertExpression)
ConvertExpression(SourcePosition p, TypeExpression* t, Expression* v)
......
......@@ -34,6 +34,21 @@ std::ostream& operator<<(std::ostream& os, const RuntimeFunction& b) {
return os;
}
std::ostream& operator<<(std::ostream& os, const Generic& g) {
os << "generic " << g.name() << "<";
bool first = true;
for (auto t : g.declaration()->generic_parameters) {
if (!first) {
os << ", ";
}
first = false;
os << t << ": type";
}
os << ">";
return os;
}
} // namespace torque
} // namespace internal
} // namespace v8
......@@ -32,6 +32,7 @@ class Declarable {
kBuiltin,
kRuntimeFunction,
kGeneric,
kGenericList,
kTypeAlias,
kLabel,
kConstant
......@@ -46,6 +47,7 @@ class Declarable {
bool IsLabel() const { return kind() == kLabel; }
bool IsVariable() const { return kind() == kVariable; }
bool IsMacroList() const { return kind() == kMacroList; }
bool IsGenericList() const { return kind() == kGenericList; }
bool IsConstant() const { return kind() == kConstant; }
bool IsValue() const { return IsVariable() || IsConstant() || IsParameter(); }
virtual const char* type_name() const { return "<<unknown>>"; }
......@@ -286,6 +288,7 @@ class Generic : public Declarable {
DECLARE_DECLARABLE_BOILERPLATE(Generic, generic);
GenericDeclaration* declaration() const { return declaration_; }
const std::string& name() const { return name_; }
Module* module() const { return module_; }
private:
......@@ -293,13 +296,31 @@ class Generic : public Declarable {
Generic(const std::string& name, Module* module,
GenericDeclaration* declaration)
: Declarable(Declarable::kGeneric),
name_(name),
module_(module),
declaration_(declaration) {}
std::string name_;
Module* module_;
GenericDeclaration* declaration_;
};
class GenericList : public Declarable {
public:
DECLARE_DECLARABLE_BOILERPLATE(GenericList, generic_list);
const std::vector<Generic*>& list() { return list_; }
Generic* AddGeneric(Generic* generic) {
list_.push_back(generic);
return generic;
}
private:
friend class Declarations;
GenericList() : Declarable(Declarable::kGenericList) {}
std::vector<Generic*> list_;
};
typedef std::pair<Generic*, TypeVector> SpecializationKey;
class TypeAlias : public Declarable {
......@@ -320,6 +341,7 @@ std::ostream& operator<<(std::ostream& os, const Callable& m);
std::ostream& operator<<(std::ostream& os, const Variable& v);
std::ostream& operator<<(std::ostream& os, const Builtin& b);
std::ostream& operator<<(std::ostream& os, const RuntimeFunction& b);
std::ostream& operator<<(std::ostream& os, const Generic& g);
#undef DECLARE_DECLARABLE_BOILERPLATE
......
......@@ -193,8 +193,7 @@ void DeclarationVisitor::Visit(TorqueMacroDeclaration* decl,
}
void DeclarationVisitor::Visit(StandardDeclaration* decl) {
Signature signature =
MakeSignature(decl->callable, decl->callable->signature.get());
Signature signature = MakeSignature(decl->callable->signature.get());
Visit(decl->callable, signature, decl->body);
}
......@@ -203,33 +202,54 @@ void DeclarationVisitor::Visit(GenericDeclaration* decl) {
}
void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
Generic* generic = declarations()->LookupGeneric(decl->name);
SpecializationKey key = {generic, GetTypeVector(decl->generic_parameters)};
CallableNode* callable = generic->declaration()->callable;
{
Signature signature_with_types =
MakeSignature(callable, decl->signature.get());
GenericList* generic_list = declarations()->LookupGeneric(decl->name);
// Find the matching generic specialization based on the concrete parameter
// list.
CallableNode* matching_callable = nullptr;
SpecializationKey matching_key;
Signature signature_with_types = MakeSignature(decl->signature.get());
for (Generic* generic : generic_list->list()) {
SpecializationKey key = {generic, GetTypeVector(decl->generic_parameters)};
CallableNode* callable_candidate = generic->declaration()->callable;
// Abuse the Specialization nodes' scope to temporarily declare the
// specialization aliases for the generic types to compare signatures. This
// scope is never used for anything else, so it's OK to pollute it.
Declarations::NodeScopeActivator specialization_activator(declarations(),
decl);
Declarations::CleanNodeScopeActivator specialization_activator(
declarations(), decl);
DeclareSpecializedTypes(key);
Signature generic_signature_with_types =
MakeSignature(generic->declaration()->callable,
generic->declaration()->callable->signature.get());
if (!signature_with_types.HasSameTypesAs(generic_signature_with_types)) {
std::stringstream stream;
stream << "specialization of " << callable->name
<< " has incompatible parameter list or label list with generic "
"definition";
ReportError(stream.str());
MakeSignature(generic->declaration()->callable->signature.get());
if (signature_with_types.HasSameTypesAs(generic_signature_with_types)) {
if (matching_callable != nullptr) {
std::stringstream stream;
stream << "specialization of " << callable_candidate->name
<< " is ambigous, it matches more than one generic declaration ("
<< *matching_key.first << " and " << *key.first << ")";
ReportError(stream.str());
}
matching_callable = callable_candidate;
matching_key = key;
}
}
SpecializeGeneric(
{key, callable, decl->signature.get(), decl->body, decl->pos});
if (matching_callable == nullptr) {
std::stringstream stream;
stream << "specialization of " << decl->name
<< " doesn't match any generic declaration";
ReportError(stream.str());
}
// Make sure the declarations of the parameter types for the specialization
// are the ones from the matching generic.
{
Declarations::CleanNodeScopeActivator specialization_activator(
declarations(), decl);
DeclareSpecializedTypes(matching_key);
}
SpecializeGeneric({matching_key, matching_callable, decl->signature.get(),
decl->body, decl->pos});
}
void DeclarationVisitor::Visit(ReturnStatement* stmt) {
......@@ -298,15 +318,22 @@ void DeclarationVisitor::Visit(TryLabelStatement* stmt) {
void DeclarationVisitor::Visit(IdentifierExpression* expr) {
if (expr->generic_arguments.size() != 0) {
Generic* generic = declarations()->LookupGeneric(expr->name);
TypeVector specialization_types;
for (auto t : expr->generic_arguments) {
specialization_types.push_back(declarations()->GetType(t));
}
CallableNode* callable = generic->declaration()->callable;
QueueGenericSpecialization({generic, specialization_types}, callable,
callable->signature.get(),
generic->declaration()->body);
// Specialize all versions of the generic, since the exact parameter type
// list cannot be resolved until the call's parameter expressions are
// evaluated. This is an overly conservative but simple way to make sure
// that the correct specialization exists.
for (auto generic : declarations()->LookupGeneric(expr->name)->list()) {
CallableNode* callable = generic->declaration()->callable;
if (generic->declaration()->body) {
QueueGenericSpecialization({generic, specialization_types}, callable,
callable->signature.get(),
generic->declaration()->body);
}
}
}
}
......@@ -333,7 +360,7 @@ void DeclarationVisitor::Specialize(const SpecializationKey& key,
// TODO(tebbi): The error should point to the source position where the
// instantiation was requested.
CurrentSourcePosition::Scope scope(generic->declaration()->pos);
CurrentSourcePosition::Scope pos_scope(generic->declaration()->pos);
size_t generic_parameter_count =
generic->declaration()->generic_parameters.size();
if (generic_parameter_count != key.second.size()) {
......@@ -346,14 +373,16 @@ void DeclarationVisitor::Specialize(const SpecializationKey& key,
ReportError(stream.str());
}
Signature type_signature;
{
// Manually activate the specialized generic's scope when declaring the
// generic parameter specializations.
Declarations::GenericScopeActivator scope(declarations(), key);
Declarations::GenericScopeActivator namespace_scope(declarations(), key);
DeclareSpecializedTypes(key);
type_signature = MakeSignature(signature);
}
Visit(callable, MakeSignature(callable, signature), body);
Visit(callable, type_signature, body);
}
} // namespace torque
......
......@@ -59,7 +59,6 @@ class DeclarationVisitor : public FileVisitor {
Visit(expr->index);
}
void Visit(FieldAccessExpression* expr) { Visit(expr->object); }
void Visit(CastExpression* expr) { Visit(expr->value); }
void Visit(UnsafeCastExpression* expr) { Visit(expr->value); }
void Visit(ConvertExpression* expr) { Visit(expr->value); }
void Visit(BlockStatement* expr) {
......
......@@ -9,13 +9,15 @@ namespace v8 {
namespace internal {
namespace torque {
Scope* Declarations::GetNodeScope(const AstNode* node) {
Scope* Declarations::GetNodeScope(const AstNode* node, bool reset_scope) {
std::pair<const AstNode*, TypeVector> key(
node, current_generic_specialization_ == nullptr
? TypeVector()
: current_generic_specialization_->second);
auto i = scopes_.find(key);
if (i != scopes_.end()) return i->second;
if (!reset_scope) {
auto i = scopes_.find(key);
if (i != scopes_.end()) return i->second;
}
Scope* result = chain_.NewScope();
scopes_[key] = result;
return result;
......@@ -175,11 +177,11 @@ Builtin* Declarations::LookupBuiltin(const std::string& name) {
return nullptr;
}
Generic* Declarations::LookupGeneric(const std::string& name) {
Declarable* declarable = Lookup(name);
if (declarable != nullptr) {
if (declarable->IsGeneric()) {
return Generic::cast(declarable);
GenericList* Declarations::LookupGeneric(const std::string& name) {
Declarable* declarable_list = Lookup(name);
if (declarable_list != nullptr) {
if (declarable_list->IsGenericList()) {
return GenericList::cast(declarable_list);
}
ReportError(name + " is not a generic");
}
......@@ -308,9 +310,20 @@ void Declarations::DeclareConstant(const std::string& name, const Type* type,
Generic* Declarations::DeclareGeneric(const std::string& name, Module* module,
GenericDeclaration* generic) {
CheckAlreadyDeclared(name, "generic");
auto previous = chain_.Lookup(name);
GenericList* generic_list = nullptr;
if (previous == nullptr) {
generic_list = new GenericList();
Declare(name, std::unique_ptr<Declarable>(generic_list));
} else if (!previous->IsGenericList()) {
std::stringstream s;
s << "cannot redeclare non-generic " << name << " as a generic";
ReportError(s.str());
} else {
generic_list = GenericList::cast(previous);
}
Generic* result = new Generic(name, module, generic);
Declare(name, std::unique_ptr<Generic>(result));
generic_list->AddGeneric(result);
generic_declaration_scopes_[result] = GetScopeChainSnapshot();
return result;
}
......
......@@ -64,7 +64,7 @@ class Declarations {
Label* LookupLabel(const std::string& name);
Generic* LookupGeneric(const std::string& name);
GenericList* LookupGeneric(const std::string& name);
const AbstractType* DeclareAbstractType(const std::string& name,
const std::string& generated,
......@@ -109,12 +109,13 @@ class Declarations {
void PrintScopeChain() { chain_.Print(); }
class NodeScopeActivator;
class CleanNodeScopeActivator;
class GenericScopeActivator;
class ScopedGenericSpecializationKey;
class ScopedGenericScopeChainSnapshot;
private:
Scope* GetNodeScope(const AstNode* node);
Scope* GetNodeScope(const AstNode* node, bool reset_scope = false);
Scope* GetGenericScope(Generic* generic, const TypeVector& types);
template <class T>
......@@ -153,6 +154,15 @@ class Declarations::NodeScopeActivator {
Scope::Activator activator_;
};
class Declarations::CleanNodeScopeActivator {
public:
CleanNodeScopeActivator(Declarations* declarations, AstNode* node)
: activator_(declarations->GetNodeScope(node, true)) {}
private:
Scope::Activator activator_;
};
class Declarations::GenericScopeActivator {
public:
GenericScopeActivator(Declarations* declarations,
......
......@@ -5,14 +5,13 @@
#include "src/torque/file-visitor.h"
#include "src/torque/declarable.h"
#include "src/torque/parameter-difference.h"
namespace v8 {
namespace internal {
namespace torque {
Signature FileVisitor::MakeSignature(CallableNode* decl,
const CallableNodeSignature* signature) {
Declarations::NodeScopeActivator scope(declarations(), decl);
Signature FileVisitor::MakeSignature(const CallableNodeSignature* signature) {
LabelDeclarationVector definition_vector;
for (auto label : signature->labels) {
LabelDeclaration def = {label.name, GetTypeVector(label.types)};
......@@ -45,25 +44,40 @@ Callable* FileVisitor::LookupCall(const std::string& name,
} else if (declarable->IsRuntimeFunction()) {
result = RuntimeFunction::cast(declarable);
} else if (declarable->IsMacroList()) {
for (auto& m : MacroList::cast(declarable)->list()) {
std::vector<Macro*> candidates;
for (Macro* m : MacroList::cast(declarable)->list()) {
if (IsCompatibleSignature(m->signature().parameter_types,
parameter_types)) {
if (result != nullptr) {
std::stringstream stream;
stream << "multiple matching matching parameter list for macro "
<< name << ": (" << parameter_types << ") and ("
<< result->signature().parameter_types << ")";
ReportError(stream.str());
}
result = m;
candidates.push_back(m);
}
}
if (result == nullptr) {
std::stringstream stream;
stream << "no matching matching parameter list for macro " << name
<< ": call parameters were (" << parameter_types << ")";
ReportError(stream.str());
auto is_better_candidate = [&](Macro* a, Macro* b) {
return ParameterDifference(a->signature().parameter_types.types,
parameter_types)
.StrictlyBetterThan(ParameterDifference(
b->signature().parameter_types.types, parameter_types));
};
if (!candidates.empty()) {
Macro* best = *std::min_element(candidates.begin(), candidates.end(),
is_better_candidate);
for (Macro* candidate : candidates) {
if (candidate != best && !is_better_candidate(best, candidate)) {
std::stringstream s;
s << "ambiguous macro \"" << name << "\" with types ("
<< parameter_types << "), candidates:";
for (Macro* m : candidates) {
s << "\n (" << m->signature().parameter_types << ") => "
<< m->signature().return_type;
}
ReportError(s.str());
}
}
return best;
}
std::stringstream stream;
stream << "cannot find macro with name \"" << name << "\"";
ReportError(stream.str());
} else {
std::stringstream stream;
stream << "can't call " << declarable->type_name() << " " << name
......@@ -100,14 +114,13 @@ void FileVisitor::SpecializeGeneric(
completed_specializations_.end()) {
std::stringstream stream;
stream << "cannot redeclare specialization of "
<< specialization.key.first->declaration()->callable->name
<< " with types <" << specialization.key.second << ">";
<< specialization.key.first->name() << " with types <"
<< specialization.key.second << ">";
ReportError(stream.str());
}
if (!specialization.body) {
std::stringstream stream;
stream << "missing specialization of "
<< specialization.key.first->declaration()->callable->name
stream << "missing specialization of " << specialization.key.first->name()
<< " with types <" << specialization.key.second << ">";
ReportError(stream.str());
}
......
......@@ -70,8 +70,7 @@ class FileVisitor {
Callable* LookupCall(const std::string& name,
const TypeVector& parameter_types);
Signature MakeSignature(CallableNode* decl,
const CallableNodeSignature* signature);
Signature MakeSignature(const CallableNodeSignature* signature);
std::string GetGeneratedCallableName(const std::string& name,
const TypeVector& specialized_types);
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "src/torque/implementation-visitor.h"
#include "src/torque/parameter-difference.h"
#include "include/v8.h"
......@@ -151,7 +152,7 @@ void ImplementationVisitor::Visit(ModuleDeclaration* decl) {
void ImplementationVisitor::Visit(TorqueMacroDeclaration* decl,
const Signature& sig, Statement* body) {
Signature signature = MakeSignature(decl, decl->signature.get());
Signature signature = MakeSignature(decl->signature.get());
std::string name = GetGeneratedCallableName(
decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
const TypeVector& list = signature.types();
......@@ -501,13 +502,15 @@ VisitResult ImplementationVisitor::GetBuiltinCode(Builtin* builtin) {
VisitResult ImplementationVisitor::Visit(IdentifierExpression* expr) {
std::string name = expr->name;
if (expr->generic_arguments.size() != 0) {
Generic* generic = declarations()->LookupGeneric(expr->name);
TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
name = GetGeneratedCallableName(name, specialization_types);
CallableNode* callable = generic->declaration()->callable;
QueueGenericSpecialization({generic, specialization_types}, callable,
callable->signature.get(),
generic->declaration()->body);
GenericList* generic_list = declarations()->LookupGeneric(expr->name);
for (Generic* generic : generic_list->list()) {
TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
name = GetGeneratedCallableName(name, specialization_types);
CallableNode* callable = generic->declaration()->callable;
QueueGenericSpecialization({generic, specialization_types}, callable,
callable->signature.get(),
generic->declaration()->body);
}
}
if (Builtin* builtin = Builtin::DynamicCast(declarations()->Lookup(name))) {
......@@ -517,13 +520,6 @@ VisitResult ImplementationVisitor::Visit(IdentifierExpression* expr) {
return GenerateFetchFromLocation(expr, GetLocationReference(expr));
}
VisitResult ImplementationVisitor::Visit(CastExpression* expr) {
Arguments args;
args.parameters = {Visit(expr->value)};
args.labels = LabelsFromIdentifiers({expr->otherwise});
return GenerateOperation("cast<>", args, declarations()->GetType(expr->type));
}
VisitResult ImplementationVisitor::Visit(UnsafeCastExpression* expr) {
const Type* type = declarations()->GetType(expr->type);
if (type->IsConstexpr()) {
......@@ -1083,62 +1079,6 @@ void ImplementationVisitor::GenerateMacroFunctionDeclaration(
o << ")";
}
class ParameterDifference {
public:
ParameterDifference(const TypeVector& to, const TypeVector& from) {
DCHECK_EQ(to.size(), from.size());
for (size_t i = 0; i < to.size(); ++i) {
AddParameter(to[i], from[i]);
}
}
// An overload is selected if it is strictly better than all alternatives.
// This means that it has to be strictly better in at least one parameter,
// and better or equally good in all others.
//
// When comparing a pair of corresponding parameters of two overloads...
// ... they are considered equally good if:
// - They are equal.
// - Both require some implicit conversion.
// ... one is considered better if:
// - It is a strict subtype of the other.
// - It doesn't require an implicit conversion, while the other does.
bool StrictlyBetterThan(const ParameterDifference& other) const {
DCHECK_EQ(difference_.size(), other.difference_.size());
bool better_parameter_found = false;
for (size_t i = 0; i < difference_.size(); ++i) {
base::Optional<const Type*> a = difference_[i];
base::Optional<const Type*> b = other.difference_[i];
if (a == b) {
continue;
} else if (a && b && a != b && (*a)->IsSubtypeOf(*b)) {
DCHECK(!(*b)->IsSubtypeOf(*a));
better_parameter_found = true;
} else if (a && !b) {
better_parameter_found = true;
} else {
return false;
}
}
return better_parameter_found;
}
private:
// Pointwise difference between call arguments and a signature.
// {base::nullopt} means that an implicit conversion was necessary,
// otherwise we store the supertype found in the signature.
std::vector<base::Optional<const Type*>> difference_;
void AddParameter(const Type* to, const Type* from) {
if (from->IsSubtypeOf(to)) {
difference_.push_back(to);
} else if (IsAssignableFrom(to, from)) {
difference_.push_back(base::nullopt);
} else {
UNREACHABLE();
}
}
};
VisitResult ImplementationVisitor::GenerateOperation(
const std::string& operation, Arguments arguments,
......@@ -1563,14 +1503,30 @@ void ImplementationVisitor::Visit(StandardDeclaration* decl) {
}
void ImplementationVisitor::Visit(SpecializationDeclaration* decl) {
Generic* generic = declarations()->LookupGeneric(decl->name);
TypeVector specialization_types = GetTypeVector(decl->generic_parameters);
CallableNode* callable = generic->declaration()->callable;
SpecializeGeneric({{generic, specialization_types},
callable,
decl->signature.get(),
decl->body,
decl->pos});
Signature signature_with_types = MakeSignature(decl->signature.get());
Declarations::NodeScopeActivator specialization_activator(declarations(),
decl);
GenericList* generic_list = declarations()->LookupGeneric(decl->name);
for (Generic* generic : generic_list->list()) {
CallableNode* callable = generic->declaration()->callable;
Signature generic_signature_with_types =
MakeSignature(callable->signature.get());
if (signature_with_types.HasSameTypesAs(generic_signature_with_types)) {
TypeVector specialization_types = GetTypeVector(decl->generic_parameters);
SpecializeGeneric({{generic, specialization_types},
callable,
decl->signature.get(),
decl->body,
decl->pos});
return;
}
}
// Because the DeclarationVisitor already performed the same lookup
// as above to find aspecialization match and already threw if it didn't
// find one, failure to find a match here should never happen.
// TODO(danno): Remember the specialization found in the declaration visitor
// so that the lookup doesn't have to be repeated here.
UNREACHABLE();
}
VisitResult ImplementationVisitor::Visit(CallExpression* expr,
......@@ -1579,14 +1535,18 @@ VisitResult ImplementationVisitor::Visit(CallExpression* expr,
std::string name = expr->callee.name;
bool has_template_arguments = expr->callee.generic_arguments.size() != 0;
if (has_template_arguments) {
Generic* generic = declarations()->LookupGeneric(expr->callee.name);
TypeVector specialization_types =
GetTypeVector(expr->callee.generic_arguments);
name = GetGeneratedCallableName(name, specialization_types);
CallableNode* callable = generic->declaration()->callable;
QueueGenericSpecialization({generic, specialization_types}, callable,
callable->signature.get(),
generic->declaration()->body);
for (auto generic :
declarations()->LookupGeneric(expr->callee.name)->list()) {
CallableNode* callable = generic->declaration()->callable;
if (generic->declaration()->body) {
QueueGenericSpecialization({generic, specialization_types}, callable,
callable->signature.get(),
generic->declaration()->body);
}
}
}
for (Expression* arg : expr->arguments)
arguments.parameters.push_back(Visit(arg));
......
......@@ -83,7 +83,6 @@ class ImplementationVisitor : public FileVisitor {
return GenerateFetchFromLocation(expr, GetLocationReference(expr));
}
VisitResult Visit(CastExpression* expr);
VisitResult Visit(UnsafeCastExpression* expr);
VisitResult Visit(ConvertExpression* expr);
......@@ -227,7 +226,7 @@ class ImplementationVisitor : public FileVisitor {
const CallableNodeSignature* signature,
Statement* body) override {
Declarations::GenericScopeActivator scope(declarations(), key);
Visit(callable, MakeSignature(callable, signature), body);
Visit(callable, MakeSignature(signature), body);
}
std::string NewTempVariable();
......
// Copyright 2018 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.
#ifndef V8_TORQUE_PARAMETER_DIFFERENCE_H_
#define V8_TORQUE_PARAMETER_DIFFERENCE_H_
#include <vector>
#include "src/torque/types.h"
namespace v8 {
namespace internal {
namespace torque {
class ParameterDifference {
public:
ParameterDifference(const TypeVector& to, const TypeVector& from) {
DCHECK_EQ(to.size(), from.size());
for (size_t i = 0; i < to.size(); ++i) {
AddParameter(to[i], from[i]);
}
}
// An overload is selected if it is strictly better than all alternatives.
// This means that it has to be strictly better in at least one parameter,
// and better or equally good in all others.
//
// When comparing a pair of corresponding parameters of two overloads...
// ... they are considered equally good if:
// - They are equal.
// - Both require some implicit conversion.
// ... one is considered better if:
// - It is a strict subtype of the other.
// - It doesn't require an implicit conversion, while the other does.
bool StrictlyBetterThan(const ParameterDifference& other) const {
DCHECK_EQ(difference_.size(), other.difference_.size());
bool better_parameter_found = false;
for (size_t i = 0; i < difference_.size(); ++i) {
base::Optional<const Type*> a = difference_[i];
base::Optional<const Type*> b = other.difference_[i];
if (a == b) {
continue;
} else if (a && b && a != b && (*a)->IsSubtypeOf(*b)) {
DCHECK(!(*b)->IsSubtypeOf(*a));
better_parameter_found = true;
} else if (a && !b) {
better_parameter_found = true;
} else {
return false;
}
}
return better_parameter_found;
}
private:
// Pointwise difference between call arguments and a signature.
// {base::nullopt} means that an implicit conversion was necessary,
// otherwise we store the supertype found in the signature.
std::vector<base::Optional<const Type*>> difference_;
void AddParameter(const Type* to, const Type* from) {
if (from->IsSubtypeOf(to)) {
difference_.push_back(to);
} else if (IsAssignableFrom(to, from)) {
difference_.push_back(base::nullopt);
} else {
UNREACHABLE();
}
}
};
} // namespace torque
} // namespace internal
} // namespace v8
#endif // V8_TORQUE_PARAMETER_DIFFERENCE_H_
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