Chromium Code Reviews| 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 |