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 "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 // Required to get M_E etc. in MSVC. | 7 // Required to get M_E etc. in MSVC. |
8 #if defined(_WIN32) | 8 #if defined(_WIN32) |
9 #define _USE_MATH_DEFINES | 9 #define _USE_MATH_DEFINES |
10 #endif | 10 #endif |
11 #include <math.h> | 11 #include <math.h> |
12 | 12 |
13 #include "src/asmjs/asm-types.h" | 13 #include "src/asmjs/asm-types.h" |
14 #include "src/asmjs/asm-wasm-builder.h" | 14 #include "src/asmjs/asm-wasm-builder.h" |
15 #include "src/asmjs/switch-logic.h" | 15 #include "src/asmjs/switch-logic.h" |
16 | 16 |
17 #include "src/wasm/wasm-macro-gen.h" | 17 #include "src/wasm/wasm-macro-gen.h" |
18 #include "src/wasm/wasm-opcodes.h" | 18 #include "src/wasm/wasm-opcodes.h" |
19 | 19 |
20 #include "src/ast/ast.h" | 20 #include "src/ast/ast.h" |
21 #include "src/ast/scopes.h" | 21 #include "src/ast/scopes.h" |
22 #include "src/codegen.h" | |
23 | 22 |
24 namespace v8 { | 23 namespace v8 { |
25 namespace internal { | 24 namespace internal { |
26 namespace wasm { | 25 namespace wasm { |
27 | 26 |
28 #define RECURSE(call) \ | 27 #define RECURSE(call) \ |
29 do { \ | 28 do { \ |
30 DCHECK(!HasStackOverflow()); \ | 29 DCHECK(!HasStackOverflow()); \ |
31 call; \ | 30 call; \ |
32 if (HasStackOverflow()) return; \ | 31 if (HasStackOverflow()) return; \ |
(...skipping 715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
748 return pos->second; | 747 return pos->second; |
749 } else { | 748 } else { |
750 uint32_t index = builder_->builder_->AddImport( | 749 uint32_t index = builder_->builder_->AddImport( |
751 indices->name_, indices->name_length_, sig); | 750 indices->name_, indices->name_length_, sig); |
752 indices->signature_to_index_[sig] = index; | 751 indices->signature_to_index_[sig] = index; |
753 return index; | 752 return index; |
754 } | 753 } |
755 } | 754 } |
756 }; | 755 }; |
757 | 756 |
758 void EmitAssignmentLhs(Expression* target, MachineType* mtype) { | 757 void EmitAssignmentLhs(Expression* target, AsmType** atype) { |
759 // Match the left hand side of the assignment. | 758 // Match the left hand side of the assignment. |
760 VariableProxy* target_var = target->AsVariableProxy(); | 759 VariableProxy* target_var = target->AsVariableProxy(); |
761 if (target_var != nullptr) { | 760 if (target_var != nullptr) { |
762 // Left hand side is a local or a global variable, no code on LHS. | 761 // Left hand side is a local or a global variable, no code on LHS. |
763 return; | 762 return; |
764 } | 763 } |
765 | 764 |
766 Property* target_prop = target->AsProperty(); | 765 Property* target_prop = target->AsProperty(); |
767 if (target_prop != nullptr) { | 766 if (target_prop != nullptr) { |
768 // Left hand side is a property access, i.e. the asm.js heap. | 767 // Left hand side is a property access, i.e. the asm.js heap. |
769 VisitPropertyAndEmitIndex(target_prop, mtype); | 768 VisitPropertyAndEmitIndex(target_prop, atype); |
770 return; | 769 return; |
771 } | 770 } |
772 | 771 |
773 if (target_var == nullptr && target_prop == nullptr) { | 772 if (target_var == nullptr && target_prop == nullptr) { |
774 UNREACHABLE(); // invalid assignment. | 773 UNREACHABLE(); // invalid assignment. |
775 } | 774 } |
776 } | 775 } |
777 | 776 |
778 void EmitAssignmentRhs(Expression* target, Expression* value, bool* is_nop) { | 777 void EmitAssignmentRhs(Expression* target, Expression* value, bool* is_nop) { |
779 BinaryOperation* binop = value->AsBinaryOperation(); | 778 BinaryOperation* binop = value->AsBinaryOperation(); |
(...skipping 27 matching lines...) Expand all Loading... |
807 if (target_var != nullptr && effective_value_var != nullptr && | 806 if (target_var != nullptr && effective_value_var != nullptr && |
808 target_var->var() == effective_value_var->var()) { | 807 target_var->var() == effective_value_var->var()) { |
809 *is_nop = true; | 808 *is_nop = true; |
810 return; | 809 return; |
811 } | 810 } |
812 } | 811 } |
813 } | 812 } |
814 RECURSE(Visit(value)); | 813 RECURSE(Visit(value)); |
815 } | 814 } |
816 | 815 |
817 void EmitAssignment(Assignment* expr, MachineType type, ValueFate fate) { | 816 void EmitAssignment(Assignment* expr, AsmType* type, ValueFate fate) { |
818 // Match the left hand side of the assignment. | 817 // Match the left hand side of the assignment. |
819 VariableProxy* target_var = expr->target()->AsVariableProxy(); | 818 VariableProxy* target_var = expr->target()->AsVariableProxy(); |
820 if (target_var != nullptr) { | 819 if (target_var != nullptr) { |
821 // Left hand side is a local or a global variable. | 820 // Left hand side is a local or a global variable. |
822 Variable* var = target_var->var(); | 821 Variable* var = target_var->var(); |
823 LocalType var_type = TypeOf(expr); | 822 LocalType var_type = TypeOf(expr); |
824 DCHECK_NE(kAstStmt, var_type); | 823 DCHECK_NE(kAstStmt, var_type); |
825 if (var->IsContextSlot()) { | 824 if (var->IsContextSlot()) { |
826 uint32_t index = LookupOrInsertGlobal(var, var_type); | 825 uint32_t index = LookupOrInsertGlobal(var, var_type); |
827 current_function_builder_->EmitWithVarInt(kExprSetGlobal, index); | 826 current_function_builder_->EmitWithVarInt(kExprSetGlobal, index); |
(...skipping 14 matching lines...) Expand all Loading... |
842 Property* target_prop = expr->target()->AsProperty(); | 841 Property* target_prop = expr->target()->AsProperty(); |
843 if (target_prop != nullptr) { | 842 if (target_prop != nullptr) { |
844 // Left hand side is a property access, i.e. the asm.js heap. | 843 // Left hand side is a property access, i.e. the asm.js heap. |
845 if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() && | 844 if (TypeOf(expr->value()) == kAstF64 && expr->target()->IsProperty() && |
846 typer_->TypeOf(expr->target()->AsProperty()->obj()) | 845 typer_->TypeOf(expr->target()->AsProperty()->obj()) |
847 ->IsA(AsmType::Float32Array())) { | 846 ->IsA(AsmType::Float32Array())) { |
848 current_function_builder_->Emit(kExprF32ConvertF64); | 847 current_function_builder_->Emit(kExprF32ConvertF64); |
849 } | 848 } |
850 // Note that unlike StoreMem, AsmjsStoreMem ignores out-of-bounds writes. | 849 // Note that unlike StoreMem, AsmjsStoreMem ignores out-of-bounds writes. |
851 WasmOpcode opcode; | 850 WasmOpcode opcode; |
852 if (type == MachineType::Int8()) { | 851 if (type == AsmType::Int8Array()) { |
853 opcode = kExprI32AsmjsStoreMem8; | 852 opcode = kExprI32AsmjsStoreMem8; |
854 } else if (type == MachineType::Uint8()) { | 853 } else if (type == AsmType::Uint8Array()) { |
855 opcode = kExprI32AsmjsStoreMem8; | 854 opcode = kExprI32AsmjsStoreMem8; |
856 } else if (type == MachineType::Int16()) { | 855 } else if (type == AsmType::Int16Array()) { |
857 opcode = kExprI32AsmjsStoreMem16; | 856 opcode = kExprI32AsmjsStoreMem16; |
858 } else if (type == MachineType::Uint16()) { | 857 } else if (type == AsmType::Uint16Array()) { |
859 opcode = kExprI32AsmjsStoreMem16; | 858 opcode = kExprI32AsmjsStoreMem16; |
860 } else if (type == MachineType::Int32()) { | 859 } else if (type == AsmType::Int32Array()) { |
861 opcode = kExprI32AsmjsStoreMem; | 860 opcode = kExprI32AsmjsStoreMem; |
862 } else if (type == MachineType::Uint32()) { | 861 } else if (type == AsmType::Uint32Array()) { |
863 opcode = kExprI32AsmjsStoreMem; | 862 opcode = kExprI32AsmjsStoreMem; |
864 } else if (type == MachineType::Float32()) { | 863 } else if (type == AsmType::Float32Array()) { |
865 opcode = kExprF32AsmjsStoreMem; | 864 opcode = kExprF32AsmjsStoreMem; |
866 } else if (type == MachineType::Float64()) { | 865 } else if (type == AsmType::Float64Array()) { |
867 opcode = kExprF64AsmjsStoreMem; | 866 opcode = kExprF64AsmjsStoreMem; |
868 } else { | 867 } else { |
869 UNREACHABLE(); | 868 UNREACHABLE(); |
870 } | 869 } |
871 current_function_builder_->Emit(opcode); | 870 current_function_builder_->Emit(opcode); |
872 if (fate == kDrop) { | 871 if (fate == kDrop) { |
873 // Asm.js stores to memory leave their result on the stack. | 872 // Asm.js stores to memory leave their result on the stack. |
874 current_function_builder_->Emit(kExprDrop); | 873 current_function_builder_->Emit(kExprDrop); |
875 } | 874 } |
876 } | 875 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
923 return; | 922 return; |
924 } | 923 } |
925 if (expr->value()->IsCallNew()) { | 924 if (expr->value()->IsCallNew()) { |
926 // No init code to emit for CallNew nodes. | 925 // No init code to emit for CallNew nodes. |
927 return; | 926 return; |
928 } | 927 } |
929 as_init = true; | 928 as_init = true; |
930 } | 929 } |
931 | 930 |
932 if (as_init) LoadInitFunction(); | 931 if (as_init) LoadInitFunction(); |
933 MachineType mtype = MachineType::None(); | 932 AsmType* atype = AsmType::None(); |
934 bool is_nop = false; | 933 bool is_nop = false; |
935 EmitAssignmentLhs(expr->target(), &mtype); | 934 EmitAssignmentLhs(expr->target(), &atype); |
936 EmitAssignmentRhs(expr->target(), expr->value(), &is_nop); | 935 EmitAssignmentRhs(expr->target(), expr->value(), &is_nop); |
937 if (!is_nop) { | 936 if (!is_nop) { |
938 EmitAssignment(expr, mtype, fate); | 937 EmitAssignment(expr, atype, fate); |
939 } | 938 } |
940 if (as_init) UnLoadInitFunction(); | 939 if (as_init) UnLoadInitFunction(); |
941 } | 940 } |
942 | 941 |
943 void VisitYield(Yield* expr) { UNREACHABLE(); } | 942 void VisitYield(Yield* expr) { UNREACHABLE(); } |
944 | 943 |
945 void VisitThrow(Throw* expr) { UNREACHABLE(); } | 944 void VisitThrow(Throw* expr) { UNREACHABLE(); } |
946 | 945 |
947 void VisitForeignVariable(bool is_float, Variable* var, Property* expr) { | 946 void VisitForeignVariable(bool is_float, Variable* var, Property* expr) { |
948 DCHECK(expr->obj()->AsVariableProxy()); | 947 DCHECK(expr->obj()->AsVariableProxy()); |
949 DCHECK(VariableLocation::PARAMETER == | 948 DCHECK(VariableLocation::PARAMETER == |
950 expr->obj()->AsVariableProxy()->var()->location()); | 949 expr->obj()->AsVariableProxy()->var()->location()); |
951 DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index()); | 950 DCHECK_EQ(1, expr->obj()->AsVariableProxy()->var()->index()); |
952 Literal* key_literal = expr->key()->AsLiteral(); | 951 Literal* key_literal = expr->key()->AsLiteral(); |
953 DCHECK_NOT_NULL(key_literal); | 952 DCHECK_NOT_NULL(key_literal); |
954 if (!key_literal->value().is_null()) { | 953 if (!key_literal->value().is_null()) { |
955 Handle<Name> name = | 954 Handle<Name> name = |
956 i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked(); | 955 i::Object::ToName(isolate_, key_literal->value()).ToHandleChecked(); |
957 LocalType type = is_float ? kAstF64 : kAstI32; | 956 LocalType type = is_float ? kAstF64 : kAstI32; |
958 foreign_variables_.push_back({name, var, type}); | 957 foreign_variables_.push_back({name, var, type}); |
959 } | 958 } |
960 } | 959 } |
961 | 960 |
962 void VisitPropertyAndEmitIndex(Property* expr, MachineType* mtype) { | 961 void VisitPropertyAndEmitIndex(Property* expr, AsmType** atype) { |
963 Expression* obj = expr->obj(); | 962 Expression* obj = expr->obj(); |
964 AsmType* type = typer_->TypeOf(obj); | 963 *atype = typer_->TypeOf(obj); |
965 int size; | 964 int size = (*atype)->ElementSizeInBytes(); |
966 if (type->IsA(AsmType::Uint8Array())) { | |
967 *mtype = MachineType::Uint8(); | |
968 size = 1; | |
969 } else if (type->IsA(AsmType::Int8Array())) { | |
970 *mtype = MachineType::Int8(); | |
971 size = 1; | |
972 } else if (type->IsA(AsmType::Uint16Array())) { | |
973 *mtype = MachineType::Uint16(); | |
974 size = 2; | |
975 } else if (type->IsA(AsmType::Int16Array())) { | |
976 *mtype = MachineType::Int16(); | |
977 size = 2; | |
978 } else if (type->IsA(AsmType::Uint32Array())) { | |
979 *mtype = MachineType::Uint32(); | |
980 size = 4; | |
981 } else if (type->IsA(AsmType::Int32Array())) { | |
982 *mtype = MachineType::Int32(); | |
983 size = 4; | |
984 } else if (type->IsA(AsmType::Uint32Array())) { | |
985 *mtype = MachineType::Uint32(); | |
986 size = 4; | |
987 } else if (type->IsA(AsmType::Float32Array())) { | |
988 *mtype = MachineType::Float32(); | |
989 size = 4; | |
990 } else if (type->IsA(AsmType::Float64Array())) { | |
991 *mtype = MachineType::Float64(); | |
992 size = 8; | |
993 } else { | |
994 UNREACHABLE(); | |
995 } | |
996 if (size == 1) { | 965 if (size == 1) { |
997 // Allow more general expression in byte arrays than the spec | 966 // Allow more general expression in byte arrays than the spec |
998 // strictly permits. | 967 // strictly permits. |
999 // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in | 968 // Early versions of Emscripten emit HEAP8[HEAP32[..]|0] in |
1000 // places that strictly should be HEAP8[HEAP32[..]>>0]. | 969 // places that strictly should be HEAP8[HEAP32[..]>>0]. |
1001 RECURSE(Visit(expr->key())); | 970 RECURSE(Visit(expr->key())); |
1002 return; | 971 return; |
1003 } | 972 } |
1004 | 973 |
1005 Literal* value = expr->key()->AsLiteral(); | 974 Literal* value = expr->key()->AsLiteral(); |
(...skipping 17 matching lines...) Expand all Loading... |
1023 byte mask = static_cast<byte>(~(size - 1)); | 992 byte mask = static_cast<byte>(~(size - 1)); |
1024 RECURSE(Visit(binop->left())); | 993 RECURSE(Visit(binop->left())); |
1025 current_function_builder_->EmitWithU8(kExprI8Const, mask); | 994 current_function_builder_->EmitWithU8(kExprI8Const, mask); |
1026 current_function_builder_->Emit(kExprI32And); | 995 current_function_builder_->Emit(kExprI32And); |
1027 return; | 996 return; |
1028 } | 997 } |
1029 UNREACHABLE(); | 998 UNREACHABLE(); |
1030 } | 999 } |
1031 | 1000 |
1032 void VisitProperty(Property* expr) { | 1001 void VisitProperty(Property* expr) { |
1033 MachineType type; | 1002 AsmType* type = AsmType::None(); |
1034 VisitPropertyAndEmitIndex(expr, &type); | 1003 VisitPropertyAndEmitIndex(expr, &type); |
1035 WasmOpcode opcode; | 1004 WasmOpcode opcode; |
1036 if (type == MachineType::Int8()) { | 1005 if (type == AsmType::Int8Array()) { |
1037 opcode = kExprI32AsmjsLoadMem8S; | 1006 opcode = kExprI32AsmjsLoadMem8S; |
1038 } else if (type == MachineType::Uint8()) { | 1007 } else if (type == AsmType::Uint8Array()) { |
1039 opcode = kExprI32AsmjsLoadMem8U; | 1008 opcode = kExprI32AsmjsLoadMem8U; |
1040 } else if (type == MachineType::Int16()) { | 1009 } else if (type == AsmType::Int16Array()) { |
1041 opcode = kExprI32AsmjsLoadMem16S; | 1010 opcode = kExprI32AsmjsLoadMem16S; |
1042 } else if (type == MachineType::Uint16()) { | 1011 } else if (type == AsmType::Uint16Array()) { |
1043 opcode = kExprI32AsmjsLoadMem16U; | 1012 opcode = kExprI32AsmjsLoadMem16U; |
1044 } else if (type == MachineType::Int32()) { | 1013 } else if (type == AsmType::Int32Array()) { |
1045 opcode = kExprI32AsmjsLoadMem; | 1014 opcode = kExprI32AsmjsLoadMem; |
1046 } else if (type == MachineType::Uint32()) { | 1015 } else if (type == AsmType::Uint32Array()) { |
1047 opcode = kExprI32AsmjsLoadMem; | 1016 opcode = kExprI32AsmjsLoadMem; |
1048 } else if (type == MachineType::Float32()) { | 1017 } else if (type == AsmType::Float32Array()) { |
1049 opcode = kExprF32AsmjsLoadMem; | 1018 opcode = kExprF32AsmjsLoadMem; |
1050 } else if (type == MachineType::Float64()) { | 1019 } else if (type == AsmType::Float64Array()) { |
1051 opcode = kExprF64AsmjsLoadMem; | 1020 opcode = kExprF64AsmjsLoadMem; |
1052 } else { | 1021 } else { |
1053 UNREACHABLE(); | 1022 UNREACHABLE(); |
1054 } | 1023 } |
1055 | 1024 |
1056 current_function_builder_->Emit(opcode); | 1025 current_function_builder_->Emit(opcode); |
1057 } | 1026 } |
1058 | 1027 |
1059 bool VisitStdlibFunction(Call* call, VariableProxy* expr) { | 1028 bool VisitStdlibFunction(Call* call, VariableProxy* expr) { |
1060 Variable* var = expr->var(); | 1029 Variable* var = expr->var(); |
(...skipping 823 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1884 impl.builder_->WriteAsmJsOffsetTable(*asm_offsets_buffer); | 1853 impl.builder_->WriteAsmJsOffsetTable(*asm_offsets_buffer); |
1885 return {module_buffer, asm_offsets_buffer}; | 1854 return {module_buffer, asm_offsets_buffer}; |
1886 } | 1855 } |
1887 | 1856 |
1888 const char* AsmWasmBuilder::foreign_init_name = "__foreign_init__"; | 1857 const char* AsmWasmBuilder::foreign_init_name = "__foreign_init__"; |
1889 const char* AsmWasmBuilder::single_function_name = "__single_function__"; | 1858 const char* AsmWasmBuilder::single_function_name = "__single_function__"; |
1890 | 1859 |
1891 } // namespace wasm | 1860 } // namespace wasm |
1892 } // namespace internal | 1861 } // namespace internal |
1893 } // namespace v8 | 1862 } // namespace v8 |
OLD | NEW |