Chromium Code Reviews| Index: src/typing-asm.cc |
| diff --git a/src/typing-asm.cc b/src/typing-asm.cc |
| index e121e7f19accd7961d5039be617780f16199b23b..c45d6a6a1f0c30cf0d4490f4758ebccb6f79e8f2 100644 |
| --- a/src/typing-asm.cc |
| +++ b/src/typing-asm.cc |
| @@ -38,15 +38,21 @@ 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), |
| 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)), |
| @@ -92,6 +98,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); |
| } |
| @@ -155,7 +165,7 @@ void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) { |
| if (literal) { |
| RECURSE(VisitLiteral(literal, true)); |
| } else { |
| - RECURSE(VisitExpressionAnnotation(stmt->expression(), true)); |
| + RECURSE(VisitExpressionAnnotation(stmt->expression(), true, NULL)); |
| } |
| expected_type_ = old_expected; |
| result_type = computed_type_; |
| @@ -179,7 +189,11 @@ void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) { |
| Variable* var = proxy->var(); |
| if (var->location() != VariableLocation::PARAMETER || var->index() != i) |
| break; |
| - RECURSE(VisitExpressionAnnotation(expr->value(), false)); |
| + RECURSE(VisitExpressionAnnotation(expr->value(), false, var)); |
| + if (property_info_ != NULL) { |
| + SetVariableInfo(var, property_info_); |
| + property_info_ = NULL; |
| + } |
| SetType(var, computed_type_); |
| type->InitParameter(i, computed_type_); |
| good = true; |
| @@ -190,10 +204,20 @@ void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) { |
| } |
| -void AsmTyper::VisitExpressionAnnotation(Expression* expr, bool is_return) { |
| +void AsmTyper::VisitExpressionAnnotation(Expression* expr, bool is_return, |
| + Variable* variable) { |
| // Normal +x or x|0 annotations. |
| BinaryOperation* bin = expr->AsBinaryOperation(); |
| if (bin != NULL) { |
| + if (variable != NULL) { |
| + VariableProxy* proxy = bin->left()->AsVariableProxy(); |
| + if (proxy == NULL) { |
| + FAIL(bin->left(), "expected variable for type annotation"); |
| + } |
| + if (proxy->var() != variable) { |
| + FAIL(proxy, "annotation source doesn't match destination"); |
| + } |
| + } |
| Literal* right = bin->right()->AsLiteral(); |
| if (right != NULL) { |
| switch (bin->op()) { |
| @@ -230,19 +254,28 @@ void AsmTyper::VisitExpressionAnnotation(Expression* expr, bool is_return) { |
| 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"); |
| + } |
| + } |
| + Type* type = info->type; |
| + DCHECK(type->IsFunction()); |
| + if (info->is_check_function) { |
| + DCHECK(type->AsFunction()->Arity() == 1); |
| } |
| - if (call->arguments()->length() != 1) { |
| - FAIL(call, "invalid argument count calling fround"); |
| + if (call->arguments()->length() != type->AsFunction()->Arity()) { |
| + FAIL(call, "invalid argument count calling function"); |
| } |
| - SetResult(expr, cache_.kAsmFloat); |
| + SetResult(expr, type->AsFunction()->Result()); |
| return; |
| } |
| } |
| @@ -488,10 +521,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; |
| } |
| @@ -688,36 +726,107 @@ void AsmTyper::VisitHeapAccess(Property* expr) { |
| } |
| +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) return info->is_stdlib; |
| + } |
| + if (var->location() != VariableLocation::PARAMETER || var->index() != 0) { |
| + return false; |
| + } |
| + info = GetVariableInfo(var, true); |
| + info->type = Type::Object(); |
| + info->is_stdlib = 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); |
| +} |
| + |
| + |
| +bool AsmTyper::IsSIMDTypeObject(Expression* expr, const char* name) { |
| + Expression* obj = GetReceiverOfPropertyAccess(expr, name); |
| + return obj && IsSIMDObject(obj); |
| +} |
| + |
| + |
| void AsmTyper::VisitProperty(Property* expr) { |
| - // stdlib.Math.x |
| - Property* inner_prop = expr->obj()->AsProperty(); |
| - if (inner_prop != NULL) { |
| - // Get property name. |
| + if (IsMathObject(expr->obj())) { |
| Literal* key = expr->key()->AsLiteral(); |
| if (key == NULL || !key->IsPropertyName()) |
| - FAIL(expr, "invalid type annotation on property 2"); |
| + FAIL(expr, "invalid key used on Math object"); |
| 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)"); |
| - |
| - // Look up library type. |
| - Type* type = LibType(stdlib_math_types_, name); |
| - if (type == NULL) FAIL(expr, "unknown standard function 3 "); |
| - SetResult(expr, type); |
| + VariableInfo* info = LibType(stdlib_math_types_, name); |
| + if (info == NULL || info->type == NULL) FAIL(expr, "unknown Math function"); |
| + SetResult(expr, info->type); |
| + property_info_ = info; |
| + return; |
| + } |
| +#define V(NAME, Name, name, lane_count, lane_type) \ |
|
titzer
2015/11/30 20:40:14
That's a big hunk of code. Not sure how many types
bradn
2015/11/30 21:10:50
Done.
|
| + if (IsSIMDTypeObject(expr->obj(), #Name)) { \ |
| + Literal* key = expr->key()->AsLiteral(); \ |
| + if (key == NULL || !key->IsPropertyName()) \ |
| + FAIL(expr, "invalid key used on SIMD type object"); \ |
| + Handle<String> kname = key->AsPropertyName(); \ |
| + VariableInfo* info = LibType(stdlib_simd_##name##_types_, kname); \ |
| + if (info == NULL || info->type == NULL) \ |
| + FAIL(expr, "unknown Math function"); \ |
| + SetResult(expr, info->type); \ |
| + property_info_ = info; \ |
| + 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())) { |
| + Literal* key = expr->key()->AsLiteral(); |
| + if (key == NULL || !key->IsPropertyName()) |
| + FAIL(expr, "invalid key used on stdlib object"); |
| + Handle<String> name = key->AsPropertyName(); |
| + VariableInfo* info = LibType(stdlib_types_, name); |
| + if (info == NULL || info->type == NULL) |
| + FAIL(expr, "unknown standard function"); |
| + SetResult(expr, info->type); |
| + property_info_ = info; |
| return; |
| } |
| + property_info_ = NULL; |
| + |
| // Only recurse at this point so that we avoid needing |
| // stdlib.Math to have a real type. |
| RECURSE(VisitWithExpectation(expr->obj(), Type::Any(), |
| @@ -729,35 +838,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; |
| } |
| } |
| @@ -1087,7 +1175,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()); |
| @@ -1121,27 +1228,29 @@ 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) { |
| +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()) { |
| @@ -1152,32 +1261,51 @@ 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) { |
|
titzer
2015/11/30 20:40:14
You probably need to initialize is_stdlib_object h
bradn
2015/11/30 21:10:50
Done.
|
| + VariableInfo* dest = GetVariableInfo(variable, true); |
| + dest->type = info->type; |
| + dest->is_check_function = info->is_check_function; |
| + dest->is_constructor_function = info->is_constructor_function; |
| } |