Index: src/typing-asm.cc |
diff --git a/src/typing-asm.cc b/src/typing-asm.cc |
index ebb5eaa67f3f34c26103b4ef60bb4cb6b6193e18..be74193597ef3c9f7bb8d96ca597ca6186e6d8f7 100644 |
--- a/src/typing-asm.cc |
+++ b/src/typing-asm.cc |
@@ -38,16 +38,22 @@ namespace internal { |
AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, |
FunctionLiteral* root) |
: zone_(zone), |
+ isolate_(isolate), |
script_(script), |
root_(root), |
valid_(true), |
+ allow_simd_(false), |
intish_(0), |
stdlib_types_(zone), |
stdlib_heap_types_(zone), |
stdlib_math_types_(zone), |
- global_variable_type_(HashMap::PointersMatch, |
- ZoneHashMap::kDefaultHashMapCapacity, |
- ZoneAllocationPolicy(zone)), |
+#define V(NAME, Name, name, lane_count, lane_type) \ |
+ stdlib_simd_##name##_types_(zone), |
+ SIMD128_TYPES(V) |
+#undef V |
+ global_variable_type_(HashMap::PointersMatch, |
+ ZoneHashMap::kDefaultHashMapCapacity, |
+ ZoneAllocationPolicy(zone)), |
local_variable_type_(HashMap::PointersMatch, |
ZoneHashMap::kDefaultHashMapCapacity, |
ZoneAllocationPolicy(zone)), |
@@ -93,6 +99,10 @@ void AsmTyper::VisitAsmModule(FunctionLiteral* fun) { |
RECURSE(VisitFunctionAnnotation(decl->fun())); |
Variable* var = decl->proxy()->var(); |
DCHECK(GetType(var) == NULL); |
+ if (property_info_ != NULL) { |
+ SetVariableInfo(var, property_info_); |
+ property_info_ = NULL; |
+ } |
SetType(var, computed_type_); |
DCHECK(GetType(var) != NULL); |
} |
@@ -181,6 +191,10 @@ void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) { |
if (var->location() != VariableLocation::PARAMETER || var->index() != i) |
break; |
RECURSE(VisitExpressionAnnotation(expr->value(), var, false)); |
+ if (property_info_ != NULL) { |
+ SetVariableInfo(var, property_info_); |
+ property_info_ = NULL; |
+ } |
SetType(var, computed_type_); |
type->InitParameter(i, computed_type_); |
good = true; |
@@ -197,12 +211,12 @@ void AsmTyper::VisitExpressionAnnotation(Expression* expr, Variable* var, |
BinaryOperation* bin = expr->AsBinaryOperation(); |
if (bin != NULL) { |
if (var != NULL) { |
- VariableProxy* left = bin->left()->AsVariableProxy(); |
- if (!left) { |
- FAIL(expr, "variable name expected in type annotation"); |
+ VariableProxy* proxy = bin->left()->AsVariableProxy(); |
+ if (proxy == NULL) { |
+ FAIL(bin->left(), "expected variable for type annotation"); |
} |
- if (left->var() != var) { |
- FAIL(left, "variable type annotation references other variable"); |
+ if (proxy->var() != var) { |
+ FAIL(proxy, "annotation source doesn't match destination"); |
} |
} |
Literal* right = bin->right()->AsLiteral(); |
@@ -241,19 +255,28 @@ void AsmTyper::VisitExpressionAnnotation(Expression* expr, Variable* var, |
Call* call = expr->AsCall(); |
if (call != NULL) { |
- if (call->expression()->IsVariableProxy()) { |
- RECURSE(VisitWithExpectation( |
- call->expression(), Type::Any(zone()), |
- "only fround allowed on expression annotations")); |
- if (!computed_type_->Is( |
- Type::Function(cache_.kAsmFloat, Type::Number(zone()), zone()))) { |
- FAIL(call->expression(), |
- "only fround allowed on expression annotations"); |
+ VariableProxy* proxy = call->expression()->AsVariableProxy(); |
+ if (proxy != NULL) { |
+ VariableInfo* info = GetVariableInfo(proxy->var(), false); |
+ if (!info || |
+ (!info->is_check_function && !info->is_constructor_function)) { |
+ if (allow_simd_) { |
+ FAIL(call->expression(), |
+ "only fround/SIMD.checks allowed on expression annotations"); |
+ } else { |
+ FAIL(call->expression(), |
+ "only fround allowed on expression annotations"); |
+ } |
} |
- if (call->arguments()->length() != 1) { |
- FAIL(call, "invalid argument count calling fround"); |
+ Type* type = info->type; |
+ DCHECK(type->IsFunction()); |
+ if (info->is_check_function) { |
+ DCHECK(type->AsFunction()->Arity() == 1); |
} |
- SetResult(expr, cache_.kAsmFloat); |
+ if (call->arguments()->length() != type->AsFunction()->Arity()) { |
+ FAIL(call, "invalid argument count calling function"); |
+ } |
+ SetResult(expr, type->AsFunction()->Result()); |
return; |
} |
} |
@@ -499,10 +522,15 @@ void AsmTyper::VisitConditional(Conditional* expr) { |
void AsmTyper::VisitVariableProxy(VariableProxy* expr) { |
Variable* var = expr->var(); |
- if (GetType(var) == NULL) { |
+ VariableInfo* info = GetVariableInfo(var, false); |
+ if (info == NULL || info->type == NULL) { |
FAIL(expr, "unbound variable"); |
} |
- Type* type = Type::Intersect(GetType(var), expected_type_, zone()); |
+ if (property_info_ != NULL) { |
+ SetVariableInfo(var, property_info_); |
+ property_info_ = NULL; |
+ } |
+ Type* type = Type::Intersect(info->type, expected_type_, zone()); |
if (type->Is(cache_.kAsmInt)) { |
type = cache_.kAsmInt; |
} |
@@ -739,35 +767,83 @@ void AsmTyper::VisitHeapAccess(Property* expr, bool assigning, |
} |
-void AsmTyper::VisitProperty(Property* expr) { |
- // stdlib.Math.x |
- Property* inner_prop = expr->obj()->AsProperty(); |
- if (inner_prop != NULL) { |
- // Get property name. |
- Literal* key = expr->key()->AsLiteral(); |
- if (key == NULL || !key->IsPropertyName()) |
- FAIL(expr, "invalid type annotation on property 2"); |
- Handle<String> name = key->AsPropertyName(); |
- |
- // 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 on stdlib (a1)"); |
- |
- // Check that object is stdlib. |
- VariableProxy* proxy = inner_prop->obj()->AsVariableProxy(); |
- if (proxy == NULL) FAIL(expr, "invalid type annotation on stdlib (a2)"); |
- Variable* var = proxy->var(); |
- if (var->location() != VariableLocation::PARAMETER || var->index() != 0) |
- FAIL(expr, "invalid type annotation on stdlib (a3)"); |
+bool AsmTyper::IsStdlibObject(Expression* expr) { |
+ VariableProxy* proxy = expr->AsVariableProxy(); |
+ if (proxy == NULL) { |
+ return false; |
+ } |
+ Variable* var = proxy->var(); |
+ VariableInfo* info = GetVariableInfo(var, false); |
+ if (info) { |
+ if (info->is_stdlib_object) return info->is_stdlib_object; |
+ } |
+ if (var->location() != VariableLocation::PARAMETER || var->index() != 0) { |
+ return false; |
+ } |
+ info = GetVariableInfo(var, true); |
+ info->type = Type::Object(); |
+ info->is_stdlib_object = true; |
+ return true; |
+} |
+ |
+ |
+Expression* AsmTyper::GetReceiverOfPropertyAccess(Expression* expr, |
+ const char* name) { |
+ Property* property = expr->AsProperty(); |
+ if (property == NULL) { |
+ return NULL; |
+ } |
+ Literal* key = property->key()->AsLiteral(); |
+ if (key == NULL || !key->IsPropertyName() || |
+ !key->AsPropertyName()->IsUtf8EqualTo(CStrVector(name))) { |
+ return NULL; |
+ } |
+ return property->obj(); |
+} |
+ |
+ |
+bool AsmTyper::IsMathObject(Expression* expr) { |
+ Expression* obj = GetReceiverOfPropertyAccess(expr, "Math"); |
+ return obj && IsStdlibObject(obj); |
+} |
+ |
+ |
+bool AsmTyper::IsSIMDObject(Expression* expr) { |
+ Expression* obj = GetReceiverOfPropertyAccess(expr, "SIMD"); |
+ return obj && IsStdlibObject(obj); |
+} |
+ |
- // Look up library type. |
- Type* type = LibType(stdlib_math_types_, name); |
- if (type == NULL) FAIL(expr, "unknown standard function 3 "); |
- SetResult(expr, type); |
+bool AsmTyper::IsSIMDTypeObject(Expression* expr, const char* name) { |
+ Expression* obj = GetReceiverOfPropertyAccess(expr, name); |
+ return obj && IsSIMDObject(obj); |
+} |
+ |
+ |
+void AsmTyper::VisitProperty(Property* expr) { |
+ if (IsMathObject(expr->obj())) { |
+ VisitLibraryAccess(&stdlib_math_types_, expr); |
return; |
} |
+#define V(NAME, Name, name, lane_count, lane_type) \ |
+ if (IsSIMDTypeObject(expr->obj(), #Name)) { \ |
+ VisitLibraryAccess(&stdlib_simd_##name##_types_, expr); \ |
+ return; \ |
+ } \ |
+ if (IsSIMDTypeObject(expr, #Name)) { \ |
+ VariableInfo* info = stdlib_simd_##name##_constructor_type_; \ |
+ SetResult(expr, info->type); \ |
+ property_info_ = info; \ |
+ return; \ |
+ } |
+ SIMD128_TYPES(V) |
+#undef V |
+ if (IsStdlibObject(expr->obj())) { |
+ VisitLibraryAccess(&stdlib_types_, expr); |
+ return; |
+ } |
+ |
+ property_info_ = NULL; |
// Only recurse at this point so that we avoid needing |
// stdlib.Math to have a real type. |
@@ -779,35 +855,14 @@ void AsmTyper::VisitProperty(Property* expr) { |
return; |
} |
- // Get property name. |
- Literal* key = expr->key()->AsLiteral(); |
- if (key == NULL || !key->IsPropertyName()) |
- FAIL(expr, "invalid type annotation on property 3"); |
- Handle<String> name = key->AsPropertyName(); |
- |
// stdlib.x or foreign.x |
VariableProxy* proxy = expr->obj()->AsVariableProxy(); |
if (proxy != NULL) { |
Variable* var = proxy->var(); |
- if (var->location() != VariableLocation::PARAMETER) { |
- FAIL(expr, "invalid type annotation on variable"); |
- } |
- switch (var->index()) { |
- case 0: { |
- // Object is stdlib, look up library type. |
- Type* type = LibType(stdlib_types_, name); |
- if (type == NULL) { |
- FAIL(expr, "unknown standard function 4"); |
- } |
- SetResult(expr, type); |
- return; |
- } |
- case 1: |
- // Object is foreign lib. |
- SetResult(expr, expected_type_); |
- return; |
- default: |
- FAIL(expr, "invalid type annotation on parameter"); |
+ if (var->location() == VariableLocation::PARAMETER && var->index() == 1) { |
+ // foreign.x is ok. |
+ SetResult(expr, expected_type_); |
+ return; |
} |
} |
@@ -1143,7 +1198,26 @@ void AsmTyper::VisitSuperCallReference(SuperCallReference* expr) { |
} |
+void AsmTyper::InitializeStdlibSIMD() { |
+#define V(NAME, Name, name, lane_count, lane_type) \ |
+ { \ |
+ Type* type = Type::Function(Type::Name(isolate_, zone()), Type::Any(), \ |
+ lane_count, zone()); \ |
+ for (int i = 0; i < lane_count; ++i) { \ |
+ type->AsFunction()->InitParameter(i, Type::Number()); \ |
+ } \ |
+ stdlib_simd_##name##_constructor_type_ = new (zone()) VariableInfo(type); \ |
+ stdlib_simd_##name##_constructor_type_->is_constructor_function = true; \ |
+ } |
+ SIMD128_TYPES(V) |
+#undef V |
+} |
+ |
+ |
void AsmTyper::InitializeStdlib() { |
+ if (allow_simd_) { |
+ InitializeStdlibSIMD(); |
+ } |
Type* number_type = Type::Number(zone()); |
Type* double_type = cache_.kAsmDouble; |
Type* double_fn1_type = Type::Function(double_type, double_type, zone()); |
@@ -1177,30 +1251,44 @@ void AsmTyper::InitializeStdlib() { |
{"acos", double_fn1_type}, {"asin", double_fn1_type}, |
{"atan", double_fn1_type}, {"atan2", double_fn2_type}}; |
for (unsigned i = 0; i < arraysize(math); ++i) { |
- stdlib_math_types_[math[i].name] = math[i].type; |
+ stdlib_math_types_[math[i].name] = new (zone()) VariableInfo(math[i].type); |
} |
+ stdlib_math_types_["fround"]->is_check_function = true; |
- stdlib_types_["Infinity"] = double_type; |
- stdlib_types_["NaN"] = double_type; |
+ stdlib_types_["Infinity"] = new (zone()) VariableInfo(double_type); |
+ stdlib_types_["NaN"] = new (zone()) VariableInfo(double_type); |
Type* buffer_type = Type::Any(zone()); |
#define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size) \ |
- stdlib_types_[#TypeName "Array"] = \ |
- Type::Function(cache_.k##TypeName##Array, buffer_type, zone()); |
+ stdlib_types_[#TypeName "Array"] = new (zone()) VariableInfo( \ |
+ Type::Function(cache_.k##TypeName##Array, buffer_type, zone())); |
TYPED_ARRAYS(TYPED_ARRAY) |
#undef TYPED_ARRAY |
-#define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size) \ |
- stdlib_heap_types_[#TypeName "Array"] = \ |
- Type::Function(cache_.k##TypeName##Array, buffer_type, zone()); |
+#define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size) \ |
+ stdlib_heap_types_[#TypeName "Array"] = new (zone()) VariableInfo( \ |
+ Type::Function(cache_.k##TypeName##Array, buffer_type, zone())); |
TYPED_ARRAYS(TYPED_ARRAY) |
#undef TYPED_ARRAY |
} |
-Type* AsmTyper::LibType(ObjectTypeMap map, Handle<String> name) { |
+void AsmTyper::VisitLibraryAccess(ObjectTypeMap* map, Property* expr) { |
+ Literal* key = expr->key()->AsLiteral(); |
+ if (key == NULL || !key->IsPropertyName()) |
+ FAIL(expr, "invalid key used on stdlib member"); |
+ Handle<String> name = key->AsPropertyName(); |
+ VariableInfo* info = LibType(map, name); |
+ if (info == NULL || info->type == NULL) FAIL(expr, "unknown stdlib function"); |
+ SetResult(expr, info->type); |
+ property_info_ = info; |
+} |
+ |
+ |
+AsmTyper::VariableInfo* AsmTyper::LibType(ObjectTypeMap* map, |
+ Handle<String> name) { |
base::SmartArrayPointer<char> aname = name->ToCString(); |
- ObjectTypeMap::iterator i = map.find(std::string(aname.get())); |
- if (i == map.end()) { |
+ ObjectTypeMap::iterator i = map->find(std::string(aname.get())); |
+ if (i == map->end()) { |
return NULL; |
} |
return i->second; |
@@ -1208,32 +1296,52 @@ Type* AsmTyper::LibType(ObjectTypeMap map, Handle<String> name) { |
void AsmTyper::SetType(Variable* variable, Type* type) { |
- ZoneHashMap::Entry* entry; |
- if (in_function_) { |
- entry = local_variable_type_.LookupOrInsert( |
- variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone())); |
- } else { |
- entry = global_variable_type_.LookupOrInsert( |
- variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone())); |
- } |
- entry->value = reinterpret_cast<void*>(type); |
+ VariableInfo* info = GetVariableInfo(variable, true); |
+ info->type = type; |
} |
Type* AsmTyper::GetType(Variable* variable) { |
- i::ZoneHashMap::Entry* entry = NULL; |
+ VariableInfo* info = GetVariableInfo(variable, false); |
+ if (!info) return NULL; |
+ return info->type; |
+} |
+ |
+ |
+AsmTyper::VariableInfo* AsmTyper::GetVariableInfo(Variable* variable, |
+ bool setting) { |
+ ZoneHashMap::Entry* entry; |
+ ZoneHashMap* map; |
if (in_function_) { |
- entry = local_variable_type_.Lookup(variable, ComputePointerHash(variable)); |
- } |
- if (entry == NULL) { |
- entry = |
- global_variable_type_.Lookup(variable, ComputePointerHash(variable)); |
+ map = &local_variable_type_; |
+ } else { |
+ map = &global_variable_type_; |
} |
- if (entry == NULL) { |
- return NULL; |
+ if (setting) { |
+ entry = map->LookupOrInsert(variable, ComputePointerHash(variable), |
+ ZoneAllocationPolicy(zone())); |
} else { |
- return reinterpret_cast<Type*>(entry->value); |
+ entry = map->Lookup(variable, ComputePointerHash(variable)); |
+ if (!entry && in_function_) { |
+ entry = |
+ global_variable_type_.Lookup(variable, ComputePointerHash(variable)); |
+ } |
} |
+ if (!entry) return NULL; |
+ if (!entry->value) { |
+ if (!setting) return NULL; |
+ entry->value = new (zone()) VariableInfo; |
+ } |
+ return reinterpret_cast<VariableInfo*>(entry->value); |
+} |
+ |
+ |
+void AsmTyper::SetVariableInfo(Variable* variable, const VariableInfo* info) { |
+ VariableInfo* dest = GetVariableInfo(variable, true); |
+ dest->type = info->type; |
+ dest->is_stdlib_object = info->is_stdlib_object; |
+ dest->is_check_function = info->is_check_function; |
+ dest->is_constructor_function = info->is_constructor_function; |
} |