Commit 9ef4df2f authored by Simon Zünd's avatar Simon Zünd Committed by Commit Bot

[torque] Add unsafe cast to Torque.

This CL is a proposal to add "checked" casts (CAST in CSA) to the Torque language.
The CL adds the "unsafe_cast<>" operator that emits a "CAST".

Example:

let n: Number = ...;
...
if (TaggedIsSmi(n)) {
  let m: Smi = unsafe_cast<Smi>(n);
  ...
}

The cast wont incur a runtime overhead now.

R=tebbi@chromium.org

Change-Id: I9fca90d1d11e61617ba0270e5022fd66200e2195
Reviewed-on: https://chromium-review.googlesource.com/1070151
Commit-Queue: Simon Zünd <szuend@google.com>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53416}
parent 0fd549f8
...@@ -18,6 +18,7 @@ IMPLICIT: 'implicit'; ...@@ -18,6 +18,7 @@ IMPLICIT: 'implicit';
DEFERRED: 'deferred'; DEFERRED: 'deferred';
IF: 'if'; IF: 'if';
CAST_KEYWORD: 'cast'; CAST_KEYWORD: 'cast';
UNSAFE_CAST_KEYWORD: 'unsafe_cast';
CONVERT_KEYWORD: 'convert'; CONVERT_KEYWORD: 'convert';
FOR: 'for'; FOR: 'for';
WHILE: 'while'; WHILE: 'while';
...@@ -216,6 +217,7 @@ primaryExpression ...@@ -216,6 +217,7 @@ primaryExpression
| DECIMAL_LITERAL | DECIMAL_LITERAL
| STRING_LITERAL | STRING_LITERAL
| CAST_KEYWORD '<' type '>' '(' expression ')' OTHERWISE IDENTIFIER | CAST_KEYWORD '<' type '>' '(' expression ')' OTHERWISE IDENTIFIER
| UNSAFE_CAST_KEYWORD '<' type '>' '(' expression ')'
| CONVERT_KEYWORD '<' type '>' '(' expression ')' | CONVERT_KEYWORD '<' type '>' '(' expression ')'
| ('(' expression ')'); | ('(' expression ')');
......
This diff is collapsed.
...@@ -43,60 +43,61 @@ class TorqueLexer : public antlr4::Lexer { ...@@ -43,60 +43,61 @@ class TorqueLexer : public antlr4::Lexer {
DEFERRED = 28, DEFERRED = 28,
IF = 29, IF = 29,
CAST_KEYWORD = 30, CAST_KEYWORD = 30,
CONVERT_KEYWORD = 31, UNSAFE_CAST_KEYWORD = 31,
FOR = 32, CONVERT_KEYWORD = 32,
WHILE = 33, FOR = 33,
RETURN = 34, WHILE = 34,
CONSTEXPR = 35, RETURN = 35,
CONTINUE = 36, CONSTEXPR = 36,
BREAK = 37, CONTINUE = 37,
GOTO = 38, BREAK = 38,
OTHERWISE = 39, GOTO = 39,
TRY = 40, OTHERWISE = 40,
CATCH = 41, TRY = 41,
LABEL = 42, CATCH = 42,
LABELS = 43, LABEL = 43,
TAIL = 44, LABELS = 44,
ISNT = 45, TAIL = 45,
IS = 46, ISNT = 46,
LET = 47, IS = 47,
EXTERN = 48, LET = 48,
ASSERT_TOKEN = 49, EXTERN = 49,
CHECK_TOKEN = 50, ASSERT_TOKEN = 50,
UNREACHABLE_TOKEN = 51, CHECK_TOKEN = 51,
DEBUG_TOKEN = 52, UNREACHABLE_TOKEN = 52,
ASSIGNMENT = 53, DEBUG_TOKEN = 53,
ASSIGNMENT_OPERATOR = 54, ASSIGNMENT = 54,
EQUAL = 55, ASSIGNMENT_OPERATOR = 55,
PLUS = 56, EQUAL = 56,
MINUS = 57, PLUS = 57,
MULTIPLY = 58, MINUS = 58,
DIVIDE = 59, MULTIPLY = 59,
MODULO = 60, DIVIDE = 60,
BIT_OR = 61, MODULO = 61,
BIT_AND = 62, BIT_OR = 62,
BIT_NOT = 63, BIT_AND = 63,
MAX = 64, BIT_NOT = 64,
MIN = 65, MAX = 65,
NOT_EQUAL = 66, MIN = 66,
LESS_THAN = 67, NOT_EQUAL = 67,
LESS_THAN_EQUAL = 68, LESS_THAN = 68,
GREATER_THAN = 69, LESS_THAN_EQUAL = 69,
GREATER_THAN_EQUAL = 70, GREATER_THAN = 70,
SHIFT_LEFT = 71, GREATER_THAN_EQUAL = 71,
SHIFT_RIGHT = 72, SHIFT_LEFT = 72,
SHIFT_RIGHT_ARITHMETIC = 73, SHIFT_RIGHT = 73,
VARARGS = 74, SHIFT_RIGHT_ARITHMETIC = 74,
EQUALITY_OPERATOR = 75, VARARGS = 75,
INCREMENT = 76, EQUALITY_OPERATOR = 76,
DECREMENT = 77, INCREMENT = 77,
NOT = 78, DECREMENT = 78,
STRING_LITERAL = 79, NOT = 79,
IDENTIFIER = 80, STRING_LITERAL = 80,
WS = 81, IDENTIFIER = 81,
BLOCK_COMMENT = 82, WS = 82,
LINE_COMMENT = 83, BLOCK_COMMENT = 83,
DECIMAL_LITERAL = 84 LINE_COMMENT = 84,
DECIMAL_LITERAL = 85
}; };
explicit TorqueLexer(antlr4::CharStream* input); explicit TorqueLexer(antlr4::CharStream* input);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -43,60 +43,61 @@ class TorqueParser : public antlr4::Parser { ...@@ -43,60 +43,61 @@ class TorqueParser : public antlr4::Parser {
DEFERRED = 28, DEFERRED = 28,
IF = 29, IF = 29,
CAST_KEYWORD = 30, CAST_KEYWORD = 30,
CONVERT_KEYWORD = 31, UNSAFE_CAST_KEYWORD = 31,
FOR = 32, CONVERT_KEYWORD = 32,
WHILE = 33, FOR = 33,
RETURN = 34, WHILE = 34,
CONSTEXPR = 35, RETURN = 35,
CONTINUE = 36, CONSTEXPR = 36,
BREAK = 37, CONTINUE = 37,
GOTO = 38, BREAK = 38,
OTHERWISE = 39, GOTO = 39,
TRY = 40, OTHERWISE = 40,
CATCH = 41, TRY = 41,
LABEL = 42, CATCH = 42,
LABELS = 43, LABEL = 43,
TAIL = 44, LABELS = 44,
ISNT = 45, TAIL = 45,
IS = 46, ISNT = 46,
LET = 47, IS = 47,
EXTERN = 48, LET = 48,
ASSERT_TOKEN = 49, EXTERN = 49,
CHECK_TOKEN = 50, ASSERT_TOKEN = 50,
UNREACHABLE_TOKEN = 51, CHECK_TOKEN = 51,
DEBUG_TOKEN = 52, UNREACHABLE_TOKEN = 52,
ASSIGNMENT = 53, DEBUG_TOKEN = 53,
ASSIGNMENT_OPERATOR = 54, ASSIGNMENT = 54,
EQUAL = 55, ASSIGNMENT_OPERATOR = 55,
PLUS = 56, EQUAL = 56,
MINUS = 57, PLUS = 57,
MULTIPLY = 58, MINUS = 58,
DIVIDE = 59, MULTIPLY = 59,
MODULO = 60, DIVIDE = 60,
BIT_OR = 61, MODULO = 61,
BIT_AND = 62, BIT_OR = 62,
BIT_NOT = 63, BIT_AND = 63,
MAX = 64, BIT_NOT = 64,
MIN = 65, MAX = 65,
NOT_EQUAL = 66, MIN = 66,
LESS_THAN = 67, NOT_EQUAL = 67,
LESS_THAN_EQUAL = 68, LESS_THAN = 68,
GREATER_THAN = 69, LESS_THAN_EQUAL = 69,
GREATER_THAN_EQUAL = 70, GREATER_THAN = 70,
SHIFT_LEFT = 71, GREATER_THAN_EQUAL = 71,
SHIFT_RIGHT = 72, SHIFT_LEFT = 72,
SHIFT_RIGHT_ARITHMETIC = 73, SHIFT_RIGHT = 73,
VARARGS = 74, SHIFT_RIGHT_ARITHMETIC = 74,
EQUALITY_OPERATOR = 75, VARARGS = 75,
INCREMENT = 76, EQUALITY_OPERATOR = 76,
DECREMENT = 77, INCREMENT = 77,
NOT = 78, DECREMENT = 78,
STRING_LITERAL = 79, NOT = 79,
IDENTIFIER = 80, STRING_LITERAL = 80,
WS = 81, IDENTIFIER = 81,
BLOCK_COMMENT = 82, WS = 82,
LINE_COMMENT = 83, BLOCK_COMMENT = 83,
DECIMAL_LITERAL = 84 LINE_COMMENT = 84,
DECIMAL_LITERAL = 85
}; };
enum { enum {
...@@ -737,6 +738,7 @@ class TorqueParser : public antlr4::Parser { ...@@ -737,6 +738,7 @@ class TorqueParser : public antlr4::Parser {
ExpressionContext* expression(); ExpressionContext* expression();
antlr4::tree::TerminalNode* OTHERWISE(); antlr4::tree::TerminalNode* OTHERWISE();
antlr4::tree::TerminalNode* IDENTIFIER(); antlr4::tree::TerminalNode* IDENTIFIER();
antlr4::tree::TerminalNode* UNSAFE_CAST_KEYWORD();
antlr4::tree::TerminalNode* CONVERT_KEYWORD(); antlr4::tree::TerminalNode* CONVERT_KEYWORD();
void enterRule(antlr4::tree::ParseTreeListener* listener) override; void enterRule(antlr4::tree::ParseTreeListener* listener) override;
......
...@@ -553,6 +553,10 @@ antlrcpp::Any AstGenerator::visitPrimaryExpression( ...@@ -553,6 +553,10 @@ antlrcpp::Any AstGenerator::visitPrimaryExpression(
return implicit_cast<Expression*>(RegisterNode(new ConvertExpression{ return implicit_cast<Expression*>(RegisterNode(new ConvertExpression{
Pos(context), GetType(context->type()), Pos(context), GetType(context->type()),
context->expression()->accept(this).as<Expression*>()})); context->expression()->accept(this).as<Expression*>()}));
if (context->UNSAFE_CAST_KEYWORD())
return implicit_cast<Expression*>(RegisterNode(new UnsafeCastExpression{
Pos(context), GetType(context->type()),
context->expression()->accept(this).as<Expression*>()}));
if (context->CAST_KEYWORD()) if (context->CAST_KEYWORD())
return implicit_cast<Expression*>(RegisterNode(new CastExpression{ return implicit_cast<Expression*>(RegisterNode(new CastExpression{
Pos(context), GetType(context->type()), Pos(context), GetType(context->type()),
......
...@@ -40,6 +40,7 @@ DECLARE_CONTEXTUAL_VARIABLE(CurrentSourcePosition, SourcePosition) ...@@ -40,6 +40,7 @@ DECLARE_CONTEXTUAL_VARIABLE(CurrentSourcePosition, SourcePosition)
V(AssignmentExpression) \ V(AssignmentExpression) \
V(IncrementDecrementExpression) \ V(IncrementDecrementExpression) \
V(CastExpression) \ V(CastExpression) \
V(UnsafeCastExpression) \
V(ConvertExpression) V(ConvertExpression)
#define AST_TYPE_EXPRESSION_NODE_KIND_LIST(V) \ #define AST_TYPE_EXPRESSION_NODE_KIND_LIST(V) \
...@@ -320,6 +321,14 @@ struct ConvertExpression : Expression { ...@@ -320,6 +321,14 @@ struct ConvertExpression : Expression {
Expression* value; Expression* value;
}; };
struct UnsafeCastExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(UnsafeCastExpression)
UnsafeCastExpression(SourcePosition p, TypeExpression* t, Expression* v)
: Expression(kKind, p), type(t), value(v) {}
TypeExpression* type;
Expression* value;
};
struct ElementAccessExpression : LocationExpression { struct ElementAccessExpression : LocationExpression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ElementAccessExpression) DEFINE_AST_NODE_LEAF_BOILERPLATE(ElementAccessExpression)
ElementAccessExpression(SourcePosition p, Expression* a, Expression* i) ElementAccessExpression(SourcePosition p, Expression* a, Expression* i)
......
...@@ -60,6 +60,7 @@ class DeclarationVisitor : public FileVisitor { ...@@ -60,6 +60,7 @@ class DeclarationVisitor : public FileVisitor {
} }
void Visit(FieldAccessExpression* expr) { Visit(expr->object); } void Visit(FieldAccessExpression* expr) { Visit(expr->object); }
void Visit(CastExpression* expr) { Visit(expr->value); } void Visit(CastExpression* expr) { Visit(expr->value); }
void Visit(UnsafeCastExpression* expr) { Visit(expr->value); }
void Visit(ConvertExpression* expr) { Visit(expr->value); } void Visit(ConvertExpression* expr) { Visit(expr->value); }
void Visit(BlockStatement* expr) { void Visit(BlockStatement* expr) {
Declarations::NodeScopeActivator scope(declarations(), expr); Declarations::NodeScopeActivator scope(declarations(), expr);
......
...@@ -526,6 +526,21 @@ VisitResult ImplementationVisitor::Visit(CastExpression* expr) { ...@@ -526,6 +526,21 @@ VisitResult ImplementationVisitor::Visit(CastExpression* expr) {
return GenerateOperation("cast<>", args, declarations()->GetType(expr->type)); return GenerateOperation("cast<>", args, declarations()->GetType(expr->type));
} }
VisitResult ImplementationVisitor::Visit(UnsafeCastExpression* expr) {
const Type* type = declarations()->GetType(expr->type);
if (type->IsConstexpr()) {
ReportError("unsafe_cast can only be used for non constexpr types.");
}
VisitResult result = Visit(expr->value);
std::string result_variable_name = GenerateNewTempVariable(type);
source_out() << "CAST(";
source_out() << result.variable();
source_out() << ");\n";
return VisitResult{type, result_variable_name};
}
VisitResult ImplementationVisitor::Visit(ConvertExpression* expr) { VisitResult ImplementationVisitor::Visit(ConvertExpression* expr) {
Arguments args; Arguments args;
args.parameters = {Visit(expr->value)}; args.parameters = {Visit(expr->value)};
......
...@@ -84,6 +84,7 @@ class ImplementationVisitor : public FileVisitor { ...@@ -84,6 +84,7 @@ class ImplementationVisitor : public FileVisitor {
} }
VisitResult Visit(CastExpression* expr); VisitResult Visit(CastExpression* expr);
VisitResult Visit(UnsafeCastExpression* expr);
VisitResult Visit(ConvertExpression* expr); VisitResult Visit(ConvertExpression* expr);
void Visit(ModuleDeclaration* decl); void Visit(ModuleDeclaration* decl);
......
...@@ -156,6 +156,20 @@ TEST(TestFunctionPointerToGeneric) { ...@@ -156,6 +156,20 @@ TEST(TestFunctionPointerToGeneric) {
ft.Call(); ft.Call();
} }
TEST(TestUnsafeCast) {
Isolate* isolate(CcTest::InitIsolateOnce());
CodeAssemblerTester asm_tester(isolate, 0);
TestBuiltinsFromDSLAssembler m(asm_tester.state());
{
Node* temp = m.SmiConstant(0);
Node* n = m.SmiConstant(10);
m.Return(m.TestUnsafeCast(m.UncheckedCast<Context>(temp),
m.UncheckedCast<Number>(n)));
}
FunctionTester ft(asm_tester.GenerateCode(), 0);
ft.CheckCall(ft.true_value());
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -193,4 +193,14 @@ module test { ...@@ -193,4 +193,14 @@ module test {
macro TestTypeAlias(x : SmiToSmi) : Code { macro TestTypeAlias(x : SmiToSmi) : Code {
return x; return x;
} }
macro TestUnsafeCast(c: Context, n: Number): Boolean {
if (TaggedIsSmi(n)) {
let m: Smi = unsafe_cast<Smi>(n);
check(TestHelperPlus1(c, m) == 11);
return True;
}
return False;
}
} }
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