Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(454)

Unified Diff: src/typing-asm.cc

Issue 1161393007: OLD type Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: fix Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/typing-asm.h ('k') | src/variables.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « src/typing-asm.h ('k') | src/variables.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698