| Index: src/asmjs/asm-typer.cc
|
| diff --git a/src/asmjs/asm-typer.cc b/src/asmjs/asm-typer.cc
|
| index 07bf63fd0214373df57bfaf92f122bef5766ea59..9bc19f2aebce2890c899c0f245cc7e8e9759ba3e 100644
|
| --- a/src/asmjs/asm-typer.cc
|
| +++ b/src/asmjs/asm-typer.cc
|
| @@ -48,6 +48,9 @@
|
| namespace v8 {
|
| namespace internal {
|
| namespace wasm {
|
| +namespace {
|
| +static const uint32_t LargestFixNum = std::numeric_limits<int32_t>::max();
|
| +} // namespace
|
|
|
| using v8::internal::AstNode;
|
| using v8::internal::GetCurrentStackPosition;
|
| @@ -122,7 +125,8 @@ AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script,
|
| ZoneHashMap::kDefaultHashMapCapacity,
|
| ZoneAllocationPolicy(zone)),
|
| stack_limit_(isolate->stack_guard()->real_climit()),
|
| - node_types_(zone_) {
|
| + node_types_(zone_),
|
| + fround_type_(AsmType::FroundType(zone_)) {
|
| InitializeStdlib();
|
| module_info_.set_standard_member(kModule);
|
| }
|
| @@ -165,12 +169,16 @@ void AsmTyper::InitializeStdlib() {
|
| ii2s->AsFunctionType()->AddArgument(i);
|
|
|
| auto* minmax_d = AsmType::MinMaxType(zone_, d, d);
|
| + // *VIOLATION* The float variant is not part of the spec, but firefox accepts
|
| + // it.
|
| + auto* minmax_f = AsmType::MinMaxType(zone_, f, f);
|
| auto* minmax_i = AsmType::MinMaxType(zone_, s, i);
|
| auto* minmax = AsmType::OverloadedFunction(zone_);
|
| minmax->AsOverloadedFunctionType()->AddOverload(minmax_i);
|
| + minmax->AsOverloadedFunctionType()->AddOverload(minmax_f);
|
| minmax->AsOverloadedFunctionType()->AddOverload(minmax_d);
|
|
|
| - auto* fround = AsmType::FroundType(zone_);
|
| + auto* fround = fround_type_;
|
|
|
| auto* abs = AsmType::OverloadedFunction(zone_);
|
| abs->AsOverloadedFunctionType()->AddOverload(s2s);
|
| @@ -362,17 +370,36 @@ bool AsmTyper::AddLocal(Variable* variable, VariableInfo* info) {
|
|
|
| void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) {
|
| DCHECK_NE(type, AsmType::None());
|
| - auto** node_type = &node_types_[node];
|
| - DCHECK(*node_type == nullptr);
|
| - *node_type = type;
|
| + DCHECK(node_types_.find(node) == node_types_.end());
|
| + node_types_.insert(std::make_pair(node, type));
|
| }
|
|
|
| AsmType* AsmTyper::TypeOf(AstNode* node) const {
|
| auto node_type_iter = node_types_.find(node);
|
| - if (node_type_iter == node_types_.end()) {
|
| - return AsmType::None();
|
| + if (node_type_iter != node_types_.end()) {
|
| + return node_type_iter->second;
|
| + }
|
| +
|
| + // Sometimes literal nodes are not added to the node_type_ map simply because
|
| + // their are not visited with ValidateExpression().
|
| + if (auto* literal = node->AsLiteral()) {
|
| + if (literal->raw_value()->ContainsDot()) {
|
| + return AsmType::Double();
|
| + }
|
| + uint32_t u;
|
| + if (literal->value()->ToUint32(&u)) {
|
| + if (u > LargestFixNum) {
|
| + return AsmType::Unsigned();
|
| + }
|
| + return AsmType::FixNum();
|
| + }
|
| + int32_t i;
|
| + if (literal->value()->ToInt32(&i)) {
|
| + return AsmType::Signed();
|
| + }
|
| }
|
| - return node_type_iter->second;
|
| +
|
| + return AsmType::None();
|
| }
|
|
|
| AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
|
| @@ -607,11 +634,13 @@ AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) {
|
| auto* value = assign->value();
|
| // Not all types of assignment are allowed by asm.js. See
|
| // 5.5 Global Variable Type Annotations.
|
| + bool global_variable = false;
|
| if (value->IsLiteral() || value->IsCall()) {
|
| AsmType* type = nullptr;
|
| RECURSE(type = VariableTypeAnnotations(value));
|
| target_info = new (zone_) VariableInfo(type);
|
| target_info->set_mutability(VariableInfo::kMutableGlobal);
|
| + global_variable = true;
|
| } else if (value->IsProperty()) {
|
| target_info = ImportLookup(value->AsProperty());
|
| if (target_info == nullptr) {
|
| @@ -689,6 +718,12 @@ AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) {
|
| }
|
|
|
| DCHECK(target_info->type() != AsmType::None());
|
| + if (!global_variable) {
|
| + // Global variables have their types set in VariableTypeAnnotations.
|
| + SetTypeOf(value, target_info->type());
|
| + }
|
| + SetTypeOf(assign, target_info->type());
|
| + SetTypeOf(target, target_info->type());
|
| return target_info->type();
|
| }
|
|
|
| @@ -830,6 +865,7 @@ AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
|
| DCHECK(false);
|
| FAIL(assign, "Redeclared global identifier in function table name.");
|
| }
|
| + SetTypeOf(value, target_info->type());
|
| return target_info->type();
|
| }
|
|
|
| @@ -854,7 +890,7 @@ AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
|
| }
|
|
|
| target_info->MarkDefined();
|
| - DCHECK(target_info->type() == AsmType::None());
|
| + DCHECK(target_info->type() != AsmType::None());
|
| SetTypeOf(value, target_info->type());
|
|
|
| return target_info->type();
|
| @@ -916,6 +952,8 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
|
| FAIL(proxy, "Redeclared parameter.");
|
| }
|
| parameter_types.push_back(type);
|
| + SetTypeOf(proxy, type);
|
| + SetTypeOf(expr, type);
|
| }
|
|
|
| if (annotated_parameters != fun->parameter_count()) {
|
| @@ -952,6 +990,9 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
|
| if (!AddLocal(local->var(), local_info)) {
|
| FAIL(initializer, "Redeclared local.");
|
| }
|
| +
|
| + SetTypeOf(local, type);
|
| + SetTypeOf(initializer, type);
|
| }
|
|
|
| // 5.2 Return Type Annotations
|
| @@ -1018,6 +1059,8 @@ AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
|
| DCHECK(false);
|
| FAIL(fun_decl, "Redeclared global identifier.");
|
| }
|
| +
|
| + SetTypeOf(fun, fun_type);
|
| return fun_type;
|
| }
|
|
|
| @@ -1221,6 +1264,7 @@ AsmType* AsmTyper::ValidateSwitchStatement(SwitchStatement* stmt) {
|
| CHECK(!has_default);
|
| RECURSE(ValidateDefault(a_case));
|
| has_default = true;
|
| + continue;
|
| }
|
|
|
| int32_t case_lbl;
|
| @@ -1364,7 +1408,7 @@ bool IsUnaryMinus(BinaryOperation* binop) {
|
| return false;
|
| }
|
|
|
| - return right_as_literal->raw_value()->ContainsDot() &&
|
| + return !right_as_literal->raw_value()->ContainsDot() &&
|
| right_as_literal->raw_value()->AsNumber() == -1.0;
|
| }
|
| } // namespace
|
| @@ -1391,6 +1435,7 @@ AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) {
|
| }
|
| AsmType* left_type;
|
| RECURSE(left_type = ValidateExpression(expr->left()));
|
| + SetTypeOf(expr->right(), AsmType::Double());
|
| UNOP_OVERLOAD(Signed, Double);
|
| UNOP_OVERLOAD(Unsigned, Double);
|
| UNOP_OVERLOAD(DoubleQ, Double);
|
| @@ -1402,6 +1447,7 @@ AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) {
|
| // *VIOLATION* the parser converts -x to x * -1.0.
|
| AsmType* left_type;
|
| RECURSE(left_type = ValidateExpression(expr->left()));
|
| + SetTypeOf(expr->right(), left_type);
|
| UNOP_OVERLOAD(Int, Intish);
|
| UNOP_OVERLOAD(DoubleQ, Double);
|
| UNOP_OVERLOAD(FloatQ, Floatish);
|
| @@ -1431,6 +1477,9 @@ AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) {
|
| // This is the special ~~ operator.
|
| AsmType* left_type;
|
| RECURSE(left_type = ValidateExpression(left_as_binop->left()));
|
| + SetTypeOf(left_as_binop->right(), AsmType::FixNum());
|
| + SetTypeOf(left_as_binop, AsmType::Signed());
|
| + SetTypeOf(expr->right(), AsmType::FixNum());
|
| UNOP_OVERLOAD(Double, Signed);
|
| UNOP_OVERLOAD(FloatQ, Signed);
|
| FAIL(left_as_binop, "Invalid type for conversion to signed.");
|
| @@ -1456,24 +1505,21 @@ AsmType* AsmTyper::ValidateCommaExpression(BinaryOperation* comma) {
|
| // (expr COMMA (expr COMMA (expr COMMA (... ))))
|
|
|
| auto* left = comma->left();
|
| - auto* left_as_binop = left->AsBinaryOperation();
|
| - if (left_as_binop && left_as_binop->op() == Token::COMMA) {
|
| - ValidateCommaExpression(left_as_binop);
|
| - } else if (auto* left_as_call = left->AsCall()) {
|
| - ValidateCall(AsmType::Void(), left_as_call);
|
| + if (auto* left_as_call = left->AsCall()) {
|
| + RECURSE(ValidateCall(AsmType::Void(), left_as_call));
|
| } else {
|
| - ValidateExpression(left);
|
| + RECURSE(ValidateExpression(left));
|
| }
|
|
|
| auto* right = comma->right();
|
| - auto* right_as_binop = right->AsBinaryOperation();
|
| - if (right_as_binop && right_as_binop->op() == Token::COMMA) {
|
| - return ValidateCommaExpression(right_as_binop);
|
| + AsmType* right_type = nullptr;
|
| + if (auto* right_as_call = right->AsCall()) {
|
| + RECURSE(right_type = ValidateCall(AsmType::Void(), right_as_call));
|
| } else {
|
| - return ValidateExpression(right);
|
| + RECURSE(right_type = ValidateExpression(right));
|
| }
|
|
|
| - UNREACHABLE();
|
| + return right_type;
|
| }
|
|
|
| // 6.8.2 NumericLiteral
|
| @@ -1500,7 +1546,6 @@ AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) {
|
| return AsmType::Signed();
|
| }
|
|
|
| - static const uint32_t LargestFixNum = std::numeric_limits<int32_t>::max();
|
| if (value <= LargestFixNum) {
|
| return AsmType::FixNum();
|
| }
|
| @@ -1587,13 +1632,15 @@ AsmType* AsmTyper::ValidateAssignmentExpression(Assignment* assignment) {
|
| ValidateHeapAccess(target_as_property, StoreToHeap));
|
|
|
| // TODO(jpp): Change FloatishDoubleQ and FloatQDoubleQ so that they are base
|
| - // classes for Floatish, DoubleQ, and FloatQ, and then invert this if so
|
| - // that it reads more naturally as
|
| - //
|
| - // if (!value_type->IsA(allowed_store_types))
|
| - if (allowed_store_types == AsmType::FloatishDoubleQ() ||
|
| - allowed_store_types == AsmType::FloatQDoubleQ()) {
|
| - if (!allowed_store_types->IsA(value_type)) {
|
| + // classes for Floatish, DoubleQ, and FloatQ.
|
| + if (allowed_store_types == AsmType::FloatishDoubleQ()) {
|
| + if (!value_type->IsA(AsmType::Floatish()) &&
|
| + !value_type->IsA(AsmType::DoubleQ())) {
|
| + FAIL(assignment, "Type mismatch in heap assignment.");
|
| + }
|
| + } else if (allowed_store_types == AsmType::FloatQDoubleQ()) {
|
| + if (!value_type->IsA(AsmType::FloatQ()) &&
|
| + !value_type->IsA(AsmType::DoubleQ())) {
|
| FAIL(assignment, "Type mismatch in heap assignment.");
|
| }
|
| } else {
|
| @@ -1778,6 +1825,7 @@ AsmType* AsmTyper::ValidateAdditiveExpression(BinaryOperation* binop,
|
| left_as_binop->op() == Token::SUB)) {
|
| RECURSE(left_type =
|
| ValidateAdditiveExpression(left_as_binop, intish_count + 1));
|
| + SetTypeOf(left_as_binop, left_type);
|
| } else {
|
| RECURSE(left_type = ValidateExpression(left));
|
| }
|
| @@ -1790,6 +1838,7 @@ AsmType* AsmTyper::ValidateAdditiveExpression(BinaryOperation* binop,
|
| right_as_binop->op() == Token::SUB)) {
|
| RECURSE(right_type =
|
| ValidateAdditiveExpression(right_as_binop, intish_count + 1));
|
| + SetTypeOf(right_as_binop, right_type);
|
| } else {
|
| RECURSE(right_type = ValidateExpression(right));
|
| }
|
| @@ -2084,32 +2133,14 @@ bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) {
|
|
|
| return base::bits::IsPowerOfTwo32(1 + *value);
|
| }
|
| -
|
| -// TODO(jpp): Add a AsmType::ValidateCall is poorly designed. It can only handle
|
| -// function declarations, not invocations. CheckInvocationOf temporarily works
|
| -// around this limitation by converting each actual in actuals to a parameter
|
| -// type before invoking prototype->ValidateCall. This is the wrong behavior for
|
| -// FFIs (we need to pass Signed integers to FFIs, not Ints), so that case is
|
| -// handled separately.
|
| -bool CheckInvocationOf(AsmCallableType* prototype, AsmType* return_type,
|
| - ZoneVector<AsmType*>* actuals) {
|
| - if (auto* ffi = prototype->AsFFIType()) {
|
| - return ffi->ValidateCall(return_type, *actuals) != AsmType::None();
|
| - }
|
| -
|
| - for (size_t ii = 0; ii < actuals->size(); ++ii) {
|
| - (*actuals)[ii] = (*actuals)[ii]->ToParameterType();
|
| - }
|
| - return prototype->ValidateCall(return_type, *actuals) != AsmType::None();
|
| -}
|
| -
|
| } // namespace
|
|
|
| AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
|
| AsmType* float_coercion_type;
|
| RECURSE(float_coercion_type = ValidateFloatCoercion(call));
|
| if (float_coercion_type == AsmType::Float()) {
|
| - return AsmType::Float();
|
| + SetTypeOf(call, AsmType::Float());
|
| + return return_type;
|
| }
|
|
|
| // TODO(jpp): we should be able to reuse the args vector's storage space.
|
| @@ -2148,6 +2179,8 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
|
| DCHECK(false);
|
| FAIL(call, "Redeclared global identifier.");
|
| }
|
| + SetTypeOf(call_var_proxy, reinterpret_cast<AsmType*>(call_type));
|
| + SetTypeOf(call, return_type);
|
| return return_type;
|
| }
|
|
|
| @@ -2161,10 +2194,12 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
|
| FAIL(call, "Foreign functions can't return float.");
|
| }
|
|
|
| - if (!CheckInvocationOf(callee_type, return_type, &args)) {
|
| + if (!callee_type->CanBeInvokedWith(return_type, args)) {
|
| FAIL(call, "Function invocation does not match function type.");
|
| }
|
|
|
| + SetTypeOf(call_var_proxy, call_var_info->type());
|
| + SetTypeOf(call, return_type);
|
| return return_type;
|
| }
|
|
|
| @@ -2221,6 +2256,8 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
|
| DCHECK(false);
|
| FAIL(call, "Redeclared global identifier.");
|
| }
|
| + SetTypeOf(call_property, reinterpret_cast<AsmType*>(call_type));
|
| + SetTypeOf(call, return_type);
|
| return return_type;
|
| }
|
|
|
| @@ -2236,12 +2273,15 @@ AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
|
| auto* previous_type_signature =
|
| previous_type->signature()->AsFunctionType();
|
| DCHECK(previous_type_signature != nullptr);
|
| - if (!CheckInvocationOf(previous_type_signature, return_type, &args)) {
|
| + if (!previous_type_signature->CanBeInvokedWith(return_type, args)) {
|
| + // TODO(jpp): better error messages.
|
| FAIL(call,
|
| "Function pointer table signature does not match previous "
|
| "signature.");
|
| }
|
|
|
| + SetTypeOf(call_property, previous_type->signature());
|
| + SetTypeOf(call, return_type);
|
| return return_type;
|
| }
|
|
|
| @@ -2280,6 +2320,7 @@ AsmType* AsmTyper::ValidateHeapAccess(Property* heap,
|
| if (!obj_type->IsA(AsmType::Heap())) {
|
| FAIL(heap, "Identifier does not represent a heap view.");
|
| }
|
| + SetTypeOf(obj, obj_type);
|
|
|
| if (auto* key_as_literal = heap->key()->AsLiteral()) {
|
| if (key_as_literal->raw_value()->ContainsDot()) {
|
| @@ -2371,6 +2412,7 @@ AsmType* AsmTyper::ValidateFloatCoercion(Call* call) {
|
| RECURSE(arg_type = ValidateExpression(arg));
|
| if (arg_type->IsA(AsmType::Floatish()) || arg_type->IsA(AsmType::DoubleQ()) ||
|
| arg_type->IsA(AsmType::Signed()) || arg_type->IsA(AsmType::Unsigned())) {
|
| + SetTypeOf(call->expression(), fround_type_);
|
| return AsmType::Float();
|
| }
|
|
|
| @@ -2395,9 +2437,11 @@ AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter,
|
| "Invalid parameter type annotation - should annotate a parameter.");
|
| }
|
| if (IsDoubleAnnotation(binop)) {
|
| + SetTypeOf(left, AsmType::Double());
|
| return AsmType::Double();
|
| }
|
| if (IsIntAnnotation(binop)) {
|
| + SetTypeOf(left, AsmType::Int());
|
| return AsmType::Int();
|
| }
|
| FAIL(binop, "Invalid parameter type annotation.");
|
| @@ -2428,6 +2472,7 @@ AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter,
|
| "a parameter.");
|
| }
|
|
|
| + SetTypeOf(src_expr, AsmType::Float());
|
| return AsmType::Float();
|
| }
|
|
|
| @@ -2485,18 +2530,26 @@ AsmType* AsmTyper::ReturnTypeAnnotations(ReturnStatement* statement) {
|
| AsmType* AsmTyper::VariableTypeAnnotations(Expression* initializer) {
|
| if (auto* literal = initializer->AsLiteral()) {
|
| if (literal->raw_value()->ContainsDot()) {
|
| + SetTypeOf(initializer, AsmType::Double());
|
| return AsmType::Double();
|
| }
|
| int32_t i32;
|
| uint32_t u32;
|
| - if (literal->value()->ToInt32(&i32) || literal->value()->ToUint32(&u32)) {
|
| - return AsmType::Int();
|
| + if (literal->value()->ToUint32(&u32)) {
|
| + if (u32 > LargestFixNum) {
|
| + SetTypeOf(initializer, AsmType::Unsigned());
|
| + } else {
|
| + SetTypeOf(initializer, AsmType::FixNum());
|
| + }
|
| + } else if (literal->value()->ToInt32(&i32)) {
|
| + SetTypeOf(initializer, AsmType::Signed());
|
| + } else {
|
| + FAIL(initializer, "Invalid type annotation - forbidden literal.");
|
| }
|
| - FAIL(initializer, "Invalid type annotation - forbidden literal.");
|
| + return AsmType::Int();
|
| }
|
|
|
| auto* call = initializer->AsCall();
|
| - DCHECK(call != nullptr);
|
| if (call == nullptr) {
|
| FAIL(initializer,
|
| "Invalid variable initialization - it should be a literal, or "
|
|
|