OLD | NEW |
---|---|
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/ast/ast-expression-visitor.h" | |
13 #include "src/ast/ast-value-factory.h" | |
7 #include "src/ast/ast.h" | 14 #include "src/ast/ast.h" |
8 #include "src/ast/ast-expression-visitor.h" | |
9 #include "src/ast/scopes.h" | 15 #include "src/ast/scopes.h" |
10 #include "src/parsing/parser.h" | 16 #include "src/parsing/parser.h" |
11 #include "src/parsing/rewriter.h" | 17 #include "src/parsing/rewriter.h" |
12 #include "src/type-cache.h" | 18 #include "src/type-cache.h" |
13 #include "src/typing-asm.h" | 19 #include "src/typing-asm.h" |
20 #include "src/wasm/asm-typer.h" | |
21 #include "src/wasm/asm-types.h" | |
14 #include "test/cctest/cctest.h" | 22 #include "test/cctest/cctest.h" |
23 #include "test/cctest/expression-type-collector-macros.h" | |
15 #include "test/cctest/expression-type-collector.h" | 24 #include "test/cctest/expression-type-collector.h" |
16 #include "test/cctest/expression-type-collector-macros.h" | |
17 | 25 |
18 // Macros for function types. | 26 // Macros for function types. |
19 #define FUNC_FOREIGN_TYPE Bounds(Type::Function(Type::Any(), zone)) | 27 #define FUNC_FOREIGN_TYPE Bounds(Type::Function(Type::Any(), zone)) |
20 #define FUNC_V_TYPE Bounds(Type::Function(Type::Undefined(), zone)) | 28 #define FUNC_V_TYPE Bounds(Type::Function(Type::Undefined(), zone)) |
21 #define FUNC_I_TYPE Bounds(Type::Function(cache.kAsmSigned, zone)) | 29 #define FUNC_I_TYPE Bounds(Type::Function(cache.kAsmSigned, zone)) |
22 #define FUNC_F_TYPE Bounds(Type::Function(cache.kAsmFloat, zone)) | 30 #define FUNC_F_TYPE Bounds(Type::Function(cache.kAsmFloat, zone)) |
23 #define FUNC_D_TYPE Bounds(Type::Function(cache.kAsmDouble, zone)) | 31 #define FUNC_D_TYPE Bounds(Type::Function(cache.kAsmDouble, zone)) |
24 #define FUNC_D2D_TYPE \ | 32 #define FUNC_D2D_TYPE \ |
25 Bounds(Type::Function(cache.kAsmDouble, cache.kAsmDouble, zone)) | 33 Bounds(Type::Function(cache.kAsmDouble, cache.kAsmDouble, zone)) |
26 #define FUNC_N2F_TYPE \ | 34 #define FUNC_N2F_TYPE \ |
(...skipping 12 matching lines...) Expand all Loading... | |
39 #define FUNC_N2N_TYPE \ | 47 #define FUNC_N2N_TYPE \ |
40 Bounds(Type::Function(Type::Number(), Type::Number(), zone)) | 48 Bounds(Type::Function(Type::Number(), Type::Number(), zone)) |
41 | 49 |
42 // Macros for array types. | 50 // Macros for array types. |
43 #define FLOAT64_ARRAY_TYPE Bounds(Type::Array(cache.kAsmDouble, zone)) | 51 #define FLOAT64_ARRAY_TYPE Bounds(Type::Array(cache.kAsmDouble, zone)) |
44 #define FUNC_I2I_ARRAY_TYPE \ | 52 #define FUNC_I2I_ARRAY_TYPE \ |
45 Bounds(Type::Array(Type::Function(cache.kAsmSigned, cache.kAsmInt, zone), \ | 53 Bounds(Type::Array(Type::Function(cache.kAsmSigned, cache.kAsmInt, zone), \ |
46 zone)) | 54 zone)) |
47 | 55 |
48 using namespace v8::internal; | 56 using namespace v8::internal; |
57 namespace iw = i::wasm; | |
49 | 58 |
50 namespace { | 59 namespace { |
51 | 60 |
52 std::string Validate(Zone* zone, const char* source, | 61 std::string Validate(Zone* zone, const char* source, |
53 ZoneVector<ExpressionTypeEntry>* types) { | 62 ZoneVector<ExpressionTypeEntry>* types) { |
54 i::Isolate* isolate = CcTest::i_isolate(); | 63 i::Isolate* isolate = CcTest::i_isolate(); |
55 i::Factory* factory = isolate->factory(); | 64 i::Factory* factory = isolate->factory(); |
56 | 65 |
57 i::Handle<i::String> source_code = | 66 i::Handle<i::String> source_code = |
58 factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked(); | 67 factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked(); |
(...skipping 2447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2506 CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmDouble)) { | 2515 CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmDouble)) { |
2507 CHECK_VAR(x, Bounds(cache.kAsmDouble)); | 2516 CHECK_VAR(x, Bounds(cache.kAsmDouble)); |
2508 CHECK_EXPR(Literal, Bounds(cache.kAsmDouble)); | 2517 CHECK_EXPR(Literal, Bounds(cache.kAsmDouble)); |
2509 } | 2518 } |
2510 } | 2519 } |
2511 } | 2520 } |
2512 CHECK_SKIP(); | 2521 CHECK_SKIP(); |
2513 } | 2522 } |
2514 CHECK_FUNC_TYPES_END | 2523 CHECK_FUNC_TYPES_END |
2515 } | 2524 } |
2525 | |
bradnelson
2016/06/24 00:19:03
Maybe put this in test/wasm/test-asm-validator ?
T
John
2016/06/24 17:47:58
I left a TODO, for now. I'll move the file before
bradn
2016/06/24 18:57:03
Ok. Yeah better for review.
| |
2526 // ----------------------------------------------------------------------------- | |
2527 // asm.js typer v2. | |
2528 | |
2529 namespace v8 { | |
2530 namespace internal { | |
2531 namespace wasm { | |
2532 | |
2533 enum ValidationType { | |
2534 ValidateModule, | |
2535 ValidateGlobals, | |
2536 ValidateFunctionTables, | |
2537 ValidateExport, | |
2538 }; | |
2539 | |
2540 class AsmTyperHarnessBuilder { | |
2541 public: | |
2542 AsmTyperHarnessBuilder(const char* source, ValidationType type) | |
2543 : source_(source), | |
2544 validation_type_(type), | |
2545 handles_(), | |
2546 zone_(handles_.main_zone()), | |
2547 isolate_(CcTest::i_isolate()), | |
2548 ast_value_factory_(zone_, isolate_->heap()->HashSeed()), | |
2549 factory_(isolate_->factory()), | |
2550 source_code_( | |
2551 factory_->NewStringFromUtf8(CStrVector(source)).ToHandleChecked()), | |
2552 script_(factory_->NewScript(source_code_)) { | |
2553 ParseInfo info(zone_, script_); | |
2554 Parser parser(&info); | |
2555 info.set_global(); | |
2556 info.set_lazy(false); | |
2557 info.set_allow_lazy_parsing(false); | |
2558 info.set_toplevel(true); | |
2559 info.set_ast_value_factory(&ast_value_factory_); | |
2560 info.set_ast_value_factory_owned(false); | |
2561 | |
2562 if (!Compiler::ParseAndAnalyze(&info)) { | |
2563 std::cerr << "Failed to parse:\n" << source_ << "\n"; | |
2564 CHECK(false); | |
2565 } | |
2566 | |
2567 outer_scope_ = info.script_scope(); | |
2568 module_ = | |
2569 info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun(); | |
2570 typer_.reset(new AsmTyper(isolate_, zone_, *script_, module_)); | |
2571 } | |
2572 | |
2573 struct VariableName { | |
2574 VariableName(const char* name, VariableMode mode) | |
2575 : name_(name), mode_(mode) {} | |
2576 VariableName(const VariableName&) = default; | |
2577 VariableName& operator=(const VariableName&) = default; | |
2578 | |
2579 const char* name_; | |
2580 const VariableMode mode_; | |
2581 }; | |
2582 | |
2583 AsmTyperHarnessBuilder* WithLocal(VariableName, AsmType*) { return this; } | |
2584 | |
2585 AsmTyperHarnessBuilder* WithGlobal(VariableName var_name, AsmType* type) { | |
2586 auto* var = DeclareVariable(var_name); | |
2587 auto* var_info = new (zone_) AsmTyper::VariableInfo(type); | |
2588 var_info->set_mutability(AsmTyper::VariableInfo::kMutableGlobal); | |
2589 CHECK(typer_->AddGlobal(var, var_info)); | |
2590 return this; | |
2591 } | |
2592 | |
2593 AsmTyperHarnessBuilder* WithGlobal( | |
2594 VariableName var_name, std::function<AsmType*(Zone*)> type_creator) { | |
2595 return WithGlobal(var_name, type_creator(zone_)); | |
2596 } | |
2597 | |
2598 AsmTyperHarnessBuilder* WithUndefinedGlobal( | |
2599 VariableName var_name, std::function<AsmType*(Zone*)> type_creator) { | |
2600 auto* type = type_creator(zone_); | |
2601 CHECK(type->AsFunctionType() != nullptr || | |
2602 type->AsFunctionTableType() != nullptr); | |
2603 WithGlobal(var_name, type); | |
2604 auto* var_info = typer_->Lookup(DeclareVariable(var_name)); | |
2605 CHECK(var_info); | |
2606 var_info->FirstForwardUseIs(nullptr); | |
2607 return this; | |
2608 } | |
2609 | |
2610 AsmTyperHarnessBuilder* WithImport(VariableName var_name, | |
2611 AsmTyper::StandardMember standard_member) { | |
2612 auto* var = DeclareVariable(var_name); | |
2613 AsmTyper::VariableInfo* var_info = nullptr; | |
2614 auto* stdlib_map = &typer_->stdlib_math_types_; | |
2615 switch (standard_member) { | |
2616 case AsmTyper::kHeap: | |
2617 case AsmTyper::kStdlib: | |
2618 case AsmTyper::kModule: | |
2619 case AsmTyper::kNone: | |
2620 CHECK(false); | |
2621 case AsmTyper::kFFI: | |
2622 stdlib_map = nullptr; | |
2623 var_info = new (zone_) AsmTyper::VariableInfo(AsmType::FFIType(zone_)); | |
2624 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal); | |
2625 break; | |
2626 case AsmTyper::kInfinity: | |
2627 case AsmTyper::kNaN: | |
2628 stdlib_map = &typer_->stdlib_types_; | |
2629 default: | |
2630 break; | |
2631 } | |
2632 | |
2633 if (var_info == nullptr) { | |
2634 for (auto iter : *stdlib_map) { | |
2635 if (iter.second->standard_member() == standard_member) { | |
2636 var_info = iter.second; | |
2637 break; | |
2638 } | |
2639 } | |
2640 | |
2641 CHECK(var_info != nullptr); | |
2642 var_info = var_info->Clone(zone_); | |
2643 } | |
2644 | |
2645 CHECK(typer_->AddGlobal(var, var_info)); | |
2646 return this; | |
2647 } | |
2648 | |
2649 AsmTyperHarnessBuilder* WithStdlib(VariableName var_name) { | |
2650 auto* var = DeclareVariable(var_name); | |
2651 auto* var_info = new (zone_) AsmTyper::VariableInfo(); | |
2652 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal); | |
2653 var_info->set_standard_member(AsmTyper::kStdlib); | |
2654 CHECK(typer_->AddGlobal(var, var_info)); | |
2655 return this; | |
2656 } | |
2657 | |
2658 AsmTyperHarnessBuilder* WithHeap(VariableName var_name) { | |
2659 auto* var = DeclareVariable(var_name); | |
2660 auto* var_info = new (zone_) AsmTyper::VariableInfo(); | |
2661 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal); | |
2662 var_info->set_standard_member(AsmTyper::kHeap); | |
2663 CHECK(typer_->AddGlobal(var, var_info)); | |
2664 return this; | |
2665 } | |
2666 | |
2667 AsmTyperHarnessBuilder* WithFFI(VariableName var_name) { | |
2668 auto* var = DeclareVariable(var_name); | |
2669 auto* var_info = | |
2670 new (zone_) AsmTyper::VariableInfo(AsmType::FFIType(zone_)); | |
2671 var_info->set_mutability(AsmTyper::VariableInfo::kImmutableGlobal); | |
2672 var_info->set_standard_member(AsmTyper::kFFI); | |
2673 CHECK(typer_->AddGlobal(var, var_info)); | |
2674 return this; | |
2675 } | |
2676 | |
2677 bool Succeeds() { | |
2678 CHECK(validation_type_ == ValidateModule || | |
2679 validation_type_ == ValidateGlobals || | |
2680 validation_type_ == ValidateFunctionTables || | |
2681 validation_type_ == ValidateExport); | |
2682 if (typer_->Validate()) { | |
2683 return true; | |
2684 } | |
2685 | |
2686 std::cerr << "Asm validation failed: " << typer_->error_message() << "\n"; | |
2687 return false; | |
2688 } | |
2689 | |
2690 bool FailsWithMessage(const char* error_message) { | |
2691 CHECK(validation_type_ == ValidateModule || | |
2692 validation_type_ == ValidateGlobals || | |
2693 validation_type_ == ValidateFunctionTables || | |
2694 validation_type_ == ValidateExport); | |
2695 | |
2696 if (typer_->Validate()) { | |
2697 std::cerr << "Asm validation succeeded\n"; | |
2698 return false; | |
2699 } | |
2700 | |
2701 if (std::strstr(typer_->error_message(), error_message) == nullptr) { | |
2702 std::cerr << "Asm validation failed with the wrong error message:\n" | |
2703 "Expected to contain '" | |
2704 << error_message << "'\n" | |
2705 " Actually is '" | |
2706 << typer_->error_message() << "'\n"; | |
2707 return false; | |
2708 } | |
2709 | |
2710 return true; | |
2711 } | |
2712 | |
2713 private: | |
2714 Variable* DeclareVariable(VariableName var_name) { | |
2715 auto* name_ast_string = ast_value_factory_.GetOneByteString(var_name.name_); | |
2716 return var_name.mode_ == DYNAMIC_GLOBAL | |
2717 ? outer_scope_->DeclareDynamicGlobal(name_ast_string) | |
2718 : module_->scope()->DeclareLocal(name_ast_string, VAR, | |
2719 kCreatedInitialized, | |
2720 Variable::NORMAL); | |
2721 } | |
2722 | |
2723 std::string source_; | |
2724 ValidationType validation_type_; | |
2725 HandleAndZoneScope handles_; | |
2726 Zone* zone_; | |
2727 Isolate* isolate_; | |
2728 AstValueFactory ast_value_factory_; | |
2729 Factory* factory_; | |
2730 Handle<String> source_code_; | |
2731 Handle<Script> script_; | |
2732 | |
2733 Scope* outer_scope_; | |
2734 FunctionLiteral* module_; | |
2735 std::unique_ptr<AsmTyper> typer_; | |
2736 }; | |
2737 | |
2738 } // namespace wasm | |
2739 } // namespace internal | |
2740 } // namespace v8 | |
2741 | |
2742 namespace { | |
2743 | |
2744 struct ValidationInput { | |
2745 ValidationInput(const std::string& source, iw::ValidationType type) | |
2746 : source_(source), type_(type) {} | |
2747 | |
2748 const std::string source_; | |
2749 const iw::ValidationType type_; | |
2750 }; | |
2751 | |
2752 std::unique_ptr<iw::AsmTyperHarnessBuilder> ValidationOf( | |
2753 ValidationInput input) { | |
2754 return std::unique_ptr<iw::AsmTyperHarnessBuilder>( | |
2755 new iw::AsmTyperHarnessBuilder(input.source_.c_str(), input.type_)); | |
2756 } | |
2757 | |
2758 ValidationInput Module(const char* source) { | |
2759 return ValidationInput(source, iw::ValidateModule); | |
2760 } | |
2761 | |
2762 std::string WrapInFunction(const char* source, bool needs_use_asm) { | |
2763 if (needs_use_asm) { | |
2764 return std::string( | |
2765 "function foo() {\n" | |
2766 " 'use asm';\n" | |
2767 " ") + | |
2768 source + | |
2769 "\n" | |
2770 "}"; | |
2771 } | |
2772 | |
2773 return std::string( | |
2774 "function foo() {\n" | |
2775 " ") + | |
2776 source + | |
2777 "\n" | |
2778 "}"; | |
2779 } | |
2780 | |
2781 ValidationInput Globals(const char* source) { | |
2782 static const bool kNeedsUseAsm = true; | |
2783 return ValidationInput(WrapInFunction(source, kNeedsUseAsm), | |
2784 iw::ValidateGlobals); | |
2785 } | |
2786 | |
2787 ValidationInput FunctionTables(const char* source) { | |
2788 static const bool kNeedsUseAsm = true; | |
2789 return ValidationInput(WrapInFunction(source, kNeedsUseAsm), | |
2790 iw::ValidateFunctionTables); | |
2791 } | |
2792 | |
2793 ValidationInput Export(const char* source) { | |
2794 static const bool kNeedsUseAsm = true; | |
2795 return ValidationInput(WrapInFunction(source, kNeedsUseAsm), | |
2796 iw::ValidateExport); | |
2797 } | |
2798 | |
2799 iw::AsmTyperHarnessBuilder::VariableName Var(const char* name) { | |
2800 return iw::AsmTyperHarnessBuilder::VariableName(name, VAR); | |
2801 } | |
2802 | |
2803 iw::AsmTyperHarnessBuilder::VariableName DynamicGlobal(const char* name) { | |
2804 return iw::AsmTyperHarnessBuilder::VariableName(name, DYNAMIC_GLOBAL); | |
2805 } | |
2806 | |
2807 TEST(MissingUseAsmDirective) { | |
2808 v8::V8::Initialize(); | |
2809 | |
2810 // We can't test the empty input ("") because the AsmTyperHarnessBuilder will | |
2811 // CHECK if there's no function in the top-level scope. | |
2812 const char* kTests[] = {"function module(){}", | |
2813 "function module(){ use_asm; }", | |
2814 "function module(){ \"use asm \"; }", | |
2815 "function module(){ \" use asm \"; }", | |
2816 "function module(){ \"use Asm\"; }"}; | |
2817 | |
2818 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
2819 const char* module = kTests[ii]; | |
2820 if (!ValidationOf(Module(module)) | |
2821 ->FailsWithMessage("missing \"use asm\"")) { | |
2822 std::cerr << "Test:\n" << module; | |
2823 CHECK(false); | |
2824 } | |
2825 } | |
2826 } | |
2827 | |
2828 TEST(InvalidModuleSignature) { | |
2829 v8::V8::Initialize(); | |
2830 | |
2831 const struct { | |
2832 const char* module; | |
2833 const char* error_message; | |
2834 } kTests[] = { | |
2835 {"function eval(){ \"use asm\"; }", | |
2836 "Invalid ASM.js identifier in module name"}, | |
2837 {"function arguments(){ \"use asm\"; }", | |
2838 "Invalid ASM.js identifier in module name"}, | |
2839 {"function module(eval){ \"use asm\"; }", | |
2840 "Invalid ASM.js identifier in module parameter"}, | |
2841 {"function module(arguments){ \"use asm\"; }", | |
2842 "Invalid ASM.js identifier in module parameter"}, | |
2843 {"function module(stdlib, eval){ \"use asm\"; }", | |
2844 "Invalid ASM.js identifier in module parameter"}, | |
2845 {"function module(stdlib, arguments){ \"use asm\"; }", | |
2846 "Invalid ASM.js identifier in module parameter"}, | |
2847 {"function module(stdlib, foreign, eval){ \"use asm\"; }", | |
2848 "Invalid ASM.js identifier in module parameter"}, | |
2849 {"function module(stdlib, foreign, arguments){ \"use asm\"; }", | |
2850 "Invalid ASM.js identifier in module parameter"}, | |
2851 {"function module(stdlib, foreign, heap, eval){ \"use asm\"; }", | |
2852 "ASM.js modules may not have more than three parameters"}, | |
2853 {"function module(stdlib, foreign, heap, arguments){ \"use asm\"; }", | |
2854 "ASM.js modules may not have more than three parameters"}, | |
2855 {"function module(module){ \"use asm\"; }", | |
2856 "Redeclared identifier in module parameter"}, | |
2857 {"function module(stdlib, module){ \"use asm\"; }", | |
2858 "Redeclared identifier in module parameter"}, | |
2859 {"function module(stdlib, stdlib){ \"use asm\"; }", | |
2860 "Redeclared identifier in module parameter"}, | |
2861 {"function module(stdlib, foreign, module){ \"use asm\"; }", | |
2862 "Redeclared identifier in module parameter"}, | |
2863 {"function module(stdlib, foreign, stdlib){ \"use asm\"; }", | |
2864 "Redeclared identifier in module parameter"}, | |
2865 {"function module(stdlib, foreign, foreign){ \"use asm\"; }", | |
2866 "Redeclared identifier in module parameter"}, | |
2867 }; | |
2868 | |
2869 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
2870 const auto* test = kTests + ii; | |
2871 if (!ValidationOf(Module(test->module)) | |
2872 ->FailsWithMessage(test->error_message)) { | |
2873 std::cerr << "Test:\n" << test->module; | |
2874 CHECK(false); | |
2875 } | |
2876 } | |
2877 } | |
2878 | |
2879 TEST(ErrorsInGlobalVariableDefinition) { | |
2880 const struct { | |
2881 const char* decl; | |
2882 const char* error_message; | |
2883 } kTests[] = { | |
2884 {"var v;", "Global variable missing initializer"}, | |
2885 {"var v = uninitialized;", "Invalid global variable initializer"}, | |
2886 {"var v = 'use asm';", "type annotation - forbidden literal"}, | |
2887 {"var v = 4294967296;", " - forbidden literal"}, | |
2888 {"var v = not_fround;", "Invalid global variable initializer"}, | |
2889 {"var v = not_fround(1);", "expected call fround(literal)"}, | |
2890 {"var v = __fround__(1.0);", "expected call fround(literal)"}, | |
2891 {"var v = fround(1.0, 1.0);", "expected call fround(literal)"}, | |
2892 {"var v = fround(not_fround);", "literal argument for call to fround"}, | |
2893 {"var v = fround(1);", "literal argument to be a floating point"}, | |
2894 {"var v = stdlib.nan", "Invalid import"}, | |
2895 {"var v = stdlib.Math.nan", "Invalid import"}, | |
2896 {"var v = stdlib.Mathh.E", "Invalid import"}, | |
2897 {"var v = stdlib.Math", "Invalid import"}, | |
2898 {"var v = Stdlib.Math.E", "Invalid import"}, | |
2899 {"var v = stdlib.Math.E[0]", "Invalid import"}, | |
2900 {"var v = stdlibb.NaN", "Invalid import"}, | |
2901 {"var v = ffi.NaN[0]", "Invalid import"}, | |
2902 {"var v = heap.NaN[0]", "Invalid import"}, | |
2903 {"var v = ffi.foo * 2.0;", "unrecognized annotation"}, | |
2904 {"var v = ffi.foo|1;", "unrecognized annotation"}, | |
2905 {"var v = ffi()|0;", "must import member"}, | |
2906 {"var v = +ffi();", "must import member"}, | |
2907 {"var v = ffi().a|0;", "object lookup failed"}, | |
2908 {"var v = +ffi().a;", "object lookup failed"}, | |
2909 {"var v = sstdlib.a|0;", "object lookup failed"}, | |
2910 {"var v = +sstdlib.a;", "object lookup failed"}, | |
2911 {"var v = stdlib.NaN|0;", "object is not the ffi"}, | |
2912 {"var v = +stdlib.NaN;", "object is not the ffi"}, | |
2913 {"var v = new f()", "Invalid type after new"}, | |
2914 {"var v = new stdli.Uint8Array(heap)", "Unknown stdlib member in heap"}, | |
2915 {"var v = new stdlib.dd(heap)", "Unknown stdlib member in heap"}, | |
2916 {"var v = new stdlib.Math.fround(heap)", "Type is not a heap view type"}, | |
2917 {"var v = new stdlib.Uint8Array(a, b)", "Invalid number of arguments"}, | |
2918 {"var v = new stdlib.Uint8Array(heap())", "should be the module's heap"}, | |
2919 {"var v = new stdlib.Uint8Array(heap_)", "instead of heap parameter"}, | |
2920 {"var v = new stdlib.Uint8Array(ffi)", "should be the module's heap"}, | |
2921 {"var eval = 0;", "in global variable"}, | |
2922 {"var eval = 0.0;", "in global variable"}, | |
2923 {"var eval = fround(0.0);", "in global variable"}, | |
2924 {"var eval = +ffi.a;", "in global variable"}, | |
2925 {"var eval = ffi.a|0;", "in global variable"}, | |
2926 {"var eval = ffi.a;", "in global variable"}, | |
2927 {"var eval = new stdlib.Uint8Array(heap);", "in global variable"}, | |
2928 {"var arguments = 0;", "in global variable"}, | |
2929 {"var arguments = 0.0;", "in global variable"}, | |
2930 {"var arguments = fround(0.0);", "in global variable"}, | |
2931 {"var arguments = +ffi.a;", "in global variable"}, | |
2932 {"var arguments = ffi.a|0;", "in global variable"}, | |
2933 {"var arguments = ffi.a;", "in global variable"}, | |
2934 {"var arguments = new stdlib.Uint8Array(heap);", "in global variable"}, | |
2935 {"var a = 0, a = 0.0;", "Redefined global variable"}, | |
2936 {"var a = 0; var a = 0;", "Redefined global variable"}, | |
2937 {"var a = 0, b = 0; var a = 0;", "Redefined global variable"}, | |
2938 {"var a = 0, b = 0; var b = 0, a = 0.0;", "Redefined global variable"}, | |
2939 }; | |
2940 | |
2941 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
2942 const auto* test = kTests + ii; | |
2943 if (!ValidationOf(Globals(test->decl)) | |
2944 ->WithStdlib(DynamicGlobal("stdlib")) | |
2945 ->WithFFI(DynamicGlobal("ffi")) | |
2946 ->WithHeap(DynamicGlobal("heap")) | |
2947 ->WithGlobal(DynamicGlobal("not_fround"), iw::AsmType::Int()) | |
2948 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround) | |
2949 ->FailsWithMessage(test->error_message)) { | |
2950 std::cerr << "Test:\n" << test->decl; | |
2951 CHECK(false); | |
2952 } | |
2953 } | |
2954 } | |
2955 | |
2956 TEST(ErrorsInFunctionTableDefinition) { | |
2957 const struct { | |
2958 const char* tables; | |
2959 const char* error_message; | |
2960 } kTests[] = { | |
2961 {"var a = [a, a, a];", "Invalid length for function pointer table"}, | |
2962 {"var a = [d2s0()];", "must be a function name"}, | |
2963 {"var a = [d2s44];", "Undefined identifier in function pointer"}, | |
2964 {"var a = [fround];", "not be a member of the standard library"}, | |
2965 {"var a = [imul];", "not be a member of the standard library"}, | |
2966 {"var a = [ffi_import];", "must be an ASM.js function"}, | |
2967 {"var a = [dI];", "must be an ASM.js function"}, | |
2968 {"var a = [d2s0, d2s1, d2s0, f2s0];", "mismatch in function pointer"}, | |
2969 {"var eval = [d2s0, d2s1];", "ASM.js identifier in function table name"}, | |
2970 {"var arguments = [d2s0, d2s1];", "ASM.js identifier in function table"}, | |
2971 {"var foo = [d2s0, d2s1];", "Identifier redefined in function table"}, | |
2972 {"var I = [d2s0, d2s1];", "Identifier redefined in function table name"}, | |
2973 {"var d2s = [d2f0, d2f1];", "redeclared as function pointer table"}, | |
2974 {"var d2s_t = [d2s0];", "Function table size mismatch"}, | |
2975 {"var d2s_t = [d2f0, d2sf];", "initializer does not match previous"}, | |
2976 }; | |
2977 | |
2978 auto d2s = [](Zone* zone) -> iw::AsmType* { | |
2979 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
2980 ret->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
2981 return ret; | |
2982 }; | |
2983 | |
2984 auto d2s_tbl = [](Zone* zone) -> iw::AsmType* { | |
2985 auto* d2s = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
2986 d2s->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
2987 | |
2988 auto* ret = iw::AsmType::FunctionTableType(zone, 2, d2s); | |
2989 return ret; | |
2990 }; | |
2991 | |
2992 auto f2s = [](Zone* zone) -> iw::AsmType* { | |
2993 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
2994 ret->AsFunctionType()->AddArgument(iw::AsmType::Float()); | |
2995 return ret; | |
2996 }; | |
2997 | |
2998 auto d2f = [](Zone* zone) -> iw::AsmType* { | |
2999 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Float()); | |
3000 ret->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
3001 return ret; | |
3002 }; | |
3003 | |
3004 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
3005 const auto* test = kTests + ii; | |
3006 if (!ValidationOf(FunctionTables(test->tables)) | |
3007 ->WithImport(DynamicGlobal("ffi_import"), iw::AsmTyper::kFFI) | |
3008 ->WithImport(DynamicGlobal("imul"), iw::AsmTyper::kMathImul) | |
3009 ->WithImport(DynamicGlobal("E"), iw::AsmTyper::kMathE) | |
3010 ->WithImport(DynamicGlobal("fround"), iw::AsmTyper::kMathFround) | |
3011 ->WithImport(DynamicGlobal("floor"), iw::AsmTyper::kMathFround) | |
3012 ->WithGlobal(DynamicGlobal("d2s0"), d2s) | |
3013 ->WithGlobal(DynamicGlobal("d2s1"), d2s) | |
3014 ->WithGlobal(DynamicGlobal("f2s0"), f2s) | |
3015 ->WithGlobal(DynamicGlobal("f2s1"), f2s) | |
3016 ->WithGlobal(DynamicGlobal("d2f0"), d2f) | |
3017 ->WithGlobal(DynamicGlobal("d2f1"), d2f) | |
3018 ->WithGlobal(DynamicGlobal("dI"), iw::AsmType::Int()) | |
3019 ->WithGlobal(Var("I"), iw::AsmType::Int()) | |
3020 ->WithUndefinedGlobal(Var("d2s"), d2s) | |
3021 ->WithUndefinedGlobal(Var("d2s_t"), d2s_tbl) | |
3022 ->FailsWithMessage(test->error_message)) { | |
3023 std::cerr << "Test:\n" << test->tables; | |
3024 CHECK(false); | |
3025 } | |
3026 } | |
3027 } | |
3028 | |
3029 TEST(ErrorsInModuleExport) { | |
bradnelson
2016/06/24 00:19:03
These tests are great John, definitely a good appr
John
2016/06/24 17:47:58
Acknowledged.
| |
3030 const struct { | |
3031 const char* module_export; | |
3032 const char* error_message; | |
3033 } kTests[] = { | |
3034 {"", "Missing ASM.js module export"}, | |
3035 {"return;", "Unrecognized expression in ASM.js module export expression"}, | |
3036 {"return d2s_tbl;", "is not an ASM.js function"}, | |
3037 {"return min;", "is not an ASM.js function"}, | |
3038 {"return I;", "is not an ASM.js function"}, | |
3039 {"return {\'a\': d2s_tbl}", "export property is not an ASM.js"}, | |
3040 {"return {\'a\': min}", "export cannot contain standard library"}, | |
3041 {"return {\'a\': f()}", "must be an ASM.js function name"}, | |
3042 {"return {\'a\': f}", "in ASM.js module export property"}, | |
3043 {"function v() { a(); } return {b: d2s}", "Missing definition for forw"}, | |
3044 {"return {b: d2s, \'a\': d2s_tbl}", "export property is not an ASM.js"}, | |
3045 {"return {b: d2s, \'a\': min}", "export cannot contain standard library"}, | |
3046 {"return {b: d2s, \'a\': f()}", "must be an ASM.js function name"}, | |
3047 {"return {b: d2s, \'a\': f}", "in ASM.js module export property"}, | |
3048 }; | |
3049 | |
3050 auto d2s_tbl = [](Zone* zone) -> iw::AsmType* { | |
3051 auto* d2s = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
3052 d2s->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
3053 | |
3054 auto* ret = iw::AsmType::FunctionTableType(zone, 2, d2s); | |
3055 return ret; | |
3056 }; | |
3057 | |
3058 auto d2s = [](Zone* zone) -> iw::AsmType* { | |
3059 auto* ret = iw::AsmType::Function(zone, iw::AsmType::Signed()); | |
3060 ret->AsFunctionType()->AddArgument(iw::AsmType::Double()); | |
3061 return ret; | |
3062 }; | |
3063 | |
3064 for (size_t ii = 0; ii < arraysize(kTests); ++ii) { | |
3065 const auto* test = kTests + ii; | |
3066 if (!ValidationOf(Export(test->module_export)) | |
3067 ->WithGlobal(DynamicGlobal("d2s_tbl"), d2s_tbl) | |
3068 ->WithGlobal(DynamicGlobal("d2s"), d2s) | |
3069 ->WithImport(DynamicGlobal("min"), iw::AsmTyper::kMathMin) | |
3070 ->WithGlobal(DynamicGlobal("I"), iw::AsmType::Int()) | |
3071 ->FailsWithMessage(test->error_message)) { | |
3072 std::cerr << "Test:\n" << test->module_export; | |
3073 CHECK(false); | |
3074 } | |
3075 } | |
3076 } | |
3077 | |
3078 } // namespace | |
OLD | NEW |