| Index: src/typing-asm.cc
|
| diff --git a/src/typing-asm.cc b/src/typing-asm.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a671f386ed6bb64091641628a677f6ea13d24de1
|
| --- /dev/null
|
| +++ b/src/typing-asm.cc
|
| @@ -0,0 +1,990 @@
|
| +// Copyright 2013 the V8 project authors. All rights reserved.
|
| +// Redistribution and use in source and binary forms, with or without
|
| +// modification, are permitted provided that the following conditions are
|
| +// met:
|
| +//
|
| +// * Redistributions of source code must retain the above copyright
|
| +// notice, this list of conditions and the following disclaimer.
|
| +// * Redistributions in binary form must reproduce the above
|
| +// copyright notice, this list of conditions and the following
|
| +// disclaimer in the documentation and/or other materials provided
|
| +// with the distribution.
|
| +// * Neither the name of Google Inc. nor the names of its
|
| +// contributors may be used to endorse or promote products derived
|
| +// from this software without specific prior written permission.
|
| +//
|
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +
|
| +#if 0
|
| +#include "typing-asm.h"
|
| +
|
| +#include "parser.h" // for CompileTimeValue; TODO(rossberg): should move
|
| +#include "scopes.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +
|
| +
|
| +AsmTyper::AsmTyper(CompilationInfo* info) : info_(info), valid_(true) {
|
| + InitializeAstVisitor(info->isolate(), info->zone());
|
| +}
|
| +
|
| +
|
| +bool AsmTyper::Run(CompilationInfo* info) {
|
| + AsmTyper* visitor = new(info->zone()) AsmTyper(info);
|
| + visitor->VisitAsmModule(info->function());
|
| +#ifdef DEBUG
|
| + if (FLAG_print_asm_env && visitor->valid_ && !visitor->HasStackOverflow())
|
| + info->scope()->Print();
|
| +#endif
|
| + return visitor->valid_ && !visitor->HasStackOverflow();
|
| +}
|
| +
|
| +
|
| +#define RECURSE(call) \
|
| + do { \
|
| + DCHECK(valid_ && !HasStackOverflow()); \
|
| + call; \
|
| + if (!valid_ || HasStackOverflow()) return; \
|
| + } while (false)
|
| +
|
| +#define RECURSE_STMT(stmt) RECURSE(Visit(stmt))
|
| +
|
| +#ifdef DEBUG
|
| +#define PRINT_TYPE(label, type) { PrintF("%s", label); type->TypePrint(); }
|
| +#else
|
| +#define PRINT_TYPE(label, type) {}
|
| +#endif
|
| +
|
| +#define RECURSE_EXPR(expr, expected_type, msg) \
|
| + do { \
|
| + Handle<Type> save = expected_type_; \
|
| + expected_type_ = handle_type(expected_type); \
|
| + RECURSE(Visit(expr)); \
|
| + Handle<Type> bounded_type = handle_type( \
|
| + Type::Intersect(computed_type_, expected_type_)); \
|
| + if (bounded_type->Is(Type::None())) { \
|
| + PRINT_TYPE("Computed type: ", computed_type_); \
|
| + PRINT_TYPE("Expected type: ", expected_type_); \
|
| + } \
|
| + if (bounded_type->Is(Type::None())) FAIL(expr, msg); \
|
| + expected_type_ = save; \
|
| + } while (false)
|
| +
|
| +#define RETURN(expr, type) \
|
| + do { \
|
| + computed_type_ = handle_type(type); \
|
| + Handle<Type> bounded_type = handle_type( \
|
| + Type::Intersect(computed_type_, expected_type_)); \
|
| + expr->set_bounds(Bounds(bounded_type)); \
|
| + return; \
|
| + } while (false)
|
| +
|
| +#define RETURN_ANNOT(expr, type) \
|
| + do { \
|
| + computed_type_ = handle_type(type); \
|
| + expr->set_bounds(Bounds(computed_type_)); \
|
| + return; \
|
| + } while (false)
|
| +
|
| +#define FAIL(node, msg) \
|
| + do { \
|
| + valid_ = false; \
|
| + int line = node->position() == RelocInfo::kNoPosition \
|
| + ? -1 : GetScriptLineNumberSafe(info_->script(), node->position()); \
|
| + PrintF("asm: line %d: %s\n", line, msg); \
|
| + return; \
|
| + } while (false)
|
| +
|
| +
|
| +
|
| +void AsmTyper::VisitAsmModule(FunctionLiteral* fun) {
|
| + Scope* scope = fun->scope();
|
| + DCHECK(scope->asm_mode() == ASM_MODULE);
|
| + DCHECK(scope->is_function_scope());
|
| +
|
| + // Module parameters.
|
| + for (int i = 0; i < scope->num_parameters(); ++i) {
|
| + Variable* param = scope->parameter(i);
|
| + DCHECK(param->type().is_null());
|
| + switch (i) {
|
| + case 0: // stdlib
|
| + param->set_type(StdlibType());
|
| + break;
|
| + case 1: // foreign
|
| + param->set_type(handle_type(Type::Object()));
|
| + break;
|
| + case 2: // heap
|
| + // TODO(bradnelson): Fix me
|
| + // param->set_type(handle_type(Type::Buffer()));
|
| + param->set_type(handle_type(Type::Object()));
|
| + break;
|
| + default:
|
| + param->set_type(handle_type(Type::Any()));
|
| + }
|
| + }
|
| +
|
| + // Declarations.
|
| + VariableDeclaration* decl = scope->function();
|
| + if (decl != NULL)
|
| + decl->proxy()->var()->set_type(handle_type(Type::Function()));
|
| + RECURSE(VisitDeclarations(scope->declarations()));
|
| +
|
| + // Body.
|
| + return_type_ = handle_type(Type::Object());
|
| + RECURSE(VisitStatements(fun->body()));
|
| +
|
| +/*
|
| + // Global variables.
|
| + ZoneList<Statement*>* stmts = fun->body();
|
| + bool good = true;
|
| + int i;
|
| + for (i = 0; i < stmts->length() - 1; ++i) {
|
| + good = false;
|
| + ExpressionStatement* stmt = stmts->at(i)->AsExpressionStatement();
|
| + if (stmt == NULL) break;
|
| + Assignment* expr = stmt->expression()->AsAssignment();
|
| + if (expr == NULL || expr->is_compound()) break;
|
| + VariableProxy* proxy = expr->target()->AsVariableProxy();
|
| + if (proxy == NULL) break;
|
| + Variable* var = proxy->var();
|
| + if (var->location() != Variable::PARAMETER) {
|
| + DCHECK(var->type().is_null());
|
| + RECURSE(VisitExpressionAnnotation(expr->value()));
|
| + var->set_type(computed_type_);
|
| + }
|
| + good = true;
|
| + }
|
| + if (!good) FAIL(stmts->at(i), "invalid statement in module body");
|
| +
|
| + // Export.
|
| +*/
|
| +
|
| + // Function bodies.
|
| + ZoneList<Declaration*>* decls = scope->declarations();
|
| + for (int i = 0; i < decls->length(); ++i) {
|
| + FunctionDeclaration* decl = decls->at(i)->AsFunctionDeclaration();
|
| + if (decl != NULL) {
|
| + RECURSE_EXPR(decl->fun(), Type::Function(),
|
| + "function literal expected to be a function");
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitVariableDeclaration(VariableDeclaration* decl) {
|
| + Variable* var = decl->proxy()->var();
|
| + if (var->location() != Variable::PARAMETER) {
|
| + DCHECK(var->type().is_null());
|
| + var->set_type(handle_type(Type::Any()));
|
| + }
|
| + DCHECK(!var->type().is_null());
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitFunctionDeclaration(FunctionDeclaration* decl) {
|
| + Variable* var = decl->proxy()->var();
|
| + DCHECK(var->type().is_null());
|
| + RECURSE(VisitFunctionAnnotation(decl->fun()));
|
| + var->set_type(computed_type_);
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) {
|
| + DCHECK(fun->scope()->asm_mode() == ASM_FUNCTION);
|
| +
|
| + // Extract result type.
|
| + ZoneList<Statement*>* body = fun->body();
|
| + Handle<Type> result_type = handle_type(Type::Undefined());
|
| + if (body->length() > 0) {
|
| + ReturnStatement* stmt = body->last()->AsReturnStatement();
|
| + if (stmt != NULL) {
|
| + RECURSE(VisitExpressionAnnotation(stmt->expression()));
|
| + result_type = computed_type_;
|
| + }
|
| + }
|
| + Handle<FunctionType> type =
|
| + Type::Function(fun->parameter_count(), result_type, isolate_);
|
| +
|
| + // Extract parameter types.
|
| + bool good = true;
|
| + for (int i = 0; i < fun->parameter_count(); ++i) {
|
| + good = false;
|
| + if (i >= body->length()) break;
|
| + ExpressionStatement* stmt = body->at(i)->AsExpressionStatement();
|
| + if (stmt == NULL) break;
|
| + Assignment* expr = stmt->expression()->AsAssignment();
|
| + if (expr == NULL || expr->is_compound()) break;
|
| + VariableProxy* proxy = expr->target()->AsVariableProxy();
|
| + if (proxy == NULL) break;
|
| + Variable* var = proxy->var();
|
| + if (var->location() != Variable::PARAMETER || var->index() != i) break;
|
| + RECURSE(VisitExpressionAnnotation(expr->value()));
|
| + var->set_type(computed_type_);
|
| + type->InitParameter(i, computed_type_);
|
| + good = true;
|
| + }
|
| + if (!good) FAIL(fun, "missing parameter type annotations");
|
| +
|
| + // Set type of function variable if present.
|
| + VariableDeclaration* decl = fun->scope()->function();
|
| + if (decl != NULL) decl->proxy()->var()->set_type(type);
|
| +
|
| + RETURN_ANNOT(fun, type);
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitExpressionAnnotation(Expression* expr) {
|
| + // Normal +x or x|0 annotations.
|
| + BinaryOperation* bin = expr->AsBinaryOperation();
|
| + if (bin != NULL) {
|
| + Handle<Type> type;
|
| + switch (bin->op()) {
|
| + case Token::MUL: // We encode +x as 1*x
|
| + RETURN_ANNOT(expr, Type::Double());
|
| + case Token::BIT_OR:
|
| + RETURN_ANNOT(expr, Type::Int32());
|
| + default:
|
| + FAIL(expr, "invalid type annotation");
|
| + }
|
| + }
|
| +
|
| + // Numbers or the undefined literal (for empty returns).
|
| + Literal* lit = expr->AsLiteral();
|
| + if (lit != NULL) {
|
| + Handle<Object> value = lit->value();
|
| + if (value->IsSmi())
|
| + RETURN_ANNOT(expr, Type::Int32());
|
| + else if (value->IsNumber())
|
| + RETURN_ANNOT(expr, Type::Double());
|
| + else if (value->IsUndefined())
|
| + RETURN_ANNOT(expr, Type::Undefined());
|
| + else
|
| + FAIL(expr, "invalid type annotation");
|
| + }
|
| +/*
|
| + // Global stdlib.x, stdlib.Math.x, or foreign.x annotations.
|
| + Property* prop = expr->AsProperty();
|
| + if (prop != NULL) {
|
| + // Get property name.
|
| + Literal* key = prop->key()->AsLiteral();
|
| + if (key == NULL || !key->IsPropertyName())
|
| + FAIL(expr, "invalid type annotation");
|
| + Handle<String> name = key->AsPropertyName();
|
| +
|
| + // stdlib.x or foreign.x
|
| + VariableProxy* proxy = prop->obj()->AsVariableProxy();
|
| + if (proxy != NULL) {
|
| + Variable* var = proxy->var();
|
| + if (var->location() != Variable::PARAMETER)
|
| + FAIL(expr, "invalid type annotation");
|
| + switch (var->index()) {
|
| + case 0: {
|
| + // Object is stdlib, look up library type.
|
| + Handle<Type> type = LibType(global_lib_, name);
|
| + if (type.is_null()) FAIL(expr, "unknown standard function");
|
| + RETURN_ANNOT(expr, type);
|
| + }
|
| + case 1:
|
| + // Object is foreign lib.
|
| + RETURN_ANNOT(expr, Type::Function());
|
| + default:
|
| + FAIL(expr, "invalid type annotation");
|
| + }
|
| + }
|
| +
|
| + // stdlib.Math.x
|
| + Property* inner_prop = prop->obj()->AsProperty();
|
| + if (inner_prop != NULL) {
|
| + // Check that inner property name is "Math".
|
| + Literal* math_key = inner_prop->key()->AsLiteral();
|
| + if (math_key == NULL || !math_key->IsPropertyName() ||
|
| + !math_key->AsPropertyName()->IsUtf8EqualTo(CStrVector("Math")))
|
| + FAIL(expr, "invalid type annotation");
|
| +
|
| + // Check that object is stdlib.
|
| + VariableProxy* proxy = prop->obj()->AsVariableProxy();
|
| + if (proxy == NULL) FAIL(expr, "invalid type annotation");
|
| + Variable* var = proxy->var();
|
| + if (var->location() != Variable::PARAMETER || var->index() != 0)
|
| + FAIL(expr, "invalid type annotation");
|
| +
|
| + // Look up library type.
|
| + Handle<Type> type = LibType(math_lib_, name);
|
| + if (type.is_null()) FAIL(expr, "unknown standard function");
|
| + RETURN_ANNOT(expr, type);
|
| + }
|
| + }
|
| +
|
| + // Global heap view annotation.
|
| + CallNew* cons = expr->AsCallNew();
|
| + if (cons != NULL && cons->arguments()->length() == 1) {
|
| + // Check that argument is heap parameter.
|
| + VariableProxy* arg = cons->arguments()->at(0)->AsVariableProxy();
|
| + if (arg == NULL) FAIL(expr, "invalid type annotation");
|
| + Variable* heap_var = arg->var();
|
| + if (heap_var->location() != Variable::PARAMETER || heap_var->index() != 2)
|
| + FAIL(expr, "invalid type annotation");
|
| +
|
| + Property* prop = cons->expression()->AsProperty();
|
| + if (prop == NULL) FAIL(expr, "invalid type annotation");
|
| +
|
| + // Check that object is stdlib.
|
| + VariableProxy* proxy = prop->obj()->AsVariableProxy();
|
| + if (proxy == NULL) FAIL(expr, "invalid type annotation");
|
| + Variable* lib_var = proxy->var();
|
| + if (lib_var->location() != Variable::PARAMETER || lib_var->index() != 0)
|
| + FAIL(expr, "invalid type annotation");
|
| +
|
| + // Look up array type.
|
| + Literal* key = prop->key()->AsLiteral();
|
| + if (key == NULL || !key->IsPropertyName())
|
| + FAIL(expr, "invalid type annotation");
|
| + Handle<String> name = key->AsPropertyName();
|
| + Handle<Type> type = LibType(array_lib_, name);
|
| + if (type.is_null()) FAIL(expr, "unknown array view");
|
| + RETURN_ANNOT(expr, type);
|
| + }
|
| +
|
| + // Function table.
|
| + ArrayLiteral* array = expr->AsArrayLiteral();
|
| + if (array != NULL && array->values()->length() > 0) {
|
| + ZoneList<Expression*>* values = array->values();
|
| + Handle<Type> type(Type::None(), isolate_);
|
| + for (int i = 0; i < values->length(); ++i) {
|
| + // Check that value is a variable.
|
| + VariableProxy* proxy = values->at(i)->AsVariableProxy();
|
| + if (proxy == NULL) FAIL(expr, "invalid entry in function table");
|
| +
|
| + // Merge type.
|
| + Handle<Type> type_i = proxy->var()->type();
|
| + if (type_i.is_null() || !type_i->IsFunction())
|
| + FAIL(proxy, "invalid entry in function table");
|
| + type = handle(Type::Union(type, type_i), isolate_);
|
| + }
|
| + RETURN_ANNOT(expr, Type::Array(type, isolate_));
|
| + }
|
| +*/
|
| + FAIL(expr, "invalid type annotation");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitStatements(ZoneList<Statement*>* stmts) {
|
| + for (int i = 0; i < stmts->length(); ++i) {
|
| + Statement* stmt = stmts->at(i);
|
| + RECURSE_STMT(stmt);
|
| + }
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitBlock(Block* stmt) {
|
| + RECURSE(VisitStatements(stmt->statements()));
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
|
| + RECURSE_EXPR(stmt->expression(), Type::Any(),
|
| + "expression statement expected to ba any");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitEmptyStatement(EmptyStatement* stmt) {
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitIfStatement(IfStatement* stmt) {
|
| + RECURSE_EXPR(stmt->condition(), Type::Int32(),
|
| + "if condition expected to be integer");
|
| + RECURSE_STMT(stmt->then_statement());
|
| + RECURSE_STMT(stmt->else_statement());
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitContinueStatement(ContinueStatement* stmt) {
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitBreakStatement(BreakStatement* stmt) {
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitReturnStatement(ReturnStatement* stmt) {
|
| + RECURSE_EXPR(stmt->expression(), return_type_,
|
| + "return expression expected to have return type");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitWithStatement(WithStatement* stmt) {
|
| + FAIL(stmt, "with statement encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitSwitchStatement(SwitchStatement* stmt) {
|
| + RECURSE_EXPR(stmt->tag(), Type::Signed32(),
|
| + "switch expression expected to be integer");
|
| +
|
| + ZoneList<CaseClause*>* clauses = stmt->cases();
|
| + SwitchStatement::SwitchType switch_type = SwitchStatement::SMI_SWITCH;
|
| + for (int i = 0; i < clauses->length(); ++i) {
|
| + CaseClause* clause = clauses->at(i);
|
| + if (!clause->is_default()) {
|
| + Expression* label = clause->label();
|
| + RECURSE_EXPR(label, Type::Signed32(),
|
| + "case label expected to be integer");
|
| + if (!label->IsLiteral()) FAIL(label, "illegal label");
|
| + Handle<Object> value = label->AsLiteral()->value();
|
| + if (!value->IsSmi()) {
|
| + if (!value->IsHeapNumber()) FAIL(label, "illegal label");
|
| + double x = HeapNumber::cast(*value)->value();
|
| + if (static_cast<int32_t>(x) != x) FAIL(label, "illegal label");
|
| + // TODO(rossberg): we'd need a SIGNED32_SWITCH to be precise.
|
| + switch_type = SwitchStatement::GENERIC_SWITCH;
|
| + }
|
| + }
|
| + ZoneList<Statement*>* stmts = clause->statements();
|
| + RECURSE(VisitStatements(stmts));
|
| + }
|
| + stmt->set_switch_type(switch_type);
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitCaseClause(CaseClause* clause) {
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
| + RECURSE_STMT(stmt->body());
|
| + RECURSE_EXPR(stmt->cond(), Type::Int32(),
|
| + "do condition expected to be integer");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitWhileStatement(WhileStatement* stmt) {
|
| + RECURSE_EXPR(stmt->cond(), Type::Int32(),
|
| + "while condition expected to be integer");
|
| + RECURSE_STMT(stmt->body());
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitForStatement(ForStatement* stmt) {
|
| + if (stmt->init() != NULL) RECURSE_STMT(stmt->init());
|
| + if (stmt->cond() != NULL) RECURSE_EXPR(stmt->cond(), Type::Int32(),
|
| + "for condition expected to be integer");
|
| + if (stmt->next() != NULL) RECURSE_STMT(stmt->next());
|
| + RECURSE_STMT(stmt->body());
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitForInStatement(ForInStatement* stmt) {
|
| + FAIL(stmt, "for-in statement encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitForOfStatement(ForOfStatement* stmt) {
|
| + FAIL(stmt, "for-of statement encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
| + FAIL(stmt, "try statement encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
|
| + FAIL(stmt, "try statement encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
|
| + FAIL(stmt, "debugger statement encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
|
| + Scope* scope = expr->scope();
|
| + DCHECK(scope->is_function_scope());
|
| + DCHECK(scope->asm_mode() == ASM_FUNCTION);
|
| +
|
| + if (!expr->bounds().upper->IsFunction())
|
| + FAIL(expr, "invalid function literal");
|
| +
|
| + Handle<FunctionType> type(expr->bounds().upper->AsFunction());
|
| + Handle<Type> save_return_type = return_type_;
|
| + return_type_ = type->Result();
|
| + RECURSE(VisitDeclarations(scope->declarations()));
|
| + RECURSE(VisitStatements(expr->body()));
|
| + return_type_ = save_return_type;
|
| + RETURN(expr, type);
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
|
| + FAIL(expr, "function info literal encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitConditional(Conditional* expr) {
|
| + RECURSE_EXPR(expr->condition(), Type::Int32(),
|
| + "condition expected to be integer");
|
| + RECURSE_EXPR(expr->then_expression(), Type::Number(),
|
| + "conditional then branch expected to be integer");
|
| + Handle<Type> then_type = computed_type_;
|
| + RECURSE_EXPR(expr->else_expression(), Type::Number(),
|
| + "conditional else branch expected to be integer");
|
| + Handle<Type> else_type = computed_type_;
|
| + Handle<Type> type = handle_type(Type::Intersect(then_type, else_type));
|
| + if (!(type->Is(Type::Int32()) || type->Is(Type::Double())))
|
| + FAIL(expr, "ill-typed conditional");
|
| + RETURN(expr, type);
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitVariableProxy(VariableProxy* expr) {
|
| + Variable* var = expr->var();
|
| + if (var->type().is_null()) FAIL(expr, "unbound variable");
|
| + Handle<Type> type = handle_type(Type::Intersect(var->type(), expected_type_));
|
| + if (type->Is(Type::Int32())) type = handle_type(Type::Int32());
|
| + var->set_type(type);
|
| + RETURN(expr, type);
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitLiteral(Literal* expr) {
|
| + Handle<Object> value = expr->value();
|
| + if (value->IsNumber()) {
|
| + int32_t i;
|
| + uint32_t u;
|
| + if (expr->is_float())
|
| + RETURN(expr, Type::Double());
|
| + else if (value->ToUint32(&u))
|
| + RETURN(expr, u < 0x80000000u ? Type::Unsigned31() : Type::Unsigned32());
|
| + else if (value->ToInt32(&i))
|
| + RETURN(expr, Type::Signed32());
|
| + else
|
| + FAIL(expr, "illegal number");
|
| + } else if (value->IsString()) {
|
| + RETURN(expr, Type::String());
|
| + } else if (value->IsUndefined()) {
|
| + RETURN(expr, Type::Undefined());
|
| + } else {
|
| + FAIL(expr, "illegal literal");
|
| + }
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
|
| + FAIL(expr, "regular expression encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitObjectLiteral(ObjectLiteral* expr) {
|
| + // Allowed for asm module's export declaration.
|
| + ZoneList<ObjectLiteralProperty*>* props = expr->properties();
|
| + Handle<ObjectType> type = Type::Object(props->length(), isolate_);
|
| + for (int i = 0; i < props->length(); ++i) {
|
| + ObjectLiteralProperty* prop = props->at(i);
|
| + RECURSE_EXPR(prop->value(), Type::Function(),
|
| + "object property expected to be a function");
|
| + type->InitProperty(i, prop->key()->AsPropertyName(), computed_type_);
|
| + }
|
| + RETURN(expr, type);
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitArrayLiteral(ArrayLiteral* expr) {
|
| + // Allowed for function tables.
|
| + ZoneList<Expression*>* values = expr->values();
|
| + Handle<Type> elem_type = handle_type(Type::None());
|
| + for (int i = 0; i < values->length(); ++i) {
|
| + Expression* value = values->at(i);
|
| + RECURSE_EXPR(value, Type::Function(),
|
| + "array component expected to be a function");
|
| + elem_type = handle_type(Type::Union(elem_type, computed_type_));
|
| + }
|
| + RETURN(expr, Type::Array(elem_type, isolate_));
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitAssignment(Assignment* expr) {
|
| + if (expr->is_compound()) FAIL(expr, "compound assignment encountered");
|
| + RECURSE_EXPR(expr->value(), expected_type_,
|
| + "assignment value expected to match surrounding");
|
| + RECURSE_EXPR(expr->target(), computed_type_,
|
| + "assignment target expected to match value");
|
| + RETURN(expr, computed_type_);
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitYield(Yield* expr) {
|
| + FAIL(expr, "yield expression encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitThrow(Throw* expr) {
|
| + FAIL(expr, "throw statement encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitProperty(Property* expr) {
|
| + RECURSE_EXPR(expr->obj(), Type::Object(),
|
| + "property holder expected to be object");
|
| +
|
| + // For heap or function table access.
|
| + if (computed_type_->IsArray()) {
|
| + Handle<ArrayType> array_type = Handle<ArrayType>::cast(computed_type_);
|
| + RECURSE_EXPR(expr->key(), Type::Unsigned32(),
|
| + "array index expected to be unsigned integer");
|
| + Handle<Type> type = array_type->AsArray()->Element();
|
| + if (type->Is(Type::Int32()))
|
| + RETURN(expr, Type::Int32());
|
| + else if (type->Is(Type::Double()))
|
| + RETURN(expr, Type::Double());
|
| + else
|
| + RETURN(expr, type);
|
| + }
|
| +
|
| + // For stdlib access.
|
| + if (computed_type_->IsObject() && expr->key()->IsPropertyName()) {
|
| + Handle<ObjectType> object_type = Handle<ObjectType>::cast(computed_type_);
|
| + RECURSE_EXPR(expr->key(), Type::Name(),
|
| + "stdlib name expected to be name");
|
| + RETURN(expr,
|
| + object_type->Property(expr->key()->AsLiteral()->AsPropertyName()));
|
| + }
|
| +
|
| + // For foreign or other accesses.
|
| + RECURSE_EXPR(expr->key(), Type::Any(),
|
| + "foreign index expected to be any");
|
| + RETURN(expr, Type::Any());
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitCall(Call* expr) {
|
| + RECURSE_EXPR(expr->expression(), Type::Function(),
|
| + "callee expected to be function");
|
| + if (computed_type_->IsFunction()) {
|
| + Handle<FunctionType> fun_type = Handle<FunctionType>::cast(computed_type_);
|
| + ZoneList<Expression*>* args = expr->arguments();
|
| + if (fun_type->Arity() != args->length())
|
| + FAIL(expr, "call with wrong arity");
|
| + for (int i = 0; i < args->length(); ++i) {
|
| + Expression* arg = args->at(i);
|
| + RECURSE_EXPR(arg, fun_type->Parameter(i),
|
| + "call argument expected to match callee parameter");
|
| + }
|
| + RETURN(expr, fun_type->Result());
|
| + } else {
|
| + // For foreign calls.
|
| + ZoneList<Expression*>* args = expr->arguments();
|
| + for (int i = 0; i < args->length(); ++i) {
|
| + Expression* arg = args->at(i);
|
| + RECURSE_EXPR(arg, Type::Any(),
|
| + "foreign call argument expected to be any");
|
| + }
|
| + RETURN(expr, Type::Number());
|
| + }
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitCallNew(CallNew* expr) {
|
| + RECURSE_EXPR(expr->expression(), Type::Function(),
|
| + "constructor expected to be function");
|
| + if (computed_type_->IsFunction()) {
|
| + Handle<FunctionType> fun_type = Handle<FunctionType>::cast(computed_type_);
|
| + ZoneList<Expression*>* args = expr->arguments();
|
| + if (fun_type->Arity() != args->length())
|
| + FAIL(expr, "call with wrong arity");
|
| + for (int i = 0; i < args->length(); ++i) {
|
| + Expression* arg = args->at(i);
|
| + RECURSE_EXPR(arg, fun_type->Parameter(i),
|
| + "constructor argument expected to match callee parameter");
|
| + }
|
| + RETURN(expr, fun_type->Result());
|
| + }
|
| +
|
| + FAIL(expr, "ill-typed new operator");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitCallRuntime(CallRuntime* expr) {
|
| + FAIL(expr, "runtime call encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitUnaryOperation(UnaryOperation* expr) {
|
| + switch (expr->op()) {
|
| + case Token::NOT: // Used to encode != and !==
|
| + RECURSE_EXPR(expr->expression(), Type::Int32(),
|
| + "operand expected to be integer");
|
| + RETURN(expr, Type::Int32());
|
| + case Token::DELETE:
|
| + FAIL(expr, "delete operator encountered");
|
| + case Token::VOID:
|
| + FAIL(expr, "void operator encountered");
|
| + case Token::TYPEOF:
|
| + FAIL(expr, "typeof operator encountered");
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitCountOperation(CountOperation* expr) {
|
| + FAIL(expr, "increment or decrement operator encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) {
|
| + // TODO(rossberg): recognise unary +, -, ~ and ~~.
|
| + switch (expr->op()) {
|
| + case Token::COMMA: {
|
| + RECURSE_EXPR(expr->left(), Type::Any(),
|
| + "left comma operand expected to be any");
|
| + RECURSE_EXPR(expr->right(), Type::Any(),
|
| + "right comma operand expected to be any");
|
| + RETURN(expr, computed_type_);
|
| + }
|
| + case Token::OR:
|
| + case Token::AND:
|
| + FAIL(expr, "logical operator encountered");
|
| + case Token::BIT_OR:
|
| + case Token::BIT_AND:
|
| + case Token::BIT_XOR:
|
| + case Token::SHL:
|
| + case Token::SHR:
|
| + case Token::SAR: {
|
| + // BIT_OR allows Any since it is used as a type coercion.
|
| + // BIT_XOR allows Number since it is used as a type coercion (encoding ~).
|
| + Type* expectation =
|
| + expr->op() == Token::BIT_OR ? Type::Any() :
|
| + expr->op() == Token::BIT_XOR ? Type::Number() : Type::Int32();
|
| + Type* result =
|
| + expr->op() == Token::SHR ? Type::Unsigned32() : Type::Signed32();
|
| + RECURSE_EXPR(expr->left(), expectation,
|
| + "left bit operand expected to be integer");
|
| + RECURSE_EXPR(expr->right(), expectation,
|
| + "right bit operand expected to be integer");
|
| + RETURN(expr, result);
|
| + }
|
| + case Token::ADD:
|
| + case Token::SUB:
|
| + case Token::MUL:
|
| + case Token::DIV:
|
| + case Token::MOD: {
|
| + // MUL allows Any, since it is used as a type coercion (encoding unary +).
|
| + Type* expectation =
|
| + expr->op() == Token::MUL ? Type::Any() : Type::Number();
|
| + RECURSE_EXPR(expr->left(), expectation,
|
| + "left arithmetic operand expected to be number");
|
| + Handle<Type> left_type = computed_type_;
|
| + RECURSE_EXPR(expr->right(), expectation,
|
| + "right arithmetic operand expected to be number");
|
| + Handle<Type> right_type = computed_type_;
|
| + Handle<Type> type = handle_type(Type::Intersect(left_type, right_type));
|
| + if (type->Is(Type::Int32()))
|
| + RETURN(expr, Type::Int32());
|
| + else if (type->Is(Type::Number()))
|
| + RETURN(expr, Type::Double());
|
| + else
|
| + FAIL(expr, "ill-typed arithmetic operation");
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitCompareOperation(CompareOperation* expr) {
|
| + RECURSE_EXPR(expr->left(), Type::Number(),
|
| + "left comparison operand expected to be number");
|
| + Handle<Type> left_type = computed_type_;
|
| + RECURSE_EXPR(expr->right(), Type::Number(),
|
| + "right comparison operand expected to be number");
|
| + Handle<Type> right_type = computed_type_;
|
| + Handle<Type> type = handle_type(Type::Union(left_type, right_type));
|
| + expr->set_combined_type(type);
|
| + if (type->Is(Type::Int32()) || type->Is(Type::Double()))
|
| + RETURN(expr, Type::Int32());
|
| + else
|
| + FAIL(expr, "ill-typed comparison operation");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitThisFunction(ThisFunction* expr) {
|
| + RETURN(expr, Type::Function());
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
|
| + for (int i = 0; i < decls->length(); ++i) {
|
| + Declaration* decl = decls->at(i);
|
| + RECURSE_STMT(decl);
|
| + }
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitModuleDeclaration(ModuleDeclaration* decl) {
|
| + FAIL(decl, "module declaration encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitImportDeclaration(ImportDeclaration* decl) {
|
| + FAIL(decl, "import declaration encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitExportDeclaration(ExportDeclaration* decl) {
|
| + FAIL(decl, "export declaration encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitModuleLiteral(ModuleLiteral* module) {
|
| + FAIL(module, "module encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitModuleVariable(ModuleVariable* module) {
|
| + FAIL(module, "module encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitModulePath(ModulePath* module) {
|
| + FAIL(module, "module encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitModuleUrl(ModuleUrl* module) {
|
| + FAIL(module, "module encountered");
|
| +}
|
| +
|
| +
|
| +void AsmTyper::VisitModuleStatement(ModuleStatement* stmt) {
|
| + FAIL(stmt, "module encountered");
|
| +}
|
| +
|
| +
|
| +Handle<Type> AsmTyper::StdlibType() {
|
| + Handle<Type> no_type;
|
| + Handle<Type> signed8_type = handle_type(Type::Signed8());
|
| + Handle<Type> unsigned8_type = handle_type(Type::Unsigned8());
|
| + Handle<Type> signed16_type = handle_type(Type::Signed16());
|
| + Handle<Type> unsigned16_type = handle_type(Type::Unsigned16());
|
| + Handle<Type> signed32_type = handle_type(Type::Signed32());
|
| + Handle<Type> unsigned32_type = handle_type(Type::Unsigned32());
|
| + Handle<Type> int32_type = handle_type(Type::Int32());
|
| + Handle<Type> float32_type = handle_type(Type::Float32());
|
| + Handle<Type> double_type = handle_type(Type::Double());
|
| + Handle<Type> number_type = handle_type(Type::Number());
|
| +
|
| + Handle<FunctionType> double_fn1_type =
|
| + Type::Function(double_type, double_type, isolate_);
|
| + Handle<FunctionType> double_fn2_type =
|
| + Type::Function(double_type, double_type, double_type, isolate_);
|
| +
|
| + Handle<FunctionType> imul_type =
|
| + Type::Function(int32_type, int32_type, signed32_type, isolate_);
|
| + // TODO(rossberg): currently only approximating the proper intersection type
|
| + // (which we cannot currently represent).
|
| + Handle<FunctionType> abs_type =
|
| + Type::Function(number_type, number_type, isolate_);
|
| +
|
| + struct Assignment {
|
| + const char* name;
|
| + Handle<Type> type;
|
| + };
|
| +
|
| + const Assignment math[] = {
|
| + {"PI", double_type},
|
| + {"E", double_type},
|
| + {"LN2", double_type},
|
| + {"LN10", double_type},
|
| + {"LOG2E", double_type},
|
| + {"LOG10E", double_type},
|
| + {"SQRT2", double_type},
|
| + {"SQRT1_2", double_type},
|
| + {"imul", imul_type},
|
| + {"abs", abs_type},
|
| + {"ceil", double_fn1_type},
|
| + {"floor", double_fn1_type},
|
| + {"pow", double_fn2_type},
|
| + {"exp", double_fn1_type},
|
| + {"log", double_fn1_type},
|
| + {"sqrt", double_fn1_type},
|
| + {"cos", double_fn1_type},
|
| + {"sin", double_fn1_type},
|
| + {"tan", double_fn1_type},
|
| + {"acos", double_fn1_type},
|
| + {"asin", double_fn1_type},
|
| + {"atan", double_fn1_type},
|
| + {"atan2", double_fn2_type}
|
| + };
|
| + Handle<ObjectType> math_type = Type::Object(ARRAY_SIZE(math), isolate_);
|
| + for (unsigned i = 0; i < ARRAY_SIZE(math); ++i) {
|
| + math_type->InitProperty(i,
|
| + isolate_->factory()->InternalizeUtf8String(math[i].name), math[i].type);
|
| + }
|
| +
|
| + Handle<Type> buffer_type = handle_type(Type::Buffer());
|
| + Handle<ArrayType> int8_array_type = Type::Array(signed8_type, isolate_);
|
| + Handle<ArrayType> uint8_array_type = Type::Array(unsigned8_type, isolate_);
|
| + Handle<ArrayType> int16_array_type = Type::Array(signed16_type, isolate_);
|
| + Handle<ArrayType> uint16_array_type = Type::Array(unsigned16_type, isolate_);
|
| + Handle<ArrayType> int32_array_type = Type::Array(signed32_type, isolate_);
|
| + Handle<ArrayType> uint32_array_type = Type::Array(unsigned32_type, isolate_);
|
| + Handle<ArrayType> float32_array_type = Type::Array(float32_type, isolate_);
|
| + Handle<ArrayType> float64_array_type = Type::Array(double_type, isolate_);
|
| +
|
| + Handle<FunctionType> int8_array_cons_type =
|
| + Type::Function(buffer_type, int8_array_type, isolate_);
|
| + Handle<FunctionType> uint8_array_cons_type =
|
| + Type::Function(buffer_type, uint8_array_type, isolate_);
|
| + Handle<FunctionType> int16_array_cons_type =
|
| + Type::Function(buffer_type, int16_array_type, isolate_);
|
| + Handle<FunctionType> uint16_array_cons_type =
|
| + Type::Function(buffer_type, uint16_array_type, isolate_);
|
| + Handle<FunctionType> int32_array_cons_type =
|
| + Type::Function(buffer_type, int32_array_type, isolate_);
|
| + Handle<FunctionType> uint32_array_cons_type =
|
| + Type::Function(buffer_type, uint32_array_type, isolate_);
|
| + Handle<FunctionType> float32_array_cons_type =
|
| + Type::Function(buffer_type, float32_array_type, isolate_);
|
| + Handle<FunctionType> float64_array_cons_type =
|
| + Type::Function(buffer_type, float64_array_type, isolate_);
|
| +
|
| + const Assignment global[] = {
|
| + {"Infinity", double_type},
|
| + {"NaN", double_type},
|
| + {"Math", math_type},
|
| + {"Int8Array", int8_array_cons_type},
|
| + {"Uint8Array", uint8_array_cons_type},
|
| + {"Int16Array", int16_array_cons_type},
|
| + {"Uint16Array", uint16_array_cons_type},
|
| + {"Int32Array", int32_array_cons_type},
|
| + {"Uint32Array", uint32_array_cons_type},
|
| + {"Float32Array", float32_array_cons_type},
|
| + {"Float64Array", float64_array_cons_type}
|
| + };
|
| + Handle<ObjectType> global_type = Type::Object(ARRAY_SIZE(global), isolate_);
|
| + for (unsigned i = 0; i < ARRAY_SIZE(global); ++i) {
|
| + global_type->InitProperty(i,
|
| + isolate_->factory()->InternalizeUtf8String(global[i].name),
|
| + global[i].type);
|
| + }
|
| +
|
| + return global_type;
|
| +}
|
| +
|
| +} } // namespace v8::internal
|
| +
|
| +#endif
|
|
|