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

Side by Side Diff: test/cctest/test-asm-validator.cc

Issue 2071343003: V8. ASM-2-WASM. Validator V2. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Adds a few methods needed by the asm2wasm translator. Created 4 years, 5 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 unified diff | Download patch
« src/asmjs/asm-types.h ('K') | « src/v8.gyp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <cstring>
6 #include <functional>
7 #include <iostream>
8 #include <memory>
9
5 #include "src/v8.h" 10 #include "src/v8.h"
6 11
12 #include "src/asmjs/asm-typer.h"
13 #include "src/asmjs/asm-types.h"
7 #include "src/asmjs/typing-asm.h" 14 #include "src/asmjs/typing-asm.h"
8 #include "src/ast/ast-expression-visitor.h" 15 #include "src/ast/ast-expression-visitor.h"
16 #include "src/ast/ast-value-factory.h"
9 #include "src/ast/ast.h" 17 #include "src/ast/ast.h"
10 #include "src/ast/scopes.h" 18 #include "src/ast/scopes.h"
19 #include "src/base/platform/platform.h"
11 #include "src/parsing/parser.h" 20 #include "src/parsing/parser.h"
12 #include "src/parsing/rewriter.h" 21 #include "src/parsing/rewriter.h"
13 #include "src/type-cache.h" 22 #include "src/type-cache.h"
14 #include "test/cctest/cctest.h" 23 #include "test/cctest/cctest.h"
15 #include "test/cctest/expression-type-collector-macros.h" 24 #include "test/cctest/expression-type-collector-macros.h"
16 #include "test/cctest/expression-type-collector.h" 25 #include "test/cctest/expression-type-collector.h"
17 26
18 // Macros for function types. 27 // Macros for function types.
19 #define FUNC_FOREIGN_TYPE Bounds(Type::Function(Type::Any(), zone)) 28 #define FUNC_FOREIGN_TYPE Bounds(Type::Function(Type::Any(), zone))
20 #define FUNC_V_TYPE Bounds(Type::Function(Type::Undefined(), zone)) 29 #define FUNC_V_TYPE Bounds(Type::Function(Type::Undefined(), zone))
(...skipping 18 matching lines...) Expand all
39 #define FUNC_N2N_TYPE \ 48 #define FUNC_N2N_TYPE \
40 Bounds(Type::Function(Type::Number(), Type::Number(), zone)) 49 Bounds(Type::Function(Type::Number(), Type::Number(), zone))
41 50
42 // Macros for array types. 51 // Macros for array types.
43 #define FLOAT64_ARRAY_TYPE Bounds(Type::Array(cache.kAsmDouble, zone)) 52 #define FLOAT64_ARRAY_TYPE Bounds(Type::Array(cache.kAsmDouble, zone))
44 #define FUNC_I2I_ARRAY_TYPE \ 53 #define FUNC_I2I_ARRAY_TYPE \
45 Bounds(Type::Array(Type::Function(cache.kAsmSigned, cache.kAsmInt, zone), \ 54 Bounds(Type::Array(Type::Function(cache.kAsmSigned, cache.kAsmInt, zone), \
46 zone)) 55 zone))
47 56
48 using namespace v8::internal; 57 using namespace v8::internal;
58 namespace iw = i::wasm;
49 59
50 namespace { 60 namespace {
51 61
52 std::string Validate(Zone* zone, const char* source, 62 std::string Validate(Zone* zone, const char* source,
53 ZoneVector<ExpressionTypeEntry>* types) { 63 ZoneVector<ExpressionTypeEntry>* types) {
54 i::Isolate* isolate = CcTest::i_isolate(); 64 i::Isolate* isolate = CcTest::i_isolate();
55 i::Factory* factory = isolate->factory(); 65 i::Factory* factory = isolate->factory();
56 66
57 i::Handle<i::String> source_code = 67 i::Handle<i::String> source_code =
58 factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked(); 68 factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked();
(...skipping 2488 matching lines...) Expand 10 before | Expand all | Expand 10 after
2547 CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmDouble)) { 2557 CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmDouble)) {
2548 CHECK_VAR(x, Bounds(cache.kAsmDouble)); 2558 CHECK_VAR(x, Bounds(cache.kAsmDouble));
2549 CHECK_EXPR(Literal, Bounds(cache.kAsmDouble)); 2559 CHECK_EXPR(Literal, Bounds(cache.kAsmDouble));
2550 } 2560 }
2551 } 2561 }
2552 } 2562 }
2553 CHECK_SKIP(); 2563 CHECK_SKIP();
2554 } 2564 }
2555 CHECK_FUNC_TYPES_END 2565 CHECK_FUNC_TYPES_END
2556 } 2566 }
2567
2568 // -----------------------------------------------------------------------------
2569 // asm.js typer v2.
2570
2571 namespace v8 {
2572 namespace internal {
2573 namespace wasm {
2574
2575 enum ValidationType {
2576 ValidateModule,
bradn 2016/07/11 17:55:34 Any reason not to put these in an anonymous namesp
John 2016/07/12 21:13:15 yes: AsmTyper has a friendship relationship with A
2577 ValidateGlobals,
2578 ValidateFunctionTables,
2579 ValidateExport,
2580 ValidateFunction,
2581 ValidateStatement,
2582 ValidateExpression,
2583 };
2584
2585 class AsmTyperHarnessBuilder {
2586 public:
2587 AsmTyperHarnessBuilder(const char* source, ValidationType type)
2588 : source_(source),
2589 validation_type_(type),
2590 handles_(),
2591 zone_(handles_.main_zone()),
2592 isolate_(CcTest::i_isolate()),
2593 ast_value_factory_(zone_, isolate_->heap()->HashSeed()),
2594 factory_(isolate_->factory()),
2595 source_code_(
2596 factory_->NewStringFromUtf8(CStrVector(source)).ToHandleChecked()),
2597 script_(factory_->NewScript(source_code_)) {
2598 ParseInfo info(zone_, script_);
2599 info.set_global();
2600 info.set_lazy(false);
2601 info.set_allow_lazy_parsing(false);
2602 info.set_toplevel(true);
2603 info.set_ast_value_factory(&ast_value_factory_);
2604 info.set_ast_value_factory_owned(false);
2605 Parser parser(&info);
2606
2607 if (!Compiler::ParseAndAnalyze(&info)) {
2608 std::cerr << "Failed to parse:\n" << source_ << "\n";
2609 CHECK(false);
2610 }
2611
2612 outer_scope_ = info.script_scope();
2613 module_ =
2614 info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun();
2615 typer_.reset(new AsmTyper(isolate_, zone_, *script_, module_));
2616
2617 if (validation_type_ == ValidateStatement ||
2618 validation_type_ == ValidateExpression) {
2619 fun_scope_.reset(new AsmTyper::FunctionScope(typer_.get()));
2620
2621 auto* decls = module_->scope()->declarations();
2622 for (int ii = 0; ii < decls->length(); ++ii) {
2623 Declaration* decl = decls->at(ii);
2624 if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) {
2625 fun_decl_ = fun_decl;
bradn 2016/07/11 17:55:33 CHECK that something's found?
John 2016/07/12 21:13:15 Done.
2626 break;
2627 }
2628 }
2629 }
2630 }
2631
2632 struct VariableName {
2633 VariableName(const char* name, VariableMode mode)
2634 : name_(name), mode_(mode) {}
2635 VariableName(const VariableName&) = default;
2636 VariableName& operator=(const VariableName&) = default;
2637
2638 const char* name_;
2639 const VariableMode mode_;
2640 };
2641
2642 AsmTyperHarnessBuilder* WithLocal(VariableName var_name, AsmType* type) {
2643 CHECK(validation_type_ == ValidateStatement ||
2644 validation_type_ == ValidateExpression);
2645 auto* var = DeclareVariable(var_name);
2646 auto* var_info = new (zone_) AsmTyper::VariableInfo(type);
2647 var_info->set_mutability(AsmTyper::VariableInfo::kLocal);
2648 CHECK(typer_->AddLocal(var, var_info));
2649 return this;
2650 }
2651
2652 AsmTyperHarnessBuilder* WithGlobal(VariableName var_name, AsmType* type) {
2653 auto* var = DeclareVariable(var_name);
2654 auto* var_info = new (zone_) AsmTyper::VariableInfo(type);
2655 var_info->set_mutability(AsmTyper::VariableInfo::kMutableGlobal);
2656 CHECK(typer_->AddGlobal(var, var_info));
2657 return this;
2658 }
2659
2660 AsmTyperHarnessBuilder* WithGlobal(
2661 VariableName var_name, std::function<AsmType*(Zone*)> type_creator) {
2662 return WithGlobal(var_name, type_creator(zone_));
2663 }
2664
2665 AsmTyperHarnessBuilder* WithUndefinedGlobal(
2666 VariableName var_name, std::function<AsmType*(Zone*)> type_creator) {
2667 auto* type = type_creator(zone_);
2668 CHECK(type->AsFunctionType() != nullptr ||
2669 type->AsFunctionTableType() != nullptr);
2670 WithGlobal(var_name, type);
2671 auto* var_info = typer_->Lookup(DeclareVariable(var_name));
2672 CHECK(var_info);
2673 var_info->FirstForwardUseIs(nullptr);
2674 return this;
2675 }
2676
2677 AsmTyperHarnessBuilder* WithImport(VariableName var_name,
2678 AsmTyper::StandardMember standard_member) {
2679 auto* var = DeclareVariable(var_name);
2680 AsmTyper::VariableInfo* var_info = nullptr;
2681 auto* stdlib_map = &typer_->stdlib_math_types_;
2682 switch (standard_member) {
2683 case AsmTyper::kHeap:
2684 case AsmTyper::kStdlib:
2685 case AsmTyper::kModule:
2686 case AsmTyper::kNone:
2687 CHECK(false);
2688 case AsmTyper::kFFI:
2689 stdlib_map = nullptr;
2690 var_info = new (zone_) AsmTyper::VariableInfo(AsmType::FFIType(zone_));
2691 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal);
2692 break;
2693 case AsmTyper::kInfinity:
2694 case AsmTyper::kNaN:
2695 stdlib_map = &typer_->stdlib_types_;
2696 default:
2697 break;
2698 }
2699
2700 if (var_info == nullptr) {
2701 for (auto iter : *stdlib_map) {
2702 if (iter.second->standard_member() == standard_member) {
2703 var_info = iter.second;
2704 break;
2705 }
2706 }
2707
2708 CHECK(var_info != nullptr);
2709 var_info = var_info->Clone(zone_);
2710 }
2711
2712 CHECK(typer_->AddGlobal(var, var_info));
2713 return this;
2714 }
2715
2716 AsmTyperHarnessBuilder* WithReturnType(AsmType* type) {
2717 CHECK(type->IsReturnType());
2718 CHECK(typer_->return_type_ == AsmType::None());
2719 typer_->return_type_ = type;
2720 return this;
2721 }
2722
2723 AsmTyperHarnessBuilder* WithStdlib(VariableName var_name) {
2724 auto* var = DeclareVariable(var_name);
2725 auto* var_info = new (zone_) AsmTyper::VariableInfo();
2726 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal);
2727 var_info->set_standard_member(AsmTyper::kStdlib);
2728 CHECK(typer_->AddGlobal(var, var_info));
2729 return this;
2730 }
2731
2732 AsmTyperHarnessBuilder* WithHeap(VariableName var_name) {
2733 auto* var = DeclareVariable(var_name);
2734 auto* var_info = new (zone_) AsmTyper::VariableInfo();
2735 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal);
2736 var_info->set_standard_member(AsmTyper::kHeap);
2737 CHECK(typer_->AddGlobal(var, var_info));
2738 return this;
2739 }
2740
2741 AsmTyperHarnessBuilder* WithFFI(VariableName var_name) {
2742 auto* var = DeclareVariable(var_name);
2743 auto* var_info =
2744 new (zone_) AsmTyper::VariableInfo(AsmType::FFIType(zone_));
2745 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal);
2746 var_info->set_standard_member(AsmTyper::kFFI);
2747 CHECK(typer_->AddGlobal(var, var_info));
2748 return this;
2749 }
2750
2751 bool Succeeds() {
2752 CHECK(validation_type_ == ValidateModule ||
2753 validation_type_ == ValidateGlobals ||
2754 validation_type_ == ValidateFunctionTables ||
2755 validation_type_ == ValidateExport ||
2756 validation_type_ == ValidateFunction ||
2757 validation_type_ == ValidateStatement);
2758
2759 if (validation_type_ == ValidateStatement) {
2760 CHECK(typer_->return_type_ != AsmType::None());
2761 if (ValidateAllStatements(fun_decl_)) {
2762 return true;
2763 }
2764 } else if (typer_->Validate()) {
2765 return true;
2766 }
2767
2768 std::cerr << "Asm validation failed: " << typer_->error_message() << "\n";
2769 return false;
2770 }
2771
2772 bool SucceedsWithExactType(AsmType* type) {
2773 CHECK(validation_type_ == ValidateExpression);
2774 auto* validated_as = ValidateExpressionStatment(fun_decl_);
2775 if (validated_as == AsmType::None()) {
2776 std::cerr << "Validation failure: " << typer_->error_message() << "\n";
2777 return false;
2778 } else if (validated_as != type) {
2779 std::cerr << "Validation succeeded with wrong type "
2780 << validated_as->Name() << " (vs. " << type->Name() << ").\n";
2781 return false;
2782 }
2783
2784 return true;
2785 }
2786
2787 bool FailsWithMessage(const char* error_message) {
2788 CHECK(validation_type_ == ValidateModule ||
2789 validation_type_ == ValidateGlobals ||
2790 validation_type_ == ValidateFunctionTables ||
2791 validation_type_ == ValidateExport ||
2792 validation_type_ == ValidateFunction ||
2793 validation_type_ == ValidateStatement ||
2794 validation_type_ == ValidateExpression);
2795
2796 bool success;
2797 if (validation_type_ == ValidateStatement) {
2798 CHECK(typer_->return_type_ != AsmType::None());
2799 success = ValidateAllStatements(fun_decl_);
2800 } else if (validation_type_ == ValidateExpression) {
2801 success = ValidateExpressionStatment(fun_decl_) != AsmType::None();
2802 } else {
2803 success = typer_->Validate();
2804 }
2805
2806 if (success) {
2807 std::cerr << "Asm validation succeeded\n";
2808 return false;
2809 }
2810
2811 if (std::strstr(typer_->error_message(), error_message) == nullptr) {
2812 std::cerr << "Asm validation failed with the wrong error message:\n"
2813 "Expected to contain '"
2814 << error_message << "'\n"
2815 " Actually is '"
2816 << typer_->error_message() << "'\n";
2817 return false;
2818 }
2819
2820 return true;
2821 }
2822
2823 private:
2824 Variable* DeclareVariable(VariableName var_name) {
2825 auto* name_ast_string = ast_value_factory_.GetOneByteString(var_name.name_);
2826 return var_name.mode_ == DYNAMIC_GLOBAL
2827 ? outer_scope_->DeclareDynamicGlobal(name_ast_string)
2828 : module_->scope()->DeclareLocal(name_ast_string, VAR,
2829 kCreatedInitialized,
2830 Variable::NORMAL);
2831 }
2832
2833 bool ValidateAllStatements(FunctionDeclaration* fun_decl) {
2834 AsmTyper::FlattenedStatements iter(zone_, fun_decl->fun()->body());
2835 while (auto* curr = iter.Next()) {
2836 if (typer_->ValidateStatement(curr) == AsmType::None()) {
2837 return false;
2838 }
2839 }
2840 return true;
2841 }
2842
2843 AsmType* ValidateExpressionStatment(FunctionDeclaration* fun_decl) {
2844 AsmTyper::FlattenedStatements iter(zone_, fun_decl->fun()->body());
2845 AsmType* ret = AsmType::None();
2846 bool last_was_expression_statement = false;
2847 while (auto* curr = iter.Next()) {
2848 if (auto* expr_stmt = curr->AsExpressionStatement()) {
2849 last_was_expression_statement = true;
2850 if ((ret = typer_->ValidateExpression(expr_stmt->expression())) ==
2851 AsmType::None()) {
2852 break;
2853 }
2854 } else {
2855 ret = AsmType::None();
2856 last_was_expression_statement = true;
2857 if (typer_->ValidateStatement(curr) == AsmType::None()) {
2858 break;
2859 }
2860 }
2861 }
2862 CHECK(last_was_expression_statement || ret == AsmType::None());
2863 return ret;
2864 }
2865
2866 std::string source_;
2867 ValidationType validation_type_;
2868 HandleAndZoneScope handles_;
2869 Zone* zone_;
2870 Isolate* isolate_;
2871 AstValueFactory ast_value_factory_;
2872 Factory* factory_;
2873 Handle<String> source_code_;
2874 Handle<Script> script_;
2875
2876 Scope* outer_scope_;
2877 FunctionLiteral* module_;
2878 FunctionDeclaration* fun_decl_;
2879 std::unique_ptr<AsmTyper> typer_;
2880 std::unique_ptr<AsmTyper::FunctionScope> fun_scope_;
2881 };
2882
2883 } // namespace wasm
2884 } // namespace internal
2885 } // namespace v8
2886
2887 namespace {
2888
2889 struct ValidationInput {
2890 ValidationInput(const std::string& source, iw::ValidationType type)
2891 : source_(source), type_(type) {}
2892
2893 const std::string source_;
2894 const iw::ValidationType type_;
2895 };
2896
2897 std::unique_ptr<iw::AsmTyperHarnessBuilder> ValidationOf(
2898 ValidationInput input) {
2899 return std::unique_ptr<iw::AsmTyperHarnessBuilder>(
2900 new iw::AsmTyperHarnessBuilder(input.source_.c_str(), input.type_));
2901 }
2902
2903 ValidationInput Module(const char* source) {
2904 return ValidationInput(source, iw::ValidateModule);
2905 }
2906
2907 std::string WrapInFunction(const char* source, bool needs_use_asm) {
2908 if (needs_use_asm) {
2909 return std::string(
2910 "function foo() {\n"
2911 " 'use asm';\n"
2912 " ") +
2913 source +
2914 "\n"
2915 "}";
2916 }
2917
2918 return std::string(
2919 "function bar() {\n"
2920 " ") +
2921 source +
2922 "\n"
2923 "}\n"
2924 "return {b: bar};\n";
2925 }
2926
2927 ValidationInput Globals(const char* source) {
2928 static const bool kNeedsUseAsm = true;
2929 return ValidationInput(WrapInFunction(source, kNeedsUseAsm),
2930 iw::ValidateGlobals);
2931 }
2932
2933 ValidationInput FunctionTables(const char* source) {
2934 static const bool kNeedsUseAsm = true;
2935 return ValidationInput(WrapInFunction(source, kNeedsUseAsm),
2936 iw::ValidateFunctionTables);
2937 }
2938
2939 ValidationInput Export(const char* source) {
2940 static const bool kNeedsUseAsm = true;
2941 return ValidationInput(WrapInFunction(source, kNeedsUseAsm),
2942 iw::ValidateExport);
2943 }
2944
2945 ValidationInput Function(const char* source) {
2946 static const bool kNeedsUseAsm = true;
2947 return ValidationInput(WrapInFunction(source, kNeedsUseAsm),
2948 iw::ValidateFunction);
2949 }
2950
2951 ValidationInput Statement(const char* source) {
2952 static const bool kDoesNotNeedUseAsm = false;
2953 static const bool kNeedsUseAsm = true;
2954 return ValidationInput(
2955 WrapInFunction(WrapInFunction(source, kDoesNotNeedUseAsm).c_str(),
2956 kNeedsUseAsm),
2957 iw::ValidateStatement);
2958 }
2959
2960 ValidationInput Expression(const char* source) {
2961 static const bool kDoesNotNeedUseAsm = false;
2962 static const bool kNeedsUseAsm = true;
2963 return ValidationInput(
2964 WrapInFunction(WrapInFunction(source, kDoesNotNeedUseAsm).c_str(),
2965 kNeedsUseAsm),
2966 iw::ValidateExpression);
2967 }
2968
2969 iw::AsmTyperHarnessBuilder::VariableName Var(const char* name) {
2970 return iw::AsmTyperHarnessBuilder::VariableName(name, VAR);
2971 }
2972
2973 iw::AsmTyperHarnessBuilder::VariableName DynamicGlobal(const char* name) {
2974 return iw::AsmTyperHarnessBuilder::VariableName(name, DYNAMIC_GLOBAL);
2975 }
2976
2977 TEST(MissingUseAsmDirective) {
2978 v8::V8::Initialize();
2979
2980 // We can't test the empty input ("") because the AsmTyperHarnessBuilder will
2981 // CHECK if there's no function in the top-level scope.
2982 const char* kTests[] = {"function module(){}",
2983 "function module(){ use_asm; }",
2984 "function module(){ \"use asm \"; }",
2985 "function module(){ \" use asm \"; }",
2986 "function module(){ \"use Asm\"; }"};
2987
2988 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
2989 const char* module = kTests[ii];
2990 if (!ValidationOf(Module(module))
2991 ->FailsWithMessage("Missing \"use asm\"")) {
2992 std::cerr << "Test:\n" << module;
2993 CHECK(false);
2994 }
2995 }
2996 }
2997
2998 TEST(InvalidModuleSignature) {
2999 v8::V8::Initialize();
3000
3001 const struct {
3002 const char* module;
3003 const char* error_message;
3004 } kTests[] = {
3005 {"function eval(){ \"use asm\"; }",
3006 "Invalid asm.js identifier in module name"},
3007 {"function arguments(){ \"use asm\"; }",
3008 "Invalid asm.js identifier in module name"},
3009 {"function module(eval){ \"use asm\"; }",
3010 "Invalid asm.js identifier in module parameter"},
3011 {"function module(arguments){ \"use asm\"; }",
3012 "Invalid asm.js identifier in module parameter"},
3013 {"function module(stdlib, eval){ \"use asm\"; }",
3014 "Invalid asm.js identifier in module parameter"},
3015 {"function module(stdlib, arguments){ \"use asm\"; }",
3016 "Invalid asm.js identifier in module parameter"},
3017 {"function module(stdlib, foreign, eval){ \"use asm\"; }",
3018 "Invalid asm.js identifier in module parameter"},
3019 {"function module(stdlib, foreign, arguments){ \"use asm\"; }",
3020 "Invalid asm.js identifier in module parameter"},
3021 {"function module(stdlib, foreign, heap, eval){ \"use asm\"; }",
3022 "asm.js modules may not have more than three parameters"},
3023 {"function module(stdlib, foreign, heap, arguments){ \"use asm\"; }",
3024 "asm.js modules may not have more than three parameters"},
3025 {"function module(module){ \"use asm\"; }",
3026 "Redeclared identifier in module parameter"},
3027 {"function module(stdlib, module){ \"use asm\"; }",
3028 "Redeclared identifier in module parameter"},
3029 {"function module(stdlib, stdlib){ \"use asm\"; }",
3030 "Redeclared identifier in module parameter"},
3031 {"function module(stdlib, foreign, module){ \"use asm\"; }",
3032 "Redeclared identifier in module parameter"},
3033 {"function module(stdlib, foreign, stdlib){ \"use asm\"; }",
3034 "Redeclared identifier in module parameter"},
3035 {"function module(stdlib, foreign, foreign){ \"use asm\"; }",
3036 "Redeclared identifier in module parameter"},
3037 };
3038
3039 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3040 const auto* test = kTests + ii;
3041 if (!ValidationOf(Module(test->module))
3042 ->FailsWithMessage(test->error_message)) {
3043 std::cerr << "Test:\n" << test->module;
3044 CHECK(false);
3045 }
3046 }
3047 }
3048
3049 TEST(ErrorsInGlobalVariableDefinition) {
3050 const struct {
3051 const char* decl;
3052 const char* error_message;
3053 } kTests[] = {
3054 {"var v;", "Global variable missing initializer"},
3055 {"var v = uninitialized;", "Invalid global variable initializer"},
3056 {"var v = 'use asm';", "type annotation - forbidden literal"},
3057 {"var v = 4294967296;", " - forbidden literal"},
3058 {"var v = not_fround;", "Invalid global variable initializer"},
3059 {"var v = not_fround(1);", "expected call fround(literal)"},
3060 {"var v = __fround__(1.0);", "expected call fround(literal)"},
3061 {"var v = fround(1.0, 1.0);", "expected call fround(literal)"},
3062 {"var v = fround(not_fround);", "literal argument for call to fround"},
3063 {"var v = fround(1);", "literal argument to be a floating point"},
3064 {"var v = stdlib.nan", "Invalid import"},
3065 {"var v = stdlib.Math.nan", "Invalid import"},
3066 {"var v = stdlib.Mathh.E", "Invalid import"},
3067 {"var v = stdlib.Math", "Invalid import"},
3068 {"var v = Stdlib.Math.E", "Invalid import"},
3069 {"var v = stdlib.Math.E[0]", "Invalid import"},
3070 {"var v = stdlibb.NaN", "Invalid import"},
3071 {"var v = ffi.NaN[0]", "Invalid import"},
3072 {"var v = heap.NaN[0]", "Invalid import"},
3073 {"var v = ffi.foo * 2.0;", "unrecognized annotation"},
3074 {"var v = ffi.foo|1;", "unrecognized annotation"},
3075 {"var v = ffi()|0;", "must import member"},
3076 {"var v = +ffi();", "must import member"},
3077 {"var v = ffi().a|0;", "object lookup failed"},
3078 {"var v = +ffi().a;", "object lookup failed"},
3079 {"var v = sstdlib.a|0;", "object lookup failed"},
3080 {"var v = +sstdlib.a;", "object lookup failed"},
3081 {"var v = stdlib.NaN|0;", "object is not the ffi"},
3082 {"var v = +stdlib.NaN;", "object is not the ffi"},
3083 {"var v = new f()", "Invalid type after new"},
3084 {"var v = new stdli.Uint8Array(heap)", "Unknown stdlib member in heap"},
3085 {"var v = new stdlib.dd(heap)", "Unknown stdlib member in heap"},
3086 {"var v = new stdlib.Math.fround(heap)", "Type is not a heap view type"},
3087 {"var v = new stdlib.Uint8Array(a, b)", "Invalid number of arguments"},
3088 {"var v = new stdlib.Uint8Array(heap())", "should be the module's heap"},
3089 {"var v = new stdlib.Uint8Array(heap_)", "instead of heap parameter"},
3090 {"var v = new stdlib.Uint8Array(ffi)", "should be the module's heap"},
3091 {"var eval = 0;", "in global variable"},
3092 {"var eval = 0.0;", "in global variable"},
3093 {"var eval = fround(0.0);", "in global variable"},
3094 {"var eval = +ffi.a;", "in global variable"},
3095 {"var eval = ffi.a|0;", "in global variable"},
3096 {"var eval = ffi.a;", "in global variable"},
3097 {"var eval = new stdlib.Uint8Array(heap);", "in global variable"},
bradn 2016/07/11 17:55:34 kind of an odd error message?
John 2016/07/12 21:13:15 These are only snippets of the actual error messag
3098 {"var arguments = 0;", "in global variable"},
3099 {"var arguments = 0.0;", "in global variable"},
3100 {"var arguments = fround(0.0);", "in global variable"},
3101 {"var arguments = +ffi.a;", "in global variable"},
3102 {"var arguments = ffi.a|0;", "in global variable"},
3103 {"var arguments = ffi.a;", "in global variable"},
3104 {"var arguments = new stdlib.Uint8Array(heap);", "in global variable"},
3105 {"var a = 0, a = 0.0;", "Redefined global variable"},
3106 {"var a = 0; var a = 0;", "Redefined global variable"},
3107 {"var a = 0, b = 0; var a = 0;", "Redefined global variable"},
3108 {"var a = 0, b = 0; var b = 0, a = 0.0;", "Redefined global variable"},
3109 };
3110
3111 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3112 const auto* test = kTests + ii;
3113 if (!ValidationOf(Globals(test->decl))
3114 ->WithStdlib(DynamicGlobal("stdlib"))
3115 ->WithFFI(DynamicGlobal("ffi"))
3116 ->WithHeap(DynamicGlobal("heap"))
3117 ->WithGlobal(DynamicGlobal("not_fround"), iw::AsmType::Int())
3118 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround)
3119 ->FailsWithMessage(test->error_message)) {
3120 std::cerr << "Test:\n" << test->decl;
3121 CHECK(false);
3122 }
3123 }
3124 }
3125
3126 TEST(ErrorsInFunctionTableDefinition) {
3127 const struct {
3128 const char* tables;
3129 const char* error_message;
3130 } kTests[] = {
3131 {"var a = [a, a, a];", "Invalid length for function pointer table"},
3132 {"var a = [d2s0()];", "must be a function name"},
3133 {"var a = [d2s44];", "Undefined identifier in function pointer"},
3134 {"var a = [fround];", "not be a member of the standard library"},
3135 {"var a = [imul];", "not be a member of the standard library"},
3136 {"var a = [ffi_import];", "must be an asm.js function"},
3137 {"var a = [dI];", "must be an asm.js function"},
3138 {"var a = [d2s0, d2s1, d2s0, f2s0];", "mismatch in function pointer"},
3139 {"var eval = [d2s0, d2s1];", "asm.js identifier in function table name"},
3140 {"var arguments = [d2s0, d2s1];", "asm.js identifier in function table"},
3141 {"var foo = [d2s0, d2s1];",
3142 "Identifier redefined as function pointer table"},
3143 {"var I = [d2s0, d2s1];",
3144 "Identifier redefined as function pointer table"},
3145 {"var d2s = [d2f0, d2f1];", "redefined as function pointer table"},
3146 {"var d2s_t = [d2s0];", "Function table size mismatch"},
3147 {"var d2s_t = [d2f0, d2f1];", "initializer does not match previous"},
3148 };
3149
3150 auto d2s = [](Zone* zone) -> iw::AsmType* {
3151 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed());
3152 ret->AsFunctionType()->AddArgument(iw::AsmType::Double());
3153 return ret;
3154 };
3155
3156 auto d2s_tbl = [](Zone* zone) -> iw::AsmType* {
3157 auto* d2s = iw::AsmType::Function(zone, iw::AsmType::Signed());
3158 d2s->AsFunctionType()->AddArgument(iw::AsmType::Double());
3159
3160 auto* ret = iw::AsmType::FunctionTableType(zone, 2, d2s);
3161 return ret;
3162 };
3163
3164 auto f2s = [](Zone* zone) -> iw::AsmType* {
3165 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed());
3166 ret->AsFunctionType()->AddArgument(iw::AsmType::Float());
3167 return ret;
3168 };
3169
3170 auto d2f = [](Zone* zone) -> iw::AsmType* {
3171 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Float());
3172 ret->AsFunctionType()->AddArgument(iw::AsmType::Double());
3173 return ret;
3174 };
3175
3176 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3177 const auto* test = kTests + ii;
3178 if (!ValidationOf(FunctionTables(test->tables))
3179 ->WithImport(DynamicGlobal("ffi_import"), iw::AsmTyper::kFFI)
3180 ->WithImport(DynamicGlobal("imul"), iw::AsmTyper::kMathImul)
3181 ->WithImport(DynamicGlobal("E"), iw::AsmTyper::kMathE)
3182 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround)
3183 ->WithImport(DynamicGlobal("floor"), iw::AsmTyper::kMathFround)
3184 ->WithGlobal(DynamicGlobal("d2s0"), d2s)
3185 ->WithGlobal(DynamicGlobal("d2s1"), d2s)
3186 ->WithGlobal(DynamicGlobal("f2s0"), f2s)
3187 ->WithGlobal(DynamicGlobal("f2s1"), f2s)
3188 ->WithGlobal(DynamicGlobal("d2f0"), d2f)
3189 ->WithGlobal(DynamicGlobal("d2f1"), d2f)
3190 ->WithGlobal(DynamicGlobal("dI"), iw::AsmType::Int())
3191 ->WithGlobal(Var("I"), iw::AsmType::Int())
3192 ->WithUndefinedGlobal(Var("d2s"), d2s)
3193 ->WithUndefinedGlobal(Var("d2s_t"), d2s_tbl)
3194 ->FailsWithMessage(test->error_message)) {
3195 std::cerr << "Test:\n" << test->tables;
3196 CHECK(false);
3197 }
3198 }
3199 }
3200
3201 TEST(ErrorsInModuleExport) {
3202 const struct {
3203 const char* module_export;
3204 const char* error_message;
3205 } kTests[] = {
3206 {"", "Missing asm.js module export"},
3207 {"return;", "Unrecognized expression in asm.js module export expression"},
3208 {"return f;", "Undefined identifier in asm.js module export"},
3209 {"return f();", "Unrecognized expression in asm.js module export"},
3210 {"return d2s_tbl;", "cannot export function tables"},
3211 {"return min;", "cannot export standard library functions"},
3212 {"return ffi;", "cannot export foreign functions"},
3213 {"return I;", "is not an asm.js function"},
3214 {"return {\'a\': d2s_tbl}", "cannot export function tables"},
bradn 2016/07/11 17:55:33 Why \' ?
John 2016/07/12 21:13:15 Because. Done.
3215 {"return {\'a\': min}", "cannot export standard library functions"},
3216 {"return {\'a\': ffi}", "cannot export foreign functions"},
3217 {"return {\'a\': f()}", "must be an asm.js function name"},
3218 {"return {\'a\': f}", "Undefined identifier in asm.js module export"},
3219 {"function v() { a(); } return {b: d2s}", "Missing definition for forw"},
3220 {"return {b: d2s, \'a\': d2s_tbl}", "cannot export function tables"},
3221 {"return {b: d2s, \'a\': min}", "cannot export standard library"},
3222 {"return {b: d2s, \'a\': ffi}", "cannot export foreign functions"},
3223 {"return {b: d2s, \'a\': f()}", "must be an asm.js function name"},
3224 {"return {b: d2s, \'a\': f}", "Undefined identifier in asm.js module"},
3225 };
3226
3227 auto d2s_tbl = [](Zone* zone) -> iw::AsmType* {
3228 auto* d2s = iw::AsmType::Function(zone, iw::AsmType::Signed());
3229 d2s->AsFunctionType()->AddArgument(iw::AsmType::Double());
3230
3231 auto* ret = iw::AsmType::FunctionTableType(zone, 2, d2s);
3232 return ret;
3233 };
3234
3235 auto d2s = [](Zone* zone) -> iw::AsmType* {
3236 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed());
3237 ret->AsFunctionType()->AddArgument(iw::AsmType::Double());
3238 return ret;
3239 };
3240
3241 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3242 const auto* test = kTests + ii;
3243 if (!ValidationOf(Export(test->module_export))
3244 ->WithGlobal(DynamicGlobal("d2s_tbl"), d2s_tbl)
3245 ->WithGlobal(DynamicGlobal("d2s"), d2s)
3246 ->WithImport(DynamicGlobal("min"), iw::AsmTyper::kMathMin)
3247 ->WithImport(DynamicGlobal("ffi"), iw::AsmTyper::kFFI)
3248 ->WithGlobal(DynamicGlobal("I"), iw::AsmType::Int())
3249 ->FailsWithMessage(test->error_message)) {
3250 std::cerr << "Test:\n" << test->module_export;
3251 CHECK(false);
3252 }
3253 }
3254 }
3255
3256 TEST(ErrorsInFunction) {
3257 auto d2s = [](Zone* zone) -> iw::AsmType* {
3258 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed());
3259 ret->AsFunctionType()->AddArgument(iw::AsmType::Double());
3260 return ret;
3261 };
3262
3263 const struct {
3264 const char* function;
3265 const char* error_message;
3266 } kTests[] = {
3267 {"function f(eval) {"
3268 " eval = eval|0;"
3269 "}\n",
3270 "Invalid asm.js identifier in parameter name"},
3271 {"function f(arguments) {"
3272 " arguments = arguments|0;"
3273 "}\n",
3274 "Invalid asm.js identifier in parameter name"},
3275 // The following error should actually be a "redeclared local," but the
3276 // AST "hides" the first parameter from us, so the parameter type checking
3277 // will fail because the validator will think that the a = a|0 is
3278 // annotating the second parameter.
3279 {"function f(a, a) {\n"
3280 " a = a|0;\n"
3281 " a = +a;\n"
3282 "}\n",
3283 "Incorrect parameter type annotations"},
3284 {"function f(b, a) {\n"
3285 " if (0) return;\n"
3286 " b = +b;\n"
3287 " a = a|0;\n"
3288 "}\n",
3289 "Incorrect parameter type annotations"},
3290 {"function f(b, a) {\n"
3291 " f();\n"
3292 " b = +b;\n"
3293 " a = a|0;\n"
3294 "}\n",
3295 "Incorrect parameter type annotations"},
3296 {"function f(b, a) {\n"
3297 " f.a = 0;\n"
3298 " b = +b;\n"
3299 " a = a|0;\n"
3300 "}\n",
3301 "Incorrect parameter type annotations"},
3302 {"function f(b, a) {\n"
3303 " a = a|0;\n"
3304 " b = +b;\n"
3305 "}\n",
3306 "Incorrect parameter type annotations"},
3307 {"function f(b, a) {\n"
3308 " b = +b;\n"
3309 " a = a|0;\n"
3310 " var eval = 0;\n"
3311 "}\n",
3312 "Invalid asm.js identifier in local variable"},
3313 {"function f(b, a) {\n"
3314 " b = +b;\n"
3315 " a = a|0;\n"
3316 " var b = 0;\n"
3317 "}\n",
3318 "Redeclared local"},
3319 {"function f(b, a) {\n"
3320 " b = +b;\n"
3321 " a = a|0;\n"
3322 " var c = 0, c = 1.0;\n"
3323 "}\n",
3324 "Redeclared local"},
3325 {"function f(b, a) {\n"
3326 " b = +b;\n"
3327 " a = a|0;\n"
3328 " var c = 0; var c = 1.0;\n"
3329 "}\n",
3330 "Redeclared local"},
3331 {"function f(b, a) {\n"
3332 " b = +b;\n"
3333 " a = a|0;\n"
3334 " f();\n"
3335 " var c = 0;\n"
3336 "}\n",
3337 "Local variable missing initializer in asm.js module"},
3338 {"function f() {\n"
3339 " function ff() {}\n"
3340 "}\n",
3341 "Functions may only define inner variables"},
3342 {"function f() {\n"
3343 " return a+1;\n"
3344 "}\n",
3345 "Invalid return type annotation"},
3346 {"function f() {\n"
3347 " return ~~x;\n"
3348 "}\n",
3349 "Invalid return type annotation"},
3350 {"function f() {\n"
3351 " return d();\n"
3352 "}\n",
3353 "Invalid function call in return statement"},
3354 {"function f() {\n"
3355 " return 'use asm';\n"
3356 "}\n",
3357 "Invalid literal in return statement"},
3358 {"function f() {\n"
3359 " return 2147483648;\n"
3360 "}\n",
3361 "Invalid literal in return statement"},
3362 {"function f() {\n"
3363 " return stdlib.Math.E;"
3364 "}\n",
3365 "Invalid return type expression"},
3366 {"function f() {\n"
3367 " return E[0];"
3368 "}\n",
3369 "Invalid return type expression"},
3370 {"function I() {}\n", "Identifier redefined as function"},
3371 {"function foo() {}\n", "Identifier redefined as function"},
3372 {"function d2s() {}\n", "Identifier redefined (function name)"},
3373 {"function d2s(x) {\n"
3374 " x = x|0;\n"
3375 " return -1;\n"
3376 "}\n",
3377 "Identifier redefined (function name)"},
3378 {"function d2s(x) {\n"
3379 " x = +x;\n"
3380 " return -1.0;\n"
3381 "}\n",
3382 "Identifier redefined (function name)"},
3383 };
3384
3385 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3386 const auto* test = kTests + ii;
3387 if (!ValidationOf(Function(test->function))
3388 ->WithGlobal(Var("I"), iw::AsmType::Int())
3389 ->WithGlobal(Var("d2s"), d2s)
3390 ->FailsWithMessage(test->error_message)) {
3391 std::cerr << "Test:\n" << test->function;
3392 CHECK(false);
3393 }
3394 }
3395 }
3396
3397 TEST(ErrorsInStatement) {
3398 const struct {
3399 const char* statement;
3400 const char* error_message;
3401 } kTests[] = {
3402 {"if (fround(1));", "If condition must be type int"},
3403 {"return;", "Type mismatch in return statement"},
3404 {"return +1.0;", "Type mismatch in return statement"},
3405 {"return +d()", "Type mismatch in return statement"},
3406 {"while (fround(1));", "While condition must be type int"},
3407 {"do {} while (fround(1));", "Do {} While condition must be type int"},
3408 {"for (;fround(1););", "For condition must be type int"},
3409 {"switch(flocal){ case 0: return 0; }", "Switch tag must be signed"},
3410 {"switch(slocal){ case 1: case 1: return 0; }", "Duplicated case label"},
3411 {"switch(slocal){ case 1: case 0: break; case 1: return 0; }",
3412 "Duplicated case label"},
3413 {"switch(slocal){ case 1.0: return 0; }",
3414 "Case label must be a 32-bit signed integer"},
3415 {"switch(slocal){ case 1.0: return 0; }",
3416 "Case label must be a 32-bit signed integer"},
3417 {"switch(slocal){ case -100000: case 2147483647: return 0; }",
3418 "Out-of-bounds case"},
3419 {"switch(slocal){ case 2147483648: return 0; }",
3420 "Case label must be a 32-bit signed"},
3421 };
3422
3423 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3424 const auto* test = kTests + ii;
3425 if (!ValidationOf(Statement(test->statement))
3426 ->WithReturnType(iw::AsmType::Signed())
3427 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround)
3428 ->WithLocal(DynamicGlobal("flocal"), iw::AsmType::Float())
3429 ->WithLocal(DynamicGlobal("slocal"), iw::AsmType::Signed())
3430 ->FailsWithMessage(test->error_message)) {
3431 std::cerr << "Test:\n" << test->statement;
3432 CHECK(false);
3433 }
3434 }
3435 }
3436
3437 TEST(ErrorsInExpression) {
3438 auto d2d = [](Zone* zone) -> iw::AsmType* {
3439 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Double());
3440 ret->AsFunctionType()->AddArgument(iw::AsmType::Double());
3441 return ret;
3442 };
3443
3444 auto d2s_tbl = [](Zone* zone) -> iw::AsmType* {
3445 auto* d2s = iw::AsmType::Function(zone, iw::AsmType::Signed());
3446 d2s->AsFunctionType()->AddArgument(iw::AsmType::Double());
3447
3448 auto* ret = iw::AsmType::FunctionTableType(zone, 2, d2s);
3449 return ret;
3450 };
3451
3452 const struct {
3453 const char* expression;
3454 const char* error_message;
3455 } kTests[] = {
3456 {"noy_a_function();", "Unanotated call to a function must be a call to"},
3457 {"a = 0;", "Undeclared identifier"},
3458 {"ilocal = +1.0", "Type mismatch in assignment"},
3459 {"!dlocal", "Invalid type for !"},
3460 {"2 * dlocal", "Invalid types for intish *"},
3461 {"dlocal * 2", "Invalid types for intish *"},
3462 {"1048577 * ilocal", "Invalid operands for *"},
3463 {"1048577 / ilocal", "Invalid operands for /"},
3464 {"1048577 % dlocal", "Invalid operands for %"},
3465 {"1048577 * dlocal", "Invalid operands for *"},
3466 {"1048577 / dlocal", "Invalid operands for /"},
3467 {"1048577 % ilocal", "Invalid operands for %"},
3468 {"ilocal * dlocal", "Invalid operands for *"},
3469 {"ilocal / dlocal", "Invalid operands for /"},
3470 {"ilocal % dlocal", "Invalid operands for %"},
3471 {"1048577 + dlocal", "Invalid operands for additive expression"},
3472 {"1048577 - dlocal", "Invalid operands for additive expression"},
3473 {"ilocal + dlocal", "Invalid operands for additive expression"},
3474 {"ilocal - dlocal", "Invalid operands for additive expression"},
3475 {"1048577 << dlocal", "Invalid operands for <<"},
3476 {"1048577 >> dlocal", "Invalid operands for >>"},
3477 {"1048577 >>> dlocal", "Invalid operands for >>"},
3478 {"ilocal << dlocal", "Invalid operands for <<"},
3479 {"ilocal >> dlocal", "Invalid operands for >>"},
3480 {"ilocal >>> dlocal", "Invalid operands for >>>"},
3481 {"1048577 < dlocal", "Invalid operands for <"},
3482 {"ilocal < dlocal", "Invalid operands for <"},
3483 {"1048577 > dlocal", "Invalid operands for >"},
3484 {"ilocal > dlocal", "Invalid operands for >"},
3485 {"1048577 <= dlocal", "Invalid operands for <="},
3486 {"ilocal <= dlocal", "Invalid operands for <="},
3487 {"1048577 >= dlocal", "Invalid operands for >="},
3488 {"ilocal >= dlocal", "Invalid operands for >="},
3489 {"1048577 == dlocal", "Invalid operands for =="},
3490 {"ilocal == dlocal", "Invalid operands for =="},
3491 /* NOTE: the parser converts a == b to !(a == b). */
3492 {"1048577 != dlocal", "Invalid operands for =="},
3493 {"ilocal != dlocal", "Invalid operands for =="},
3494 {"dlocal & dlocal", "Invalid operands for &"},
3495 {"1048577 & dlocal", "Invalid operands for &"},
3496 {"ilocal & dlocal", "Invalid operands for &"},
3497 {"dlocal | dlocal2", "Invalid operands for |"},
3498 {"1048577 | dlocal", "Invalid operands for |"},
3499 {"ilocal | dlocal", "Invalid operands for |"},
3500 {"dlocal ^ dlocal2", "Invalid operands for ^"},
3501 {"1048577 ^ dlocal", "Invalid operands for ^"},
3502 {"ilocal ^ dlocal", "Invalid operands for ^"},
3503 {"dlocal ? 0 : 1", "Ternary operation condition should be int"},
3504 {"ilocal ? dlocal : 1", "Type mismatch for ternary operation result"},
3505 {"ilocal ? 1 : dlocal", "Type mismatch for ternary operation result"},
3506 {"eval(10)|0", "Invalid asm.js identifier in (forward) function"},
3507 {"arguments(10)|0", "Invalid asm.js identifier in (forward) function"},
3508 {"not_a_function(10)|0", "Calling something that's not a function"},
3509 {"fround(FFI())", "Foreign functions can't return float"},
3510 {"FFI(fround(0))|0", "Function invocation does not match function type"},
3511 {"FFI(2147483648)|0", "Function invocation does not match function type"},
3512 {"d2d(2.0)|0", "Function invocation does not match function type"},
3513 {"+d2d(2)", "Function invocation does not match function type"},
3514 {"eval[ilocal & 3]()|0", "Invalid asm.js identifier in (forward)"},
3515 {"arguments[ilocal & 3]()|0", "Invalid asm.js identifier in (forward)"},
3516 {"not_a_function[ilocal & 3]()|0", "Identifier does not name a function"},
3517 {"d2s_tbl[ilocal & 3](0.0)|0", "Function table size does not match"},
3518 {"+d2s_tbl[ilocal & 1](0.0)", "does not match previous signature"},
3519 {"d2s_tbl[ilocal & 1](0)|0", "does not match previous signature"},
3520 {"a.b()|0", "Indirect call index must be in the expr & mask form"},
3521 {"HEAP32[0][0] = 0", "Invalid heap access"},
3522 {"heap32[0] = 0", "Undeclared identifier in heap access"},
3523 {"not_a_function[0] = 0", "Identifier does not represent a heap view"},
3524 {"HEAP32[0.0] = 0", "Heap access index must be intish"},
3525 {"HEAP32[-1] = 0", "Heap access index must be a 32-bit unsigned integer"},
3526 {"HEAP32[ilocal >> 1] = 0", "Invalid heap access index"},
3527 // *VIOLATION* the following is invalid, but because of desugaring it is
3528 // accepted.
3529 // {"HEAP32[0 >> 1] = 0", "Invalid heap access index"},
3530 {"HEAP8[fround(0.0)] = 0", "Invalid heap access index for byte array"},
3531 };
3532
3533 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3534 const auto* test = kTests + ii;
3535 if (!ValidationOf(Expression(test->expression))
3536 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int())
3537 ->WithLocal(DynamicGlobal("dlocal"), iw::AsmType::Double())
3538 ->WithLocal(DynamicGlobal("dlocal2"), iw::AsmType::Double())
3539 ->WithLocal(DynamicGlobal("not_a_function"), iw::AsmType::Int())
3540 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround)
3541 ->WithImport(DynamicGlobal("FFI"), iw::AsmTyper::kFFI)
3542 ->WithGlobal(DynamicGlobal("d2d"), d2d)
3543 ->WithGlobal(DynamicGlobal("d2s_tbl"), d2s_tbl)
3544 ->WithGlobal(DynamicGlobal("HEAP32"), iw::AsmType::Int32Array())
3545 ->WithGlobal(DynamicGlobal("HEAP8"), iw::AsmType::Int8Array())
3546 ->FailsWithMessage(test->error_message)) {
3547 std::cerr << "Test:\n" << test->expression;
3548 CHECK(false);
3549 }
3550 }
3551 }
3552
3553 TEST(ValidateNumericLiteral) {
3554 const struct {
3555 const char* expression;
3556 iw::AsmType* expected_type;
3557 } kTests[] = {
3558 {"0", iw::AsmType::FixNum()},
3559 {"-1", iw::AsmType::Signed()},
3560 {"2147483648", iw::AsmType::Unsigned()},
3561 {"0.0", iw::AsmType::Double()},
3562 };
3563
3564 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3565 const auto* test = kTests + ii;
3566 if (!ValidationOf(Expression(test->expression))
3567 ->SucceedsWithExactType(test->expected_type)) {
3568 std::cerr << "Test:\n" << test->expression;
3569 CHECK(false);
3570 }
3571 }
3572 }
3573
3574 TEST(ValidateIdentifier) {
3575 const struct {
3576 const char* expression;
3577 iw::AsmType* expected_type;
3578 } kTests[] = {{"afixnum", iw::AsmType::FixNum()},
3579 {"adouble", iw::AsmType::Double()},
3580 {"afloat", iw::AsmType::Float()},
3581 {"anextern", iw::AsmType::Extern()},
3582 {"avoid", iw::AsmType::Void()}};
3583
3584 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3585 const auto* test = kTests + ii;
3586 if (!ValidationOf(Expression(test->expression))
3587 ->WithLocal(DynamicGlobal(test->expression), test->expected_type)
3588 ->WithGlobal(DynamicGlobal(test->expression),
3589 iw::AsmType::Floatish())
3590 ->SucceedsWithExactType(test->expected_type)) {
3591 std::cerr << "Test (local identifiers):\n" << test->expression;
3592 CHECK(false);
3593 }
3594 }
3595
3596 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3597 const auto* test = kTests + ii;
3598 if (!ValidationOf(Expression(test->expression))
3599 ->WithGlobal(DynamicGlobal(test->expression), test->expected_type)
3600 ->SucceedsWithExactType(test->expected_type)) {
3601 std::cerr << "Test (global identifiers):\n" << test->expression;
3602 CHECK(false);
3603 }
3604 }
3605 }
3606
3607 TEST(ValidateCallExpression) {
3608 auto v2f = [](Zone* zone) -> iw::AsmType* {
3609 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Float());
3610 return ret;
3611 };
3612
3613 const struct {
3614 const char* expression;
3615 } kTests[] = {
3616 {"a_float_function()"},
3617 {"fround(0)"},
3618 {"slocal"},
3619 {"ulocal"},
3620 {"dqlocal"},
3621 {"fishlocal"},
3622 };
3623
3624 char full_test[200];
3625 static const size_t kFullTestSize = arraysize(full_test);
3626 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3627 const auto* test = kTests + ii;
3628 CHECK(v8::base::OS::SNPrintF(full_test, kFullTestSize, "fround(%s)",
3629 test->expression) < kFullTestSize);
3630 if (!ValidationOf(Expression(full_test))
3631 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround)
3632 ->WithGlobal(DynamicGlobal("a_float_function"), v2f)
3633 ->WithLocal(DynamicGlobal("slocal"), iw::AsmType::Signed())
3634 ->WithLocal(DynamicGlobal("ulocal"), iw::AsmType::Unsigned())
3635 ->WithLocal(DynamicGlobal("dqlocal"), iw::AsmType::DoubleQ())
3636 ->WithLocal(DynamicGlobal("fishlocal"), iw::AsmType::Floatish())
3637 ->SucceedsWithExactType(iw::AsmType::Float())) {
3638 std::cerr << "Test:\n" << full_test;
3639 CHECK(false);
3640 }
3641 }
3642
3643 const struct {
3644 const char* expression;
3645 const char* error_message;
3646 } kFailureTests[] = {
3647 {"vlocal", "Invalid argument type to fround"},
3648 {"ilocal", "Invalid argument type to fround"},
3649 {"a_double_function()", "Function invocation does not match"},
3650 };
3651
3652 auto v2d = [](Zone* zone) -> iw::AsmType* {
3653 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Double());
3654 return ret;
3655 };
3656
3657 for (size_t ii = 0; ii < arraysize(kFailureTests); ++ii) {
3658 const auto* test = kFailureTests + ii;
3659 CHECK(v8::base::OS::SNPrintF(full_test, kFullTestSize, "fround(%s)",
3660 test->expression) < kFullTestSize);
3661 if (!ValidationOf(Expression(full_test))
3662 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround)
3663 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int())
3664 ->WithLocal(DynamicGlobal("vlocal"), iw::AsmType::Void())
3665 ->WithGlobal(DynamicGlobal("a_double_function"), v2d)
3666 ->FailsWithMessage(test->error_message)) {
3667 std::cerr << "Test:\n" << full_test;
3668 CHECK(false);
3669 }
3670 }
3671 }
3672
3673 TEST(ValidateMemberExpression) {
3674 const struct {
3675 const char* expression;
3676 iw::AsmType* load_type;
3677 } kTests[] = {
3678 {"I8[iish]", iw::AsmType::Intish()}, // leniency.
bradn 2016/07/11 17:55:33 Not clear what you mean?
John 2016/07/12 21:13:15 Done.
3679 {"I8[iish >> 0]", iw::AsmType::Intish()},
3680 {"I8[0]", iw::AsmType::Intish()},
3681 {"I8[2147483648]", iw::AsmType::Intish()},
3682 {"U8[iish >> 0]", iw::AsmType::Intish()},
3683 {"U8[0]", iw::AsmType::Intish()},
3684 {"U8[2147483648]", iw::AsmType::Intish()},
3685 {"I16[iish >> 1]", iw::AsmType::Intish()},
3686 {"I16[0]", iw::AsmType::Intish()},
3687 {"I16[2147483648]", iw::AsmType::Intish()}, // bug: must be "shifted."
bradn 2016/07/11 17:55:33 ??
John 2016/07/12 21:13:15 Done.
3688 {"U16[iish >> 1]", iw::AsmType::Intish()},
3689 {"U16[0]", iw::AsmType::Intish()},
3690 {"U16[2147483648]", iw::AsmType::Intish()}, // bug: must be "shifted."
3691 {"I32[iish >> 2]", iw::AsmType::Intish()},
3692 {"I32[0]", iw::AsmType::Intish()},
3693 {"I32[2147483648]", iw::AsmType::Intish()}, // bug: must be "shifted."
3694 {"U32[iish >> 2]", iw::AsmType::Intish()},
3695 {"U32[0]", iw::AsmType::Intish()},
3696 {"U32[2147483648]", iw::AsmType::Intish()}, // bug: must be "shifted."
3697 {"F32[iish >> 2]", iw::AsmType::FloatQ()},
3698 {"F32[0]", iw::AsmType::FloatQ()},
3699 {"F32[2147483648]", iw::AsmType::FloatQ()}, // bug: must be "shifted."
3700 {"F64[iish >> 3]", iw::AsmType::DoubleQ()},
3701 {"F64[0]", iw::AsmType::DoubleQ()},
3702 {"F64[2147483648]", iw::AsmType::DoubleQ()}, // bug: must be "shifted."
3703 };
3704
3705 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3706 const auto* test = kTests + ii;
3707 if (!ValidationOf(Expression(test->expression))
3708 ->WithGlobal(DynamicGlobal("I8"), iw::AsmType::Int8Array())
3709 ->WithGlobal(DynamicGlobal("U8"), iw::AsmType::Uint8Array())
3710 ->WithGlobal(DynamicGlobal("I16"), iw::AsmType::Int16Array())
3711 ->WithGlobal(DynamicGlobal("U16"), iw::AsmType::Uint16Array())
3712 ->WithGlobal(DynamicGlobal("I32"), iw::AsmType::Int32Array())
3713 ->WithGlobal(DynamicGlobal("U32"), iw::AsmType::Uint32Array())
3714 ->WithGlobal(DynamicGlobal("F32"), iw::AsmType::Float32Array())
3715 ->WithGlobal(DynamicGlobal("F64"), iw::AsmType::Float64Array())
3716 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish())
3717 ->SucceedsWithExactType(test->load_type)) {
3718 std::cerr << "Test:\n" << test->expression;
3719 CHECK(false);
3720 }
3721 }
3722 }
3723
3724 TEST(ValidateAssignmentExpression) {
3725 const struct {
3726 const char* expression;
3727 iw::AsmType* load_type;
3728 } kTests[] = {
3729 // -----------------------------------------------------------------------
3730 // Array assignments.
3731 // Storing signed to int heap view.
3732 {"I8[1024] = -1024", iw::AsmType::Signed()}, // leniency.
3733 {"I8[1024 >> 0] = -1024", iw::AsmType::Signed()},
3734 {"I8[0] = -1024", iw::AsmType::Signed()},
3735 {"I8[2147483648] = -1024", iw::AsmType::Signed()},
3736 {"U8[1024 >> 0] = -1024", iw::AsmType::Signed()},
3737 {"U8[0] = -1024", iw::AsmType::Signed()},
3738 {"U8[2147483648] = -1024", iw::AsmType::Signed()},
3739 {"I16[1024 >> 1] = -1024", iw::AsmType::Signed()},
3740 {"I16[0] = -1024", iw::AsmType::Signed()},
3741 {"I16[2147483648] = -1024", iw::AsmType::Signed()}, // bug: !"shifted."
3742 {"U16[1024 >> 1] = -1024", iw::AsmType::Signed()},
3743 {"U16[0] = -1024", iw::AsmType::Signed()},
3744 {"U16[2147483648] = -1024", iw::AsmType::Signed()}, // bug: !"shifted."
3745 {"I32[1024 >> 2] = -1024", iw::AsmType::Signed()},
3746 {"I32[0] = -1024", iw::AsmType::Signed()},
3747 {"I32[2147483648] = -1024", iw::AsmType::Signed()}, // bug: !"shifted."
3748 {"U32[1024 >> 2] = -1024", iw::AsmType::Signed()},
3749 {"U32[0] = -1024", iw::AsmType::Signed()},
3750 {"U32[2147483648] = -1024", iw::AsmType::Signed()}, // bug: !"shifted."
3751 // Sroting fixnum to int heap view.
3752 {"I8[1024] = 1024", iw::AsmType::FixNum()}, // leniency.
3753 {"I8[1024 >> 0] = 1024", iw::AsmType::FixNum()},
3754 {"I8[0] = 1024", iw::AsmType::FixNum()},
3755 {"I8[2147483648] = 1024", iw::AsmType::FixNum()},
3756 {"U8[1024 >> 0] = 1024", iw::AsmType::FixNum()},
3757 {"U8[0] = 1024", iw::AsmType::FixNum()},
3758 {"U8[2147483648] = 1024", iw::AsmType::FixNum()},
3759 {"I16[1024 >> 1] = 1024", iw::AsmType::FixNum()},
3760 {"I16[0] = 1024", iw::AsmType::FixNum()},
3761 {"I16[2147483648] = 1024", iw::AsmType::FixNum()}, // bug: not "shifted."
3762 {"U16[1024 >> 1] = 1024", iw::AsmType::FixNum()},
3763 {"U16[0] = 1024", iw::AsmType::FixNum()},
3764 {"U16[2147483648] = 1024", iw::AsmType::FixNum()}, // bug: not "shifted."
3765 {"I32[1024 >> 2] = 1024", iw::AsmType::FixNum()},
3766 {"I32[0] = 1024", iw::AsmType::FixNum()},
3767 {"I32[2147483648] = 1024", iw::AsmType::FixNum()}, // bug: not "shifted."
3768 {"U32[1024 >> 2] = 1024", iw::AsmType::FixNum()},
3769 {"U32[0] = 1024", iw::AsmType::FixNum()},
3770 {"U32[2147483648] = 1024", iw::AsmType::FixNum()}, // bug: not "shifted."
3771 // Storing int to int heap view.
3772 {"I8[ilocal] = ilocal", iw::AsmType::Int()}, // leniency.
3773 {"I8[ilocal >> 0] = ilocal", iw::AsmType::Int()},
3774 {"I8[0] = ilocal", iw::AsmType::Int()},
3775 {"I8[2147483648] = ilocal", iw::AsmType::Int()},
3776 {"U8[ilocal >> 0] = ilocal", iw::AsmType::Int()},
3777 {"U8[0] = ilocal", iw::AsmType::Int()},
3778 {"U8[2147483648] = ilocal", iw::AsmType::Int()},
3779 {"I16[ilocal >> 1] = ilocal", iw::AsmType::Int()},
3780 {"I16[0] = ilocal", iw::AsmType::Int()},
3781 {"I16[2147483648] = ilocal", iw::AsmType::Int()}, // bug: not "shifted."
3782 {"U16[ilocal >> 1] = ilocal", iw::AsmType::Int()},
3783 {"U16[0] = ilocal", iw::AsmType::Int()},
3784 {"U16[2147483648] = ilocal", iw::AsmType::Int()}, // bug: not "shifted."
3785 {"I32[ilocal >> 2] = ilocal", iw::AsmType::Int()},
3786 {"I32[0] = ilocal", iw::AsmType::Int()},
3787 {"I32[2147483648] = ilocal", iw::AsmType::Int()}, // bug: not "shifted."
3788 {"U32[ilocal >> 2] = ilocal", iw::AsmType::Int()},
3789 {"U32[0] = ilocal", iw::AsmType::Int()},
3790 {"U32[2147483648] = ilocal", iw::AsmType::Int()}, // bug: not "shifted."
3791 // Storing intish to int heap view.
3792 {"I8[iish] = iish", iw::AsmType::Intish()}, // leniency.
3793 {"I8[iish >> 0] = iish", iw::AsmType::Intish()},
3794 {"I8[0] = iish", iw::AsmType::Intish()},
3795 {"I8[2147483648] = iish", iw::AsmType::Intish()},
3796 {"U8[iish >> 0] = iish", iw::AsmType::Intish()},
3797 {"U8[0] = iish", iw::AsmType::Intish()},
3798 {"U8[2147483648] = iish", iw::AsmType::Intish()},
3799 {"I16[iish >> 1] = iish", iw::AsmType::Intish()},
3800 {"I16[0] = iish", iw::AsmType::Intish()},
3801 {"I16[2147483648] = iish", iw::AsmType::Intish()}, // bug: not "shifted."
3802 {"U16[iish >> 1] = iish", iw::AsmType::Intish()},
3803 {"U16[0] = iish", iw::AsmType::Intish()},
3804 {"U16[2147483648] = iish", iw::AsmType::Intish()}, // bug: not "shifted."
3805 {"I32[iish >> 2] = iish", iw::AsmType::Intish()},
3806 {"I32[0] = iish", iw::AsmType::Intish()},
3807 {"I32[2147483648] = iish", iw::AsmType::Intish()}, // bug: not "shifted."
3808 {"U32[iish >> 2] = iish", iw::AsmType::Intish()},
3809 {"U32[0] = iish", iw::AsmType::Intish()},
3810 {"U32[2147483648] = iish", iw::AsmType::Intish()}, // bug: not "shifted."
3811 // Storing floatish to f32 heap view.
3812 {"F32[iish >> 2] = fish", iw::AsmType::Floatish()},
3813 {"F32[0] = fish", iw::AsmType::Floatish()},
3814 {"F32[2147483648] = fish ", iw::AsmType::Floatish()}, // bug: !"shifted."
3815 // Storing double? to f32 heap view.
3816 {"F32[iish >> 2] = dq", iw::AsmType::DoubleQ()},
3817 {"F32[0] = dq", iw::AsmType::DoubleQ()},
3818 {"F32[2147483648] = dq", iw::AsmType::DoubleQ()}, // bug: not "shifted."
3819 // Storing float? to f64 heap view.
3820 {"F64[iish >> 3] = fq", iw::AsmType::FloatQ()},
3821 {"F64[0] = fq", iw::AsmType::FloatQ()},
3822 {"F64[2147483648] = fq", iw::AsmType::FloatQ()}, // bug: not "shifted."
3823 // Storing double? to f64 heap view.
3824 {"F64[iish >> 3] = dq", iw::AsmType::DoubleQ()},
3825 {"F64[0] = dq", iw::AsmType::DoubleQ()},
3826 {"F64[2147483648] = dq", iw::AsmType::DoubleQ()}, // bug: not "shifted."
3827 // -----------------------------------------------------------------------
3828 // Scalar assignments.
3829 {"ilocal = 1024", iw::AsmType::FixNum()},
3830 {"ilocal = -1024", iw::AsmType::Signed()},
3831 {"ilocal = 2147483648", iw::AsmType::Unsigned()},
3832 {"ilocal = iglobal", iw::AsmType::Int()},
3833 {"iglobal = 1024", iw::AsmType::FixNum()},
3834 {"iglobal = -1024", iw::AsmType::Signed()},
3835 {"iglobal = 2147483648", iw::AsmType::Unsigned()},
3836 {"iglobal = ilocal", iw::AsmType::Int()},
3837 {"dlocal = 0.0", iw::AsmType::Double()},
3838 {"dlocal = +make_double()", iw::AsmType::Double()},
3839 {"dglobal = 0.0", iw::AsmType::Double()},
3840 {"dglobal = +make_double()", iw::AsmType::Double()},
3841 {"flocal = fround(0)", iw::AsmType::Float()},
3842 {"flocal = fround(make_float())", iw::AsmType::Float()},
3843 {"fglobal = fround(0)", iw::AsmType::Float()},
3844 {"fglobal = fround(make_float())", iw::AsmType::Float()},
3845 };
3846
3847 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3848 const auto* test = kTests + ii;
3849 if (!ValidationOf(Expression(test->expression))
3850 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround)
3851 ->WithLocal(DynamicGlobal("fq"), iw::AsmType::FloatQ())
3852 ->WithLocal(DynamicGlobal("dq"), iw::AsmType::DoubleQ())
3853 ->WithLocal(DynamicGlobal("fish"), iw::AsmType::Floatish())
3854 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish())
3855 ->WithGlobal(DynamicGlobal("iglobal"), iw::AsmType::Int())
3856 ->WithGlobal(DynamicGlobal("dglobal"), iw::AsmType::Double())
3857 ->WithGlobal(DynamicGlobal("fglobal"), iw::AsmType::Float())
3858 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int())
3859 ->WithLocal(DynamicGlobal("dlocal"), iw::AsmType::Double())
3860 ->WithLocal(DynamicGlobal("flocal"), iw::AsmType::Float())
3861 ->WithGlobal(DynamicGlobal("I8"), iw::AsmType::Int8Array())
3862 ->WithGlobal(DynamicGlobal("U8"), iw::AsmType::Uint8Array())
3863 ->WithGlobal(DynamicGlobal("I16"), iw::AsmType::Int16Array())
3864 ->WithGlobal(DynamicGlobal("U16"), iw::AsmType::Uint16Array())
3865 ->WithGlobal(DynamicGlobal("I32"), iw::AsmType::Int32Array())
3866 ->WithGlobal(DynamicGlobal("U32"), iw::AsmType::Uint32Array())
3867 ->WithGlobal(DynamicGlobal("F32"), iw::AsmType::Float32Array())
3868 ->WithGlobal(DynamicGlobal("F64"), iw::AsmType::Float64Array())
3869 ->SucceedsWithExactType(test->load_type)) {
3870 std::cerr << "Test:\n" << test->expression;
3871 CHECK(false);
3872 }
3873 }
3874 }
3875
3876 TEST(ValidateUnaryExpression) {
3877 auto v2d = [](Zone* zone) -> iw::AsmType* {
3878 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Double());
3879 return ret;
3880 };
3881
3882 const struct {
3883 const char* expression;
3884 iw::AsmType* load_type;
3885 } kTests[] = {
3886 {"-2147483648", iw::AsmType::Signed()},
3887 {"-1024", iw::AsmType::Signed()},
3888 {"-1", iw::AsmType::Signed()},
3889 {"-2147483648.0", iw::AsmType::Double()},
3890 {"+make_double()", iw::AsmType::Double()},
3891 {"+dbl()", iw::AsmType::Double()},
3892 {"make_double() * 1.0", iw::AsmType::Double()}, // Violation.
3893 {"~~fq", iw::AsmType::Signed()},
3894 {"~~dglobal", iw::AsmType::Signed()},
3895 {"+slocal", iw::AsmType::Double()},
3896 {"slocal * 1.0", iw::AsmType::Double()}, // Violation.
3897 {"+ulocal", iw::AsmType::Double()},
3898 {"ulocal * 1.0", iw::AsmType::Double()}, // Violation.
3899 {"+dq", iw::AsmType::Double()},
3900 {"dq * 1.0", iw::AsmType::Double()}, // Violation.
3901 {"+fq", iw::AsmType::Double()},
3902 {"fq * 1.0", iw::AsmType::Double()}, // Violation.
3903 {"-ilocal", iw::AsmType::Intish()},
3904 {"ilocal * -1", iw::AsmType::Intish()}, // Violation.
3905 {"-dq", iw::AsmType::Double()},
3906 {"dq * -1", iw::AsmType::Double()}, // Violation.
3907 {"-fq", iw::AsmType::Floatish()},
3908 {"fq * -1", iw::AsmType::Floatish()}, // Violation.
3909 {"~iish", iw::AsmType::Signed()},
3910 {"iish ^ -1", iw::AsmType::Signed()}, // Violation, but OK.
3911 {"!ilocal", iw::AsmType::Int()},
3912 };
3913
3914 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3915 const auto* test = kTests + ii;
3916 if (!ValidationOf(Expression(test->expression))
3917 ->WithLocal(DynamicGlobal("fq"), iw::AsmType::FloatQ())
3918 ->WithLocal(DynamicGlobal("dq"), iw::AsmType::DoubleQ())
3919 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish())
3920 ->WithLocal(DynamicGlobal("slocal"), iw::AsmType::Signed())
3921 ->WithLocal(DynamicGlobal("ulocal"), iw::AsmType::Unsigned())
3922 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int())
3923 ->WithGlobal(DynamicGlobal("dglobal"), iw::AsmType::Double())
3924 ->WithGlobal(DynamicGlobal("dbl"), v2d)
3925 ->SucceedsWithExactType(test->load_type)) {
3926 std::cerr << "Test:\n" << test->expression;
3927 CHECK(false);
3928 }
3929 }
3930 }
3931
3932 TEST(ValidateMultiplicativeExpression) {
3933 const struct {
3934 const char* expression;
3935 iw::AsmType* load_type;
3936 } kTests[] = {
3937 {"dq * dq", iw::AsmType::Double()},
3938 {"fq * fq", iw::AsmType::Floatish()},
3939 {"slocal / slocal", iw::AsmType::Intish()},
3940 {"ulocal / ulocal", iw::AsmType::Intish()},
3941 {"dq / dq", iw::AsmType::Double()},
3942 {"fq / fq", iw::AsmType::Floatish()},
3943 {"slocal % slocal", iw::AsmType::Intish()},
3944 {"ulocal % ulocal", iw::AsmType::Intish()},
3945 {"dq % dq", iw::AsmType::Double()},
3946 {"-1048575 * ilocal", iw::AsmType::Intish()},
3947 {"ilocal * -1048575", iw::AsmType::Intish()},
3948 {"1048575 * ilocal", iw::AsmType::Intish()},
3949 {"ilocal * 1048575", iw::AsmType::Intish()},
3950 };
3951
3952 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3953 const auto* test = kTests + ii;
3954 if (!ValidationOf(Expression(test->expression))
3955 ->WithLocal(DynamicGlobal("fq"), iw::AsmType::FloatQ())
3956 ->WithLocal(DynamicGlobal("dq"), iw::AsmType::DoubleQ())
3957 ->WithLocal(DynamicGlobal("slocal"), iw::AsmType::Signed())
3958 ->WithLocal(DynamicGlobal("ulocal"), iw::AsmType::Unsigned())
3959 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int())
3960 ->WithGlobal(DynamicGlobal("dglobal"), iw::AsmType::Double())
3961 ->SucceedsWithExactType(test->load_type)) {
3962 std::cerr << "Test:\n" << test->expression;
3963 CHECK(false);
3964 }
3965 }
3966 }
3967
3968 TEST(ValidateAdditiveExpression) {
3969 const struct {
3970 const char* expression;
3971 iw::AsmType* load_type;
3972 } kTests[] = {
3973 {"dlocal + dlocal", iw::AsmType::Double()},
3974 {"fq + fq", iw::AsmType::Floatish()},
3975 {"dq - dq", iw::AsmType::Double()},
3976 {"fq - fq", iw::AsmType::Floatish()},
3977 {"ilocal + 1", iw::AsmType::Intish()},
3978 {"ilocal - 1", iw::AsmType::Intish()},
3979 {"slocal + ilocal + 1", iw::AsmType::Intish()},
3980 {"slocal - ilocal + 1", iw::AsmType::Intish()},
3981 {"ulocal + ilocal + 1", iw::AsmType::Intish()},
3982 {"ulocal - ilocal + 1", iw::AsmType::Intish()},
3983 {"ulocal + slocal + ilocal + 1", iw::AsmType::Intish()},
3984 {"ulocal + slocal - ilocal + 1", iw::AsmType::Intish()},
3985 {"ulocal - slocal + ilocal + 1", iw::AsmType::Intish()},
3986 {"ulocal - slocal - ilocal + 1", iw::AsmType::Intish()},
3987 {"1 + 1", iw::AsmType::FixNum()}, // Violation: intish.
3988 };
3989
3990 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
3991 const auto* test = kTests + ii;
3992 if (!ValidationOf(Expression(test->expression))
3993 ->WithLocal(DynamicGlobal("fq"), iw::AsmType::FloatQ())
3994 ->WithLocal(DynamicGlobal("dq"), iw::AsmType::DoubleQ())
3995 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish())
3996 ->WithLocal(DynamicGlobal("dlocal"), iw::AsmType::Double())
3997 ->WithLocal(DynamicGlobal("slocal"), iw::AsmType::Signed())
3998 ->WithLocal(DynamicGlobal("ulocal"), iw::AsmType::Unsigned())
3999 ->WithLocal(DynamicGlobal("ilocal"), iw::AsmType::Int())
4000 ->SucceedsWithExactType(test->load_type)) {
4001 std::cerr << "Test:\n" << test->expression;
4002 CHECK(false);
4003 }
4004 }
4005 }
4006
4007 TEST(ValidateShiftExpression) {
4008 const struct {
4009 const char* expression;
4010 iw::AsmType* load_type;
4011 } kTests[] = {
4012 {"iish << iish", iw::AsmType::Signed()},
4013 {"iish >> iish", iw::AsmType::Signed()},
4014 {"iish >>> iish", iw::AsmType::Unsigned()},
4015 {"1 << 0", iw::AsmType::FixNum()}, // Violation: signed.
4016 {"1 >> 0", iw::AsmType::FixNum()}, // Violation: signed.
4017 {"4294967295 >>> 0", iw::AsmType::Unsigned()},
4018 {"-1 >>> 0", iw::AsmType::Unsigned()},
4019 {"2147483647 >>> 0", iw::AsmType::FixNum()}, // Violation: unsigned.
4020 };
4021
4022 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
4023 const auto* test = kTests + ii;
4024 if (!ValidationOf(Expression(test->expression))
4025 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish())
4026 ->SucceedsWithExactType(test->load_type)) {
4027 std::cerr << "Test:\n" << test->expression;
4028 CHECK(false);
4029 }
4030 }
4031 }
4032
4033 TEST(ValidateComparisonExpression) {
4034 const struct {
4035 const char* expression;
4036 iw::AsmType* load_type;
4037 } kTests[] = {
4038 // -----------------------------------------------------------------------
4039 // Non const <op> Non const
4040 {"s0 == s1", iw::AsmType::Int()},
4041 {"u0 == u1", iw::AsmType::Int()},
4042 {"f0 == f1", iw::AsmType::Int()},
4043 {"d0 == d1", iw::AsmType::Int()},
4044 {"s0 != s1", iw::AsmType::Int()},
4045 {"u0 != u1", iw::AsmType::Int()},
4046 {"f0 != f1", iw::AsmType::Int()},
4047 {"d0 != d1", iw::AsmType::Int()},
4048 {"s0 < s1", iw::AsmType::Int()},
4049 {"u0 < u1", iw::AsmType::Int()},
4050 {"f0 < f1", iw::AsmType::Int()},
4051 {"d0 < d1", iw::AsmType::Int()},
4052 {"s0 <= s1", iw::AsmType::Int()},
4053 {"u0 <= u1", iw::AsmType::Int()},
4054 {"f0 <= f1", iw::AsmType::Int()},
4055 {"d0 <= d1", iw::AsmType::Int()},
4056 {"s0 > s1", iw::AsmType::Int()},
4057 {"u0 > u1", iw::AsmType::Int()},
4058 {"f0 > f1", iw::AsmType::Int()},
4059 {"d0 > d1", iw::AsmType::Int()},
4060 {"s0 >= s1", iw::AsmType::Int()},
4061 {"u0 >= u1", iw::AsmType::Int()},
4062 {"f0 >= f1", iw::AsmType::Int()},
4063 {"d0 >= d1", iw::AsmType::Int()},
4064 // -----------------------------------------------------------------------
4065 // Non const <op> Const
4066 {"s0 == -1025", iw::AsmType::Int()},
4067 {"u0 == 123456789", iw::AsmType::Int()},
4068 {"f0 == fround(123456.78)", iw::AsmType::Int()},
4069 {"d0 == 9876543.201", iw::AsmType::Int()},
4070 {"s0 != -1025", iw::AsmType::Int()},
4071 {"u0 != 123456789", iw::AsmType::Int()},
4072 {"f0 != fround(123456.78)", iw::AsmType::Int()},
4073 {"d0 != 9876543.201", iw::AsmType::Int()},
4074 {"s0 < -1025", iw::AsmType::Int()},
4075 {"u0 < 123456789", iw::AsmType::Int()},
4076 {"f0 < fround(123456.78)", iw::AsmType::Int()},
4077 {"d0 < 9876543.201", iw::AsmType::Int()},
4078 {"s0 <= -1025", iw::AsmType::Int()},
4079 {"u0 <= 123456789", iw::AsmType::Int()},
4080 {"f0 <= fround(123456.78)", iw::AsmType::Int()},
4081 {"d0 <= 9876543.201", iw::AsmType::Int()},
4082 {"s0 > -1025", iw::AsmType::Int()},
4083 {"u0 > 123456789", iw::AsmType::Int()},
4084 {"f0 > fround(123456.78)", iw::AsmType::Int()},
4085 {"d0 > 9876543.201", iw::AsmType::Int()},
4086 {"s0 >= -1025", iw::AsmType::Int()},
4087 {"u0 >= 123456789", iw::AsmType::Int()},
4088 {"f0 >= fround(123456.78)", iw::AsmType::Int()},
4089 {"d0 >= 9876543.201", iw::AsmType::Int()},
4090 // -----------------------------------------------------------------------
4091 // Const <op> Non const
4092 {"-1025 == s0", iw::AsmType::Int()},
4093 {"123456789 == u0", iw::AsmType::Int()},
4094 {"fround(123456.78) == f0", iw::AsmType::Int()},
4095 {"9876543.201 == d0", iw::AsmType::Int()},
4096 {"-1025 != s0", iw::AsmType::Int()},
4097 {"123456789 != u0", iw::AsmType::Int()},
4098 {"fround(123456.78) != f0", iw::AsmType::Int()},
4099 {"9876543.201 != d0", iw::AsmType::Int()},
4100 {"-1025 < s0", iw::AsmType::Int()},
4101 {"123456789 < u0", iw::AsmType::Int()},
4102 {"fround(123456.78) < f0", iw::AsmType::Int()},
4103 {"9876543.201 < d0", iw::AsmType::Int()},
4104 {"-1025 <= s0", iw::AsmType::Int()},
4105 {"123456789 <= u0", iw::AsmType::Int()},
4106 {"fround(123456.78) <= f0", iw::AsmType::Int()},
4107 {"9876543.201 <= d0", iw::AsmType::Int()},
4108 {"-1025 > s0", iw::AsmType::Int()},
4109 {"123456789 > u0", iw::AsmType::Int()},
4110 {"fround(123456.78) > f0", iw::AsmType::Int()},
4111 {"9876543.201 > d0", iw::AsmType::Int()},
4112 {"-1025 >= s0", iw::AsmType::Int()},
4113 {"123456789 >= u0", iw::AsmType::Int()},
4114 {"fround(123456.78) >= f0", iw::AsmType::Int()},
4115 {"9876543.201 >= d0", iw::AsmType::Int()},
4116 // TODO(jpp): maybe add Const <op> Const.
4117 };
4118
4119 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
4120 const auto* test = kTests + ii;
4121 if (!ValidationOf(Expression(test->expression))
4122 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround)
4123 ->WithLocal(DynamicGlobal("u0"), iw::AsmType::Unsigned())
4124 ->WithLocal(DynamicGlobal("u1"), iw::AsmType::Unsigned())
4125 ->WithLocal(DynamicGlobal("s0"), iw::AsmType::Signed())
4126 ->WithLocal(DynamicGlobal("s1"), iw::AsmType::Signed())
4127 ->WithLocal(DynamicGlobal("f0"), iw::AsmType::Float())
4128 ->WithLocal(DynamicGlobal("f1"), iw::AsmType::Float())
4129 ->WithLocal(DynamicGlobal("d0"), iw::AsmType::Double())
4130 ->WithLocal(DynamicGlobal("d1"), iw::AsmType::Double())
4131 ->SucceedsWithExactType(test->load_type)) {
4132 std::cerr << "Test:\n" << test->expression;
4133 CHECK(false);
4134 }
4135 }
4136 }
4137
4138 TEST(ValidateBitwiseExpression) {
4139 auto v2s = [](Zone* zone) -> iw::AsmType* {
4140 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed());
4141 return ret;
4142 };
4143
4144 const struct {
4145 const char* expression;
4146 iw::AsmType* load_type;
4147 } kTests[] = {
4148 {"iish0 & iish1", iw::AsmType::Signed()},
4149 {"iish0 | iish1", iw::AsmType::Signed()},
4150 {"iish0 ^ iish1", iw::AsmType::Signed()},
4151 {"iish0 & -1", iw::AsmType::Signed()},
4152 {"iish0 | -1", iw::AsmType::Signed()},
4153 {"iish0 ^ -1", iw::AsmType::Signed()},
4154 {"2147483648 & iish1", iw::AsmType::Signed()},
4155 {"2147483648 | iish1", iw::AsmType::Signed()},
4156 {"2147483648 ^ iish1", iw::AsmType::Signed()},
4157 {"2147483648 & 0", iw::AsmType::FixNum()}, // Violation: signed.
4158 {"2147483648 | 0", iw::AsmType::Signed()},
4159 {"2147483648 ^ 0", iw::AsmType::Signed()},
4160 {"2134651 & 123", iw::AsmType::FixNum()}, // Violation: signed.
4161 {"2134651 | 123", iw::AsmType::FixNum()}, // Violation: signed.
4162 {"2134651 ^ 123", iw::AsmType::FixNum()}, // Violation: signed.
4163 {"make_signed()|0", iw::AsmType::Signed()},
4164 {"signed()|0", iw::AsmType::Signed()},
4165 };
4166
4167 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
4168 const auto* test = kTests + ii;
4169 if (!ValidationOf(Expression(test->expression))
4170 ->WithLocal(DynamicGlobal("iish1"), iw::AsmType::Intish())
4171 ->WithLocal(DynamicGlobal("iish0"), iw::AsmType::Intish())
4172 ->WithGlobal(DynamicGlobal("signed"), v2s)
4173 ->SucceedsWithExactType(test->load_type)) {
4174 std::cerr << "Test:\n" << test->expression;
4175 CHECK(false);
4176 }
4177 }
4178 }
4179
4180 TEST(ValidateConditionalExpression) {
4181 const struct {
4182 const char* expression;
4183 iw::AsmType* load_type;
4184 } kTests[] = {
4185 {"i0 ? i0 : i1", iw::AsmType::Int()},
4186 {"i0 ? f0 : f1", iw::AsmType::Float()},
4187 {"i0 ? d0 : d1", iw::AsmType::Double()},
4188 {"0 ? -1 : 2147483648", iw::AsmType::Int()},
4189 };
4190
4191 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
4192 const auto* test = kTests + ii;
4193 if (!ValidationOf(Expression(test->expression))
4194 ->WithLocal(DynamicGlobal("i0"), iw::AsmType::Int())
4195 ->WithLocal(DynamicGlobal("i1"), iw::AsmType::Int())
4196 ->WithLocal(DynamicGlobal("f0"), iw::AsmType::Float())
4197 ->WithLocal(DynamicGlobal("f1"), iw::AsmType::Float())
4198 ->WithLocal(DynamicGlobal("d0"), iw::AsmType::Double())
4199 ->WithLocal(DynamicGlobal("d1"), iw::AsmType::Double())
4200 ->SucceedsWithExactType(test->load_type)) {
4201 std::cerr << "Test:\n" << test->expression;
4202 CHECK(false);
4203 }
4204 }
4205 }
4206
4207 TEST(ValidateCall) {
4208 auto v2f = [](Zone* zone) -> iw::AsmType* {
4209 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Float());
4210 return ret;
4211 };
4212
4213 // ifd2_ is a helper function that returns a lambda for creating a function
4214 // type that accepts an int, a float, and a double. ret_type_factory is a
4215 // pointer to an AsmType*() function, and (*ret_type_factory)() returns the
4216 // desired return type. For example,
4217 //
4218 // ifd2_(&iw::AsmType::Float)
4219 //
4220 // returns an AsmType representing an asm.j function with the following
4221 // signature:
4222 //
4223 // float(int, float, double)
4224 auto ifd2_ = [](iw::AsmType* (
4225 *ret_type_factory)()) -> std::function<iw::AsmType*(Zone*)> {
4226 return [ret_type_factory](Zone* zone) -> iw::AsmType* {
4227 auto* ret = iw::AsmType::Function(zone, (*ret_type_factory)());
4228 ret->AsFunctionType()->AddArgument(iw::AsmType::Int());
4229 ret->AsFunctionType()->AddArgument(iw::AsmType::Float());
4230 ret->AsFunctionType()->AddArgument(iw::AsmType::Double());
4231 return ret;
4232 };
4233 };
4234 auto ifd2f = ifd2_(&iw::AsmType::Float);
4235 auto ifd2d = ifd2_(&iw::AsmType::Double);
4236 auto ifd2i = ifd2_(&iw::AsmType::Signed);
4237
4238 // Just like ifd2_, but this one returns a type representing a function table.
4239 auto tbl_ifd2_ = [](size_t tbl_size, iw::AsmType* (*ret_type_factory)())
4240 -> std::function<iw::AsmType*(Zone*)> {
4241 return [tbl_size, ret_type_factory](Zone* zone) -> iw::AsmType* {
4242 auto* signature = iw::AsmType::Function(zone, (*ret_type_factory)());
4243 signature->AsFunctionType()->AddArgument(iw::AsmType::Int());
4244 signature->AsFunctionType()->AddArgument(iw::AsmType::Float());
4245 signature->AsFunctionType()->AddArgument(iw::AsmType::Double());
4246
4247 auto* ret = iw::AsmType::FunctionTableType(zone, tbl_size, signature);
4248 return ret;
4249 };
4250 };
4251 auto ifd2f_tbl = tbl_ifd2_(32, &iw::AsmType::Float);
4252 auto ifd2d_tbl = tbl_ifd2_(64, &iw::AsmType::Double);
4253 auto ifd2i_tbl = tbl_ifd2_(4096, &iw::AsmType::Signed);
4254
4255 const struct {
4256 const char* expression;
4257 iw::AsmType* load_type;
4258 } kTests[] = {
4259 // -----------------------------------------------------------------------
4260 // Functions.
4261 {"fround(v2f())", iw::AsmType::Float()},
4262 {"fround(fish)", iw::AsmType::Float()},
4263 {"fround(dq)", iw::AsmType::Float()},
4264 {"fround(s)", iw::AsmType::Float()},
4265 {"fround(u)", iw::AsmType::Float()},
4266 {"ffi()|0", iw::AsmType::Signed()},
4267 {"ffi(1.0)|0", iw::AsmType::Signed()},
4268 {"ffi(1.0, 2.0)|0", iw::AsmType::Signed()},
4269 {"ffi(1.0, 2.0, 3)|0", iw::AsmType::Signed()},
4270 {"ffi(1.0, 2.0, 3, 4)|0", iw::AsmType::Signed()},
4271 {"+ffi()", iw::AsmType::Double()},
4272 {"+ffi(1.0)", iw::AsmType::Double()},
4273 {"+ffi(1.0, 2.0)", iw::AsmType::Double()},
4274 {"+ffi(1.0, 2.0, 3)", iw::AsmType::Double()},
4275 {"+ffi(1.0, 2.0, 3, 4)", iw::AsmType::Double()},
4276 {"fround(ifd2f(1, fround(1), 1.0))", iw::AsmType::Float()},
4277 {"+ifd2d(1, fround(1), 1.0)", iw::AsmType::Double()},
4278 {"ifd2i(1, fround(1), 1.0)|0", iw::AsmType::Signed()},
4279 // -----------------------------------------------------------------------
4280 // Function tables.
4281 {"fround(ifd2f_tbl[iish & 31](1, fround(1), 1.0))", iw::AsmType::Float()},
4282 {"+ifd2d_tbl[iish & 63](1, fround(1), 1.0)", iw::AsmType::Double()},
4283 {"ifd2i_tbl[iish & 4095](1, fround(1), 1.0)|0", iw::AsmType::Signed()},
4284 };
4285
4286 for (size_t ii = 0; ii < arraysize(kTests); ++ii) {
4287 const auto* test = kTests + ii;
4288 if (!ValidationOf(Expression(test->expression))
4289 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround)
4290 ->WithImport(DynamicGlobal("ffi"), iw::AsmTyper::kFFI)
4291 ->WithLocal(DynamicGlobal("fish"), iw::AsmType::Floatish())
4292 ->WithLocal(DynamicGlobal("dq"), iw::AsmType::DoubleQ())
4293 ->WithLocal(DynamicGlobal("s"), iw::AsmType::Signed())
4294 ->WithLocal(DynamicGlobal("u"), iw::AsmType::Unsigned())
4295 ->WithLocal(DynamicGlobal("iish"), iw::AsmType::Intish())
4296 ->WithGlobal(DynamicGlobal("v2f"), v2f)
4297 ->WithGlobal(DynamicGlobal("ifd2f_tbl"), ifd2f_tbl)
4298 ->WithGlobal(DynamicGlobal("ifd2d_tbl"), ifd2d_tbl)
4299 ->WithGlobal(DynamicGlobal("ifd2i_tbl"), ifd2i_tbl)
4300 ->SucceedsWithExactType(test->load_type)) {
4301 std::cerr << "Test:\n" << test->expression;
4302 CHECK(false);
4303 }
4304 }
4305 }
4306
4307 } // namespace
OLDNEW
« src/asmjs/asm-types.h ('K') | « src/v8.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698