1// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/v8.h"
6
7#include "test/cctest/compiler/function-tester.h"
8
9using namespace v8::internal;
10using namespace v8::internal::compiler;
11
12TEST(SimpleCall) {
13  FunctionTester T("(function(foo,a) { return foo(a); })");
14  Handle<JSFunction> foo = T.NewFunction("(function(a) { return a; })");
15
16  T.CheckCall(T.Val(3), foo, T.Val(3));
17  T.CheckCall(T.Val(3.1), foo, T.Val(3.1));
18  T.CheckCall(foo, foo, foo);
19  T.CheckCall(T.Val("Abba"), foo, T.Val("Abba"));
20}
21
22
23TEST(SimpleCall2) {
24  FunctionTester T("(function(foo,a) { return foo(a); })");
25  Handle<JSFunction> foo = T.NewFunction("(function(a) { return a; })");
26  T.Compile(foo);
27
28  T.CheckCall(T.Val(3), foo, T.Val(3));
29  T.CheckCall(T.Val(3.1), foo, T.Val(3.1));
30  T.CheckCall(foo, foo, foo);
31  T.CheckCall(T.Val("Abba"), foo, T.Val("Abba"));
32}
33
34
35TEST(ConstCall) {
36  FunctionTester T("(function(foo,a) { return foo(a,3); })");
37  Handle<JSFunction> foo = T.NewFunction("(function(a,b) { return a + b; })");
38  T.Compile(foo);
39
40  T.CheckCall(T.Val(6), foo, T.Val(3));
41  T.CheckCall(T.Val(6.1), foo, T.Val(3.1));
42  T.CheckCall(T.Val("function (a,b) { return a + b; }3"), foo, foo);
43  T.CheckCall(T.Val("Abba3"), foo, T.Val("Abba"));
44}
45
46
47TEST(ConstCall2) {
48  FunctionTester T("(function(foo,a) { return foo(a,\"3\"); })");
49  Handle<JSFunction> foo = T.NewFunction("(function(a,b) { return a + b; })");
50  T.Compile(foo);
51
52  T.CheckCall(T.Val("33"), foo, T.Val(3));
53  T.CheckCall(T.Val("3.13"), foo, T.Val(3.1));
54  T.CheckCall(T.Val("function (a,b) { return a + b; }3"), foo, foo);
55  T.CheckCall(T.Val("Abba3"), foo, T.Val("Abba"));
56}
57
58
59TEST(PropertyNamedCall) {
60  FunctionTester T("(function(a,b) { return a.foo(b,23); })");
61  CompileRun("function foo(y,z) { return this.x + y + z; }");
62
63  T.CheckCall(T.Val(32), T.NewObject("({ foo:foo, x:4 })"), T.Val(5));
64  T.CheckCall(T.Val("xy23"), T.NewObject("({ foo:foo, x:'x' })"), T.Val("y"));
65  T.CheckCall(T.nan(), T.NewObject("({ foo:foo, y:0 })"), T.Val(3));
66}
67
68
69TEST(PropertyKeyedCall) {
70  FunctionTester T("(function(a,b) { var f = 'foo'; return a[f](b,23); })");
71  CompileRun("function foo(y,z) { return this.x + y + z; }");
72
73  T.CheckCall(T.Val(32), T.NewObject("({ foo:foo, x:4 })"), T.Val(5));
74  T.CheckCall(T.Val("xy23"), T.NewObject("({ foo:foo, x:'x' })"), T.Val("y"));
75  T.CheckCall(T.nan(), T.NewObject("({ foo:foo, y:0 })"), T.Val(3));
76}
77
78
79TEST(GlobalCall) {
80  FunctionTester T("(function(a,b) { return foo(a,b); })");
81  CompileRun("function foo(a,b) { return a + b + this.c; }");
82  CompileRun("var c = 23;");
83
84  T.CheckCall(T.Val(32), T.Val(4), T.Val(5));
85  T.CheckCall(T.Val("xy23"), T.Val("x"), T.Val("y"));
86  T.CheckCall(T.nan(), T.undefined(), T.Val(3));
87}
88
89
90TEST(LookupCall) {
91  FunctionTester T("(function(a,b) { with (a) { return foo(a,b); } })");
92
93  CompileRun("function f1(a,b) { return a.val + b; }");
94  T.CheckCall(T.Val(5), T.NewObject("({ foo:f1, val:2 })"), T.Val(3));
95  T.CheckCall(T.Val("xy"), T.NewObject("({ foo:f1, val:'x' })"), T.Val("y"));
96
97  CompileRun("function f2(a,b) { return this.val + b; }");
98  T.CheckCall(T.Val(9), T.NewObject("({ foo:f2, val:4 })"), T.Val(5));
99  T.CheckCall(T.Val("xy"), T.NewObject("({ foo:f2, val:'x' })"), T.Val("y"));
100}
101
102
103TEST(MismatchCallTooFew) {
104  FunctionTester T("(function(a,b) { return foo(a,b); })");
105  CompileRun("function foo(a,b,c) { return a + b + c; }");
106
107  T.CheckCall(T.nan(), T.Val(23), T.Val(42));
108  T.CheckCall(T.nan(), T.Val(4.2), T.Val(2.3));
109  T.CheckCall(T.Val("abundefined"), T.Val("a"), T.Val("b"));
110}
111
112
113TEST(MismatchCallTooMany) {
114  FunctionTester T("(function(a,b) { return foo(a,b); })");
115  CompileRun("function foo(a) { return a; }");
116
117  T.CheckCall(T.Val(23), T.Val(23), T.Val(42));
118  T.CheckCall(T.Val(4.2), T.Val(4.2), T.Val(2.3));
119  T.CheckCall(T.Val("a"), T.Val("a"), T.Val("b"));
120}
121
122
123TEST(ConstructorCall) {
124  FunctionTester T("(function(a,b) { return new foo(a,b).value; })");
125  CompileRun("function foo(a,b) { return { value: a + b + this.c }; }");
126  CompileRun("foo.prototype.c = 23;");
127
128  T.CheckCall(T.Val(32), T.Val(4), T.Val(5));
129  T.CheckCall(T.Val("xy23"), T.Val("x"), T.Val("y"));
130  T.CheckCall(T.nan(), T.undefined(), T.Val(3));
131}
132
133
134// TODO(titzer): factor these out into test-runtime-calls.cc
135TEST(RuntimeCallCPP1) {
136  FLAG_allow_natives_syntax = true;
137  FunctionTester T("(function(a) { return %ToBool(a); })");
138
139  T.CheckCall(T.true_value(), T.Val(23), T.undefined());
140  T.CheckCall(T.true_value(), T.Val(4.2), T.undefined());
141  T.CheckCall(T.true_value(), T.Val("str"), T.undefined());
142  T.CheckCall(T.true_value(), T.true_value(), T.undefined());
143  T.CheckCall(T.false_value(), T.false_value(), T.undefined());
144  T.CheckCall(T.false_value(), T.undefined(), T.undefined());
145  T.CheckCall(T.false_value(), T.Val(0.0), T.undefined());
146}
147
148
149TEST(RuntimeCallCPP2) {
150  FLAG_allow_natives_syntax = true;
151  FunctionTester T("(function(a,b) { return %NumberAdd(a, b); })");
152
153  T.CheckCall(T.Val(65), T.Val(42), T.Val(23));
154  T.CheckCall(T.Val(19), T.Val(42), T.Val(-23));
155  T.CheckCall(T.Val(6.5), T.Val(4.2), T.Val(2.3));
156}
157
158
159TEST(RuntimeCallJS) {
160  FLAG_allow_natives_syntax = true;
161  FunctionTester T("(function(a) { return %ToString(a); })");
162
163  T.CheckCall(T.Val("23"), T.Val(23), T.undefined());
164  T.CheckCall(T.Val("4.2"), T.Val(4.2), T.undefined());
165  T.CheckCall(T.Val("str"), T.Val("str"), T.undefined());
166  T.CheckCall(T.Val("true"), T.true_value(), T.undefined());
167  T.CheckCall(T.Val("false"), T.false_value(), T.undefined());
168  T.CheckCall(T.Val("undefined"), T.undefined(), T.undefined());
169}
170
171
172TEST(RuntimeCallInline) {
173  FLAG_allow_natives_syntax = true;
174  FunctionTester T("(function(a) { return %_IsObject(a); })");
175
176  T.CheckCall(T.false_value(), T.Val(23), T.undefined());
177  T.CheckCall(T.false_value(), T.Val(4.2), T.undefined());
178  T.CheckCall(T.false_value(), T.Val("str"), T.undefined());
179  T.CheckCall(T.false_value(), T.true_value(), T.undefined());
180  T.CheckCall(T.false_value(), T.false_value(), T.undefined());
181  T.CheckCall(T.false_value(), T.undefined(), T.undefined());
182  T.CheckCall(T.true_value(), T.NewObject("({})"), T.undefined());
183  T.CheckCall(T.true_value(), T.NewObject("([])"), T.undefined());
184}
185
186
187TEST(RuntimeCallBooleanize) {
188  // TODO(turbofan): %Booleanize will disappear, don't hesitate to remove this
189  // test case, two-argument case is covered by the above test already.
190  FLAG_allow_natives_syntax = true;
191  FunctionTester T("(function(a,b) { return %Booleanize(a, b); })");
192
193  T.CheckCall(T.true_value(), T.Val(-1), T.Val(Token::LT));
194  T.CheckCall(T.false_value(), T.Val(-1), T.Val(Token::EQ));
195  T.CheckCall(T.false_value(), T.Val(-1), T.Val(Token::GT));
196
197  T.CheckCall(T.false_value(), T.Val(0.0), T.Val(Token::LT));
198  T.CheckCall(T.true_value(), T.Val(0.0), T.Val(Token::EQ));
199  T.CheckCall(T.false_value(), T.Val(0.0), T.Val(Token::GT));
200
201  T.CheckCall(T.false_value(), T.Val(1), T.Val(Token::LT));
202  T.CheckCall(T.false_value(), T.Val(1), T.Val(Token::EQ));
203  T.CheckCall(T.true_value(), T.Val(1), T.Val(Token::GT));
204}
205
206
207TEST(EvalCall) {
208  FunctionTester T("(function(a,b) { return eval(a); })");
209  Handle<JSObject> g(T.function->context()->global_object()->global_proxy());
210
211  T.CheckCall(T.Val(23), T.Val("17 + 6"), T.undefined());
212  T.CheckCall(T.Val("'Y'; a"), T.Val("'Y'; a"), T.Val("b-val"));
213  T.CheckCall(T.Val("b-val"), T.Val("'Y'; b"), T.Val("b-val"));
214  T.CheckCall(g, T.Val("this"), T.undefined());
215  T.CheckCall(g, T.Val("'use strict'; this"), T.undefined());
216
217  CompileRun("eval = function(x) { return x; }");
218  T.CheckCall(T.Val("17 + 6"), T.Val("17 + 6"), T.undefined());
219
220  CompileRun("eval = function(x) { return this; }");
221  T.CheckCall(g, T.Val("17 + 6"), T.undefined());
222
223  CompileRun("eval = function(x) { 'use strict'; return this; }");
224  T.CheckCall(T.undefined(), T.Val("17 + 6"), T.undefined());
225}
226
227
228TEST(ReceiverPatching) {
229  // TODO(turbofan): Note that this test only checks that the function prologue
230  // patches an undefined receiver to the global receiver. If this starts to
231  // fail once we fix the calling protocol, just remove this test.
232  FunctionTester T("(function(a) { return this; })");
233  Handle<JSObject> g(T.function->context()->global_object()->global_proxy());
234  T.CheckCall(g, T.undefined());
235}
236
237
238TEST(CallEval) {
239  FunctionTester T(
240      "var x = 42;"
241      "(function () {"
242      "function bar() { return eval('x') };"
243      "return bar;"
244      "})();");
245
246  T.CheckCall(T.Val(42), T.Val("x"), T.undefined());
247}
248
249
250TEST(ContextLoadedFromActivation) {
251  const char* script =
252      "var x = 42;"
253      "(function() {"
254      "  return function () { return x };"
255      "})()";
256
257  // Disable context specialization.
258  FunctionTester T(script);
259  v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
260  v8::Context::Scope scope(context);
261  v8::Local<v8::Value> value = CompileRun(script);
262  i::Handle<i::Object> ofun = v8::Utils::OpenHandle(*value);
263  i::Handle<i::JSFunction> jsfun = Handle<JSFunction>::cast(ofun);
264  jsfun->set_code(T.function->code());
265  context->Global()->Set(v8_str("foo"), v8::Utils::ToLocal(jsfun));
266  CompileRun("var x = 24;");
267  ExpectInt32("foo();", 24);
268}
269
270
271TEST(BuiltinLoadedFromActivation) {
272  const char* script =
273      "var x = 42;"
274      "(function() {"
275      "  return function () { return this; };"
276      "})()";
277
278  // Disable context specialization.
279  FunctionTester T(script);
280  v8::Local<v8::Context> context = v8::Context::New(CcTest::isolate());
281  v8::Context::Scope scope(context);
282  v8::Local<v8::Value> value = CompileRun(script);
283  i::Handle<i::Object> ofun = v8::Utils::OpenHandle(*value);
284  i::Handle<i::JSFunction> jsfun = Handle<JSFunction>::cast(ofun);
285  jsfun->set_code(T.function->code());
286  context->Global()->Set(v8_str("foo"), v8::Utils::ToLocal(jsfun));
287  CompileRun("var x = 24;");
288  ExpectObject("foo()", context->Global());
289}
290