[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: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53416}
This commit is contained in:
Simon Zünd 2018-05-29 16:18:39 +02:00 committed by Commit Bot
parent 0fd549f885
commit 9ef4df2f30
12 changed files with 1733 additions and 1616 deletions

View File

@ -18,6 +18,7 @@ IMPLICIT: 'implicit';
DEFERRED: 'deferred';
IF: 'if';
CAST_KEYWORD: 'cast';
UNSAFE_CAST_KEYWORD: 'unsafe_cast';
CONVERT_KEYWORD: 'convert';
FOR: 'for';
WHILE: 'while';
@ -216,6 +217,7 @@ primaryExpression
| DECIMAL_LITERAL
| STRING_LITERAL
| CAST_KEYWORD '<' type '>' '(' expression ')' OTHERWISE IDENTIFIER
| UNSAFE_CAST_KEYWORD '<' type '>' '(' expression ')'
| CONVERT_KEYWORD '<' type '>' '(' expression ')'
| ('(' expression ')');

File diff suppressed because it is too large Load Diff

View File

@ -43,60 +43,61 @@ class TorqueLexer : public antlr4::Lexer {
DEFERRED = 28,
IF = 29,
CAST_KEYWORD = 30,
CONVERT_KEYWORD = 31,
FOR = 32,
WHILE = 33,
RETURN = 34,
CONSTEXPR = 35,
CONTINUE = 36,
BREAK = 37,
GOTO = 38,
OTHERWISE = 39,
TRY = 40,
CATCH = 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 = 31,
CONVERT_KEYWORD = 32,
FOR = 33,
WHILE = 34,
RETURN = 35,
CONSTEXPR = 36,
CONTINUE = 37,
BREAK = 38,
GOTO = 39,
OTHERWISE = 40,
TRY = 41,
CATCH = 42,
LABEL = 43,
LABELS = 44,
TAIL = 45,
ISNT = 46,
IS = 47,
LET = 48,
EXTERN = 49,
ASSERT_TOKEN = 50,
CHECK_TOKEN = 51,
UNREACHABLE_TOKEN = 52,
DEBUG_TOKEN = 53,
ASSIGNMENT = 54,
ASSIGNMENT_OPERATOR = 55,
EQUAL = 56,
PLUS = 57,
MINUS = 58,
MULTIPLY = 59,
DIVIDE = 60,
MODULO = 61,
BIT_OR = 62,
BIT_AND = 63,
BIT_NOT = 64,
MAX = 65,
MIN = 66,
NOT_EQUAL = 67,
LESS_THAN = 68,
LESS_THAN_EQUAL = 69,
GREATER_THAN = 70,
GREATER_THAN_EQUAL = 71,
SHIFT_LEFT = 72,
SHIFT_RIGHT = 73,
SHIFT_RIGHT_ARITHMETIC = 74,
VARARGS = 75,
EQUALITY_OPERATOR = 76,
INCREMENT = 77,
DECREMENT = 78,
NOT = 79,
STRING_LITERAL = 80,
IDENTIFIER = 81,
WS = 82,
BLOCK_COMMENT = 83,
LINE_COMMENT = 84,
DECIMAL_LITERAL = 85
};
explicit TorqueLexer(antlr4::CharStream* input);

File diff suppressed because it is too large Load Diff

View File

@ -43,60 +43,61 @@ class TorqueParser : public antlr4::Parser {
DEFERRED = 28,
IF = 29,
CAST_KEYWORD = 30,
CONVERT_KEYWORD = 31,
FOR = 32,
WHILE = 33,
RETURN = 34,
CONSTEXPR = 35,
CONTINUE = 36,
BREAK = 37,
GOTO = 38,
OTHERWISE = 39,
TRY = 40,
CATCH = 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 = 31,
CONVERT_KEYWORD = 32,
FOR = 33,
WHILE = 34,
RETURN = 35,
CONSTEXPR = 36,
CONTINUE = 37,
BREAK = 38,
GOTO = 39,
OTHERWISE = 40,
TRY = 41,
CATCH = 42,
LABEL = 43,
LABELS = 44,
TAIL = 45,
ISNT = 46,
IS = 47,
LET = 48,
EXTERN = 49,
ASSERT_TOKEN = 50,
CHECK_TOKEN = 51,
UNREACHABLE_TOKEN = 52,
DEBUG_TOKEN = 53,
ASSIGNMENT = 54,
ASSIGNMENT_OPERATOR = 55,
EQUAL = 56,
PLUS = 57,
MINUS = 58,
MULTIPLY = 59,
DIVIDE = 60,
MODULO = 61,
BIT_OR = 62,
BIT_AND = 63,
BIT_NOT = 64,
MAX = 65,
MIN = 66,
NOT_EQUAL = 67,
LESS_THAN = 68,
LESS_THAN_EQUAL = 69,
GREATER_THAN = 70,
GREATER_THAN_EQUAL = 71,
SHIFT_LEFT = 72,
SHIFT_RIGHT = 73,
SHIFT_RIGHT_ARITHMETIC = 74,
VARARGS = 75,
EQUALITY_OPERATOR = 76,
INCREMENT = 77,
DECREMENT = 78,
NOT = 79,
STRING_LITERAL = 80,
IDENTIFIER = 81,
WS = 82,
BLOCK_COMMENT = 83,
LINE_COMMENT = 84,
DECIMAL_LITERAL = 85
};
enum {
@ -737,6 +738,7 @@ class TorqueParser : public antlr4::Parser {
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;

View File

@ -553,6 +553,10 @@ antlrcpp::Any AstGenerator::visitPrimaryExpression(
return implicit_cast<Expression*>(RegisterNode(new ConvertExpression{
Pos(context), GetType(context->type()),
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())
return implicit_cast<Expression*>(RegisterNode(new CastExpression{
Pos(context), GetType(context->type()),

View File

@ -40,6 +40,7 @@ DECLARE_CONTEXTUAL_VARIABLE(CurrentSourcePosition, SourcePosition)
V(AssignmentExpression) \
V(IncrementDecrementExpression) \
V(CastExpression) \
V(UnsafeCastExpression) \
V(ConvertExpression)
#define AST_TYPE_EXPRESSION_NODE_KIND_LIST(V) \
@ -320,6 +321,14 @@ struct ConvertExpression : Expression {
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 {
DEFINE_AST_NODE_LEAF_BOILERPLATE(ElementAccessExpression)
ElementAccessExpression(SourcePosition p, Expression* a, Expression* i)

View File

@ -60,6 +60,7 @@ class DeclarationVisitor : public FileVisitor {
}
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) {
Declarations::NodeScopeActivator scope(declarations(), expr);

View File

@ -526,6 +526,21 @@ VisitResult ImplementationVisitor::Visit(CastExpression* expr) {
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) {
Arguments args;
args.parameters = {Visit(expr->value)};

View File

@ -84,6 +84,7 @@ class ImplementationVisitor : public FileVisitor {
}
VisitResult Visit(CastExpression* expr);
VisitResult Visit(UnsafeCastExpression* expr);
VisitResult Visit(ConvertExpression* expr);
void Visit(ModuleDeclaration* decl);

View File

@ -156,6 +156,20 @@ TEST(TestFunctionPointerToGeneric) {
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 internal
} // namespace v8

View File

@ -193,4 +193,14 @@ module test {
macro TestTypeAlias(x : SmiToSmi) : Code {
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;
}
}