| 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 |