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 #include "src/execution.h" | 7 #include "src/execution.h" |
8 #include "src/handles.h" | 8 #include "src/handles.h" |
9 #include "src/interpreter/bytecode-array-builder.h" | 9 #include "src/interpreter/bytecode-array-builder.h" |
10 #include "src/interpreter/interpreter.h" | 10 #include "src/interpreter/interpreter.h" |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 : InterpreterTester(isolate, source, MaybeHandle<BytecodeArray>(), | 89 : InterpreterTester(isolate, source, MaybeHandle<BytecodeArray>(), |
90 MaybeHandle<TypeFeedbackVector>(), filter) {} | 90 MaybeHandle<TypeFeedbackVector>(), filter) {} |
91 | 91 |
92 virtual ~InterpreterTester() {} | 92 virtual ~InterpreterTester() {} |
93 | 93 |
94 template <class... A> | 94 template <class... A> |
95 InterpreterCallable<A...> GetCallable() { | 95 InterpreterCallable<A...> GetCallable() { |
96 return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>()); | 96 return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>()); |
97 } | 97 } |
98 | 98 |
| 99 Local<Message> CheckThrowsReturnMessage() { |
| 100 TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate_)); |
| 101 auto callable = GetCallable<>(); |
| 102 MaybeHandle<Object> no_result = callable(); |
| 103 CHECK(isolate_->has_pending_exception()); |
| 104 CHECK(try_catch.HasCaught()); |
| 105 CHECK(no_result.is_null()); |
| 106 isolate_->OptionalRescheduleException(true); |
| 107 CHECK(!try_catch.Message().IsEmpty()); |
| 108 return try_catch.Message(); |
| 109 } |
| 110 |
99 static Handle<Object> NewObject(const char* script) { | 111 static Handle<Object> NewObject(const char* script) { |
100 return v8::Utils::OpenHandle(*CompileRun(script)); | 112 return v8::Utils::OpenHandle(*CompileRun(script)); |
101 } | 113 } |
102 | 114 |
103 static Handle<String> GetName(Isolate* isolate, const char* name) { | 115 static Handle<String> GetName(Isolate* isolate, const char* name) { |
104 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(name); | 116 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(name); |
105 return isolate->factory()->string_table()->LookupString(isolate, result); | 117 return isolate->factory()->string_table()->LookupString(isolate, result); |
106 } | 118 } |
107 | 119 |
108 static std::string SourceForBody(const char* body) { | 120 static std::string SourceForBody(const char* body) { |
(...skipping 3676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3785 for (size_t i = 0; i < arraysize(with_stmt); i++) { | 3797 for (size_t i = 0; i < arraysize(with_stmt); i++) { |
3786 std::string source(InterpreterTester::SourceForBody(with_stmt[i].first)); | 3798 std::string source(InterpreterTester::SourceForBody(with_stmt[i].first)); |
3787 InterpreterTester tester(handles.main_isolate(), source.c_str()); | 3799 InterpreterTester tester(handles.main_isolate(), source.c_str()); |
3788 auto callable = tester.GetCallable<>(); | 3800 auto callable = tester.GetCallable<>(); |
3789 | 3801 |
3790 Handle<i::Object> return_value = callable().ToHandleChecked(); | 3802 Handle<i::Object> return_value = callable().ToHandleChecked(); |
3791 CHECK(return_value->SameValue(*with_stmt[i].second)); | 3803 CHECK(return_value->SameValue(*with_stmt[i].second)); |
3792 } | 3804 } |
3793 } | 3805 } |
3794 | 3806 |
| 3807 TEST(InterpreterConstDeclaration) { |
| 3808 HandleAndZoneScope handles; |
| 3809 i::Isolate* isolate = handles.main_isolate(); |
| 3810 i::Factory* factory = isolate->factory(); |
| 3811 |
| 3812 std::pair<const char*, Handle<Object>> const_decl[] = { |
| 3813 {"const x = 3; return x;", handle(Smi::FromInt(3), isolate)}, |
| 3814 {"let x = 10; x = x + 20; return x;", handle(Smi::FromInt(30), isolate)}, |
| 3815 {"let x = 10; x = 20; return x;", handle(Smi::FromInt(20), isolate)}, |
| 3816 {"let x; x = 20; return x;", handle(Smi::FromInt(20), isolate)}, |
| 3817 {"let x; return x;", factory->undefined_value()}, |
| 3818 {"var x = 10; { let x = 30; } return x;", |
| 3819 handle(Smi::FromInt(10), isolate)}, |
| 3820 {"let x = 10; { let x = 20; } return x;", |
| 3821 handle(Smi::FromInt(10), isolate)}, |
| 3822 {"var x = 10; eval('let x = 20;'); return x;", |
| 3823 handle(Smi::FromInt(10), isolate)}, |
| 3824 {"var x = 10; eval('const x = 20;'); return x;", |
| 3825 handle(Smi::FromInt(10), isolate)}, |
| 3826 {"var x = 10; { const x = 20; } return x;", |
| 3827 handle(Smi::FromInt(10), isolate)}, |
| 3828 {"var x = 10; { const x = 20; return x;} return -1;", |
| 3829 handle(Smi::FromInt(20), isolate)}, |
| 3830 {"var a = 10;\n" |
| 3831 "for (var i = 0; i < 10; ++i) {\n" |
| 3832 " const x = i;\n" // const declarations are block scoped. |
| 3833 " a = a + x;\n" |
| 3834 "}\n" |
| 3835 "return a;\n", |
| 3836 handle(Smi::FromInt(55), isolate)}, |
| 3837 }; |
| 3838 |
| 3839 // Tests for sloppy mode. |
| 3840 for (size_t i = 0; i < arraysize(const_decl); i++) { |
| 3841 std::string source(InterpreterTester::SourceForBody(const_decl[i].first)); |
| 3842 InterpreterTester tester(handles.main_isolate(), source.c_str()); |
| 3843 auto callable = tester.GetCallable<>(); |
| 3844 |
| 3845 Handle<i::Object> return_value = callable().ToHandleChecked(); |
| 3846 CHECK(return_value->SameValue(*const_decl[i].second)); |
| 3847 } |
| 3848 |
| 3849 // Tests for strict mode. |
| 3850 for (size_t i = 0; i < arraysize(const_decl); i++) { |
| 3851 std::string strict_body = |
| 3852 "'use strict'; " + std::string(const_decl[i].first); |
| 3853 std::string source(InterpreterTester::SourceForBody(strict_body.c_str())); |
| 3854 InterpreterTester tester(handles.main_isolate(), source.c_str()); |
| 3855 auto callable = tester.GetCallable<>(); |
| 3856 |
| 3857 Handle<i::Object> return_value = callable().ToHandleChecked(); |
| 3858 CHECK(return_value->SameValue(*const_decl[i].second)); |
| 3859 } |
| 3860 } |
| 3861 |
| 3862 TEST(InterpreterConstDeclarationLookupSlots) { |
| 3863 HandleAndZoneScope handles; |
| 3864 i::Isolate* isolate = handles.main_isolate(); |
| 3865 i::Factory* factory = isolate->factory(); |
| 3866 |
| 3867 std::pair<const char*, Handle<Object>> const_decl[] = { |
| 3868 {"const x = 3; function f1() {return x;}; return x;", |
| 3869 handle(Smi::FromInt(3), isolate)}, |
| 3870 {"let x = 10; x = x + 20; function f1() {return x;}; return x;", |
| 3871 handle(Smi::FromInt(30), isolate)}, |
| 3872 {"let x; x = 20; function f1() {return x;}; return x;", |
| 3873 handle(Smi::FromInt(20), isolate)}, |
| 3874 {"let x; function f1() {return x;}; return x;", |
| 3875 factory->undefined_value()}, |
| 3876 }; |
| 3877 |
| 3878 // Tests for sloppy mode. |
| 3879 for (size_t i = 0; i < arraysize(const_decl); i++) { |
| 3880 std::string source(InterpreterTester::SourceForBody(const_decl[i].first)); |
| 3881 InterpreterTester tester(handles.main_isolate(), source.c_str()); |
| 3882 auto callable = tester.GetCallable<>(); |
| 3883 |
| 3884 Handle<i::Object> return_value = callable().ToHandleChecked(); |
| 3885 CHECK(return_value->SameValue(*const_decl[i].second)); |
| 3886 } |
| 3887 |
| 3888 // Tests for strict mode. |
| 3889 for (size_t i = 0; i < arraysize(const_decl); i++) { |
| 3890 std::string strict_body = |
| 3891 "'use strict'; " + std::string(const_decl[i].first); |
| 3892 std::string source(InterpreterTester::SourceForBody(strict_body.c_str())); |
| 3893 InterpreterTester tester(handles.main_isolate(), source.c_str()); |
| 3894 auto callable = tester.GetCallable<>(); |
| 3895 |
| 3896 Handle<i::Object> return_value = callable().ToHandleChecked(); |
| 3897 CHECK(return_value->SameValue(*const_decl[i].second)); |
| 3898 } |
| 3899 } |
| 3900 |
| 3901 TEST(InterpreterConstInLookupContextChain) { |
| 3902 HandleAndZoneScope handles; |
| 3903 i::Isolate* isolate = handles.main_isolate(); |
| 3904 |
| 3905 const char* prologue = |
| 3906 "function OuterMost() {\n" |
| 3907 " const outerConst = 10;\n" |
| 3908 " let outerLet = 20;\n" |
| 3909 " function Outer() {\n" |
| 3910 " function Inner() {\n" |
| 3911 " this.innerFunc = function() { "; |
| 3912 const char* epilogue = |
| 3913 " }\n" |
| 3914 " }\n" |
| 3915 " this.getInnerFunc =" |
| 3916 " function() {return new Inner().innerFunc;}\n" |
| 3917 " }\n" |
| 3918 " this.getOuterFunc =" |
| 3919 " function() {return new Outer().getInnerFunc();}" |
| 3920 "}\n" |
| 3921 "var f = new OuterMost().getOuterFunc();\n" |
| 3922 "f();\n"; |
| 3923 std::pair<const char*, Handle<Object>> const_decl[] = { |
| 3924 {"return outerConst;", handle(Smi::FromInt(10), isolate)}, |
| 3925 {"return outerLet;", handle(Smi::FromInt(20), isolate)}, |
| 3926 {"outerLet = 30; return outerLet;", handle(Smi::FromInt(30), isolate)}, |
| 3927 {"var outerLet = 40; return outerLet;", |
| 3928 handle(Smi::FromInt(40), isolate)}, |
| 3929 {"var outerConst = 50; return outerConst;", |
| 3930 handle(Smi::FromInt(50), isolate)}, |
| 3931 {"try { outerConst = 30 } catch(e) { return -1; }", |
| 3932 handle(Smi::FromInt(-1), isolate)}}; |
| 3933 |
| 3934 for (size_t i = 0; i < arraysize(const_decl); i++) { |
| 3935 std::string script = std::string(prologue) + |
| 3936 std::string(const_decl[i].first) + |
| 3937 std::string(epilogue); |
| 3938 InterpreterTester tester(handles.main_isolate(), script.c_str(), "*"); |
| 3939 auto callable = tester.GetCallable<>(); |
| 3940 |
| 3941 Handle<i::Object> return_value = callable().ToHandleChecked(); |
| 3942 CHECK(return_value->SameValue(*const_decl[i].second)); |
| 3943 } |
| 3944 |
| 3945 // Tests for Legacy constant. |
| 3946 bool old_flag_legacy_const = FLAG_legacy_const; |
| 3947 FLAG_legacy_const = true; |
| 3948 |
| 3949 std::pair<const char*, Handle<Object>> legacy_const_decl[] = { |
| 3950 {"return outerConst = 23;", handle(Smi::FromInt(23), isolate)}, |
| 3951 {"outerConst = 30; return outerConst;", |
| 3952 handle(Smi::FromInt(10), isolate)}, |
| 3953 }; |
| 3954 |
| 3955 for (size_t i = 0; i < arraysize(legacy_const_decl); i++) { |
| 3956 std::string script = std::string(prologue) + |
| 3957 std::string(legacy_const_decl[i].first) + |
| 3958 std::string(epilogue); |
| 3959 InterpreterTester tester(handles.main_isolate(), script.c_str(), "*"); |
| 3960 auto callable = tester.GetCallable<>(); |
| 3961 |
| 3962 Handle<i::Object> return_value = callable().ToHandleChecked(); |
| 3963 CHECK(return_value->SameValue(*legacy_const_decl[i].second)); |
| 3964 } |
| 3965 |
| 3966 FLAG_legacy_const = old_flag_legacy_const; |
| 3967 } |
| 3968 |
| 3969 TEST(InterpreterIllegalConstDeclaration) { |
| 3970 HandleAndZoneScope handles; |
| 3971 |
| 3972 std::pair<const char*, const char*> const_decl[] = { |
| 3973 {"const x = x = 10 + 3; return x;", |
| 3974 "Uncaught ReferenceError: x is not defined"}, |
| 3975 {"const x = 10; x = 20; return x;", |
| 3976 "Uncaught TypeError: Assignment to constant variable."}, |
| 3977 {"const x = 10; { x = 20; } return x;", |
| 3978 "Uncaught TypeError: Assignment to constant variable."}, |
| 3979 {"const x = 10; eval('x = 20;'); return x;", |
| 3980 "Uncaught TypeError: Assignment to constant variable."}, |
| 3981 {"let x = x + 10; return x;", |
| 3982 "Uncaught ReferenceError: x is not defined"}, |
| 3983 {"'use strict'; (function f1() { f1 = 123; })() ", |
| 3984 "Uncaught TypeError: Assignment to constant variable."}, |
| 3985 }; |
| 3986 |
| 3987 // Tests for sloppy mode. |
| 3988 for (size_t i = 0; i < arraysize(const_decl); i++) { |
| 3989 std::string source(InterpreterTester::SourceForBody(const_decl[i].first)); |
| 3990 InterpreterTester tester(handles.main_isolate(), source.c_str()); |
| 3991 v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); |
| 3992 v8::Local<v8::String> expected_string = v8_str(const_decl[i].second); |
| 3993 CHECK( |
| 3994 message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) |
| 3995 .FromJust()); |
| 3996 } |
| 3997 |
| 3998 // Tests for strict mode. |
| 3999 for (size_t i = 0; i < arraysize(const_decl); i++) { |
| 4000 std::string strict_body = |
| 4001 "'use strict'; " + std::string(const_decl[i].first); |
| 4002 std::string source(InterpreterTester::SourceForBody(strict_body.c_str())); |
| 4003 InterpreterTester tester(handles.main_isolate(), source.c_str()); |
| 4004 v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); |
| 4005 v8::Local<v8::String> expected_string = v8_str(const_decl[i].second); |
| 4006 CHECK( |
| 4007 message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) |
| 4008 .FromJust()); |
| 4009 } |
| 4010 } |
| 4011 |
| 4012 TEST(InterpreterLegacyConstDeclaration) { |
| 4013 bool old_flag_legacy_const = FLAG_legacy_const; |
| 4014 FLAG_legacy_const = true; |
| 4015 |
| 4016 HandleAndZoneScope handles; |
| 4017 i::Isolate* isolate = handles.main_isolate(); |
| 4018 |
| 4019 std::pair<const char*, Handle<Object>> const_decl[] = { |
| 4020 {"const x = (x = 10) + 3; return x;", handle(Smi::FromInt(13), isolate)}, |
| 4021 {"const x = 10; x = 20; return x;", handle(Smi::FromInt(10), isolate)}, |
| 4022 {"var a = 10;\n" |
| 4023 "for (var i = 0; i < 10; ++i) {\n" |
| 4024 " const x = i;\n" // Legacy constants are not block scoped. |
| 4025 " a = a + x;\n" |
| 4026 "}\n" |
| 4027 "return a;\n", |
| 4028 handle(Smi::FromInt(10), isolate)}, |
| 4029 {"const x = 20; eval('x = 10;'); return x;", |
| 4030 handle(Smi::FromInt(20), isolate)}, |
| 4031 }; |
| 4032 |
| 4033 for (size_t i = 0; i < arraysize(const_decl); i++) { |
| 4034 std::string source(InterpreterTester::SourceForBody(const_decl[i].first)); |
| 4035 InterpreterTester tester(handles.main_isolate(), source.c_str()); |
| 4036 auto callable = tester.GetCallable<>(); |
| 4037 |
| 4038 Handle<i::Object> return_value = callable().ToHandleChecked(); |
| 4039 CHECK(return_value->SameValue(*const_decl[i].second)); |
| 4040 } |
| 4041 |
| 4042 FLAG_legacy_const = old_flag_legacy_const; |
| 4043 } |
| 4044 |
3795 } // namespace interpreter | 4045 } // namespace interpreter |
3796 } // namespace internal | 4046 } // namespace internal |
3797 } // namespace v8 | 4047 } // namespace v8 |
OLD | NEW |