v8  3.14.5(node0.10.28)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-compiler.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include <stdlib.h>
29 #include <wchar.h>
30 
31 #include "v8.h"
32 
33 #include "compiler.h"
34 #include "disasm.h"
35 #include "disassembler.h"
36 #include "execution.h"
37 #include "factory.h"
38 #include "platform.h"
39 #include "cctest.h"
40 
41 using namespace v8::internal;
42 
44 
45 // --- P r i n t E x t e n s i o n ---
46 
47 class PrintExtension : public v8::Extension {
48  public:
49  PrintExtension() : v8::Extension("v8/print", kSource) { }
50  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
52  static v8::Handle<v8::Value> Print(const v8::Arguments& args);
53  private:
54  static const char* kSource;
55 };
56 
57 
58 const char* PrintExtension::kSource = "native function print();";
59 
60 
64 }
65 
66 
68  for (int i = 0; i < args.Length(); i++) {
69  if (i != 0) printf(" ");
70  v8::HandleScope scope;
71  v8::String::Utf8Value str(args[i]);
72  if (*str == NULL) return v8::Undefined();
73  printf("%s", *str);
74  }
75  printf("\n");
76  return v8::Undefined();
77 }
78 
79 
80 static PrintExtension kPrintExtension;
81 v8::DeclareExtension kPrintExtensionDeclaration(&kPrintExtension);
82 
83 
84 static void InitializeVM() {
85  if (env.IsEmpty()) {
86  v8::HandleScope scope;
87  const char* extensions[] = { "v8/print", "v8/gc" };
88  v8::ExtensionConfiguration config(2, extensions);
89  env = v8::Context::New(&config);
90  }
91  v8::HandleScope scope;
92  env->Enter();
93 }
94 
95 
96 static MaybeObject* GetGlobalProperty(const char* name) {
97  Handle<String> symbol = FACTORY->LookupAsciiSymbol(name);
98  return Isolate::Current()->context()->global_object()->GetProperty(*symbol);
99 }
100 
101 
102 static void SetGlobalProperty(const char* name, Object* value) {
103  Handle<Object> object(value);
104  Handle<String> symbol = FACTORY->LookupAsciiSymbol(name);
105  Handle<JSObject> global(Isolate::Current()->context()->global_object());
106  SetProperty(global, symbol, object, NONE, kNonStrictMode);
107 }
108 
109 
110 static Handle<JSFunction> Compile(const char* source) {
111  Handle<String> source_code(FACTORY->NewStringFromUtf8(CStrVector(source)));
112  Handle<SharedFunctionInfo> shared_function =
113  Compiler::Compile(source_code,
114  Handle<String>(),
115  0,
116  0,
117  Handle<Context>(Isolate::Current()->native_context()),
118  NULL,
119  NULL,
122  return FACTORY->NewFunctionFromSharedFunctionInfo(shared_function,
123  Isolate::Current()->native_context());
124 }
125 
126 
127 static double Inc(int x) {
128  const char* source = "result = %d + 1;";
130  OS::SNPrintF(buffer, source, x);
131 
132  Handle<JSFunction> fun = Compile(buffer.start());
133  if (fun.is_null()) return -1;
134 
135  bool has_pending_exception;
136  Handle<JSObject> global(Isolate::Current()->context()->global_object());
137  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
138  CHECK(!has_pending_exception);
139  return GetGlobalProperty("result")->ToObjectChecked()->Number();
140 }
141 
142 
143 TEST(Inc) {
144  InitializeVM();
145  v8::HandleScope scope;
146  CHECK_EQ(4.0, Inc(3));
147 }
148 
149 
150 static double Add(int x, int y) {
151  Handle<JSFunction> fun = Compile("result = x + y;");
152  if (fun.is_null()) return -1;
153 
154  SetGlobalProperty("x", Smi::FromInt(x));
155  SetGlobalProperty("y", Smi::FromInt(y));
156  bool has_pending_exception;
157  Handle<JSObject> global(Isolate::Current()->context()->global_object());
158  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
159  CHECK(!has_pending_exception);
160  return GetGlobalProperty("result")->ToObjectChecked()->Number();
161 }
162 
163 
164 TEST(Add) {
165  InitializeVM();
166  v8::HandleScope scope;
167  CHECK_EQ(5.0, Add(2, 3));
168 }
169 
170 
171 static double Abs(int x) {
172  Handle<JSFunction> fun = Compile("if (x < 0) result = -x; else result = x;");
173  if (fun.is_null()) return -1;
174 
175  SetGlobalProperty("x", Smi::FromInt(x));
176  bool has_pending_exception;
177  Handle<JSObject> global(Isolate::Current()->context()->global_object());
178  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
179  CHECK(!has_pending_exception);
180  return GetGlobalProperty("result")->ToObjectChecked()->Number();
181 }
182 
183 
184 TEST(Abs) {
185  InitializeVM();
186  v8::HandleScope scope;
187  CHECK_EQ(3.0, Abs(-3));
188 }
189 
190 
191 static double Sum(int n) {
192  Handle<JSFunction> fun =
193  Compile("s = 0; while (n > 0) { s += n; n -= 1; }; result = s;");
194  if (fun.is_null()) return -1;
195 
196  SetGlobalProperty("n", Smi::FromInt(n));
197  bool has_pending_exception;
198  Handle<JSObject> global(Isolate::Current()->context()->global_object());
199  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
200  CHECK(!has_pending_exception);
201  return GetGlobalProperty("result")->ToObjectChecked()->Number();
202 }
203 
204 
205 TEST(Sum) {
206  InitializeVM();
207  v8::HandleScope scope;
208  CHECK_EQ(5050.0, Sum(100));
209 }
210 
211 
213  InitializeVM();
214  v8::HandleScope scope;
215  const char* source = "for (n = 0; n < 100; ++n) print(n, 1, 2);";
216  Handle<JSFunction> fun = Compile(source);
217  if (fun.is_null()) return;
218  bool has_pending_exception;
219  Handle<JSObject> global(Isolate::Current()->context()->global_object());
220  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
221  CHECK(!has_pending_exception);
222 }
223 
224 
225 // The following test method stems from my coding efforts today. It
226 // tests all the functionality I have added to the compiler today
227 TEST(Stuff) {
228  InitializeVM();
229  v8::HandleScope scope;
230  const char* source =
231  "r = 0;\n"
232  "a = new Object;\n"
233  "if (a == a) r+=1;\n" // 1
234  "if (a != new Object()) r+=2;\n" // 2
235  "a.x = 42;\n"
236  "if (a.x == 42) r+=4;\n" // 4
237  "function foo() { var x = 87; return x; }\n"
238  "if (foo() == 87) r+=8;\n" // 8
239  "function bar() { var x; x = 99; return x; }\n"
240  "if (bar() == 99) r+=16;\n" // 16
241  "function baz() { var x = 1, y, z = 2; y = 3; return x + y + z; }\n"
242  "if (baz() == 6) r+=32;\n" // 32
243  "function Cons0() { this.x = 42; this.y = 87; }\n"
244  "if (new Cons0().x == 42) r+=64;\n" // 64
245  "if (new Cons0().y == 87) r+=128;\n" // 128
246  "function Cons2(x, y) { this.sum = x + y; }\n"
247  "if (new Cons2(3,4).sum == 7) r+=256;"; // 256
248 
249  Handle<JSFunction> fun = Compile(source);
250  CHECK(!fun.is_null());
251  bool has_pending_exception;
252  Handle<JSObject> global(Isolate::Current()->context()->global_object());
253  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
254  CHECK(!has_pending_exception);
255  CHECK_EQ(511.0, GetGlobalProperty("r")->ToObjectChecked()->Number());
256 }
257 
258 
259 TEST(UncaughtThrow) {
260  InitializeVM();
261  v8::HandleScope scope;
262 
263  const char* source = "throw 42;";
264  Handle<JSFunction> fun = Compile(source);
265  CHECK(!fun.is_null());
266  bool has_pending_exception;
267  Handle<JSObject> global(Isolate::Current()->context()->global_object());
268  Execution::Call(fun, global, 0, NULL, &has_pending_exception);
269  CHECK(has_pending_exception);
270  CHECK_EQ(42.0, Isolate::Current()->pending_exception()->
271  ToObjectChecked()->Number());
272 }
273 
274 
275 // Tests calling a builtin function from C/C++ code, and the builtin function
276 // performs GC. It creates a stack frame looks like following:
277 // | C (PerformGC) |
278 // | JS-to-C |
279 // | JS |
280 // | C-to-JS |
281 TEST(C2JSFrames) {
282  InitializeVM();
283  v8::HandleScope scope;
284 
285  const char* source = "function foo(a) { gc(), print(a); }";
286 
287  Handle<JSFunction> fun0 = Compile(source);
288  CHECK(!fun0.is_null());
289 
290  // Run the generated code to populate the global object with 'foo'.
291  bool has_pending_exception;
292  Handle<JSObject> global(Isolate::Current()->context()->global_object());
293  Execution::Call(fun0, global, 0, NULL, &has_pending_exception);
294  CHECK(!has_pending_exception);
295 
296  Object* foo_symbol = FACTORY->LookupAsciiSymbol("foo")->ToObjectChecked();
297  MaybeObject* fun1_object = Isolate::Current()->context()->global_object()->
298  GetProperty(String::cast(foo_symbol));
299  Handle<Object> fun1(fun1_object->ToObjectChecked());
300  CHECK(fun1->IsJSFunction());
301 
302  Handle<Object> argv[] = { FACTORY->LookupAsciiSymbol("hello") };
304  global,
305  ARRAY_SIZE(argv),
306  argv,
307  &has_pending_exception);
308  CHECK(!has_pending_exception);
309 }
310 
311 
312 // Regression 236. Calling InitLineEnds on a Script with undefined
313 // source resulted in crash.
314 TEST(Regression236) {
315  InitializeVM();
316  v8::HandleScope scope;
317 
318  Handle<Script> script = FACTORY->NewScript(FACTORY->empty_string());
319  script->set_source(HEAP->undefined_value());
320  CHECK_EQ(-1, GetScriptLineNumber(script, 0));
321  CHECK_EQ(-1, GetScriptLineNumber(script, 100));
322  CHECK_EQ(-1, GetScriptLineNumber(script, -1));
323 }
324 
325 
327  LocalContext env;
328  v8::HandleScope scope;
330  const char function_f[] = "function f() {}";
331  const int max_rows = 1000;
332  const int buffer_size = max_rows + sizeof(function_f);
333  ScopedVector<char> buffer(buffer_size);
334  memset(buffer.start(), '\n', buffer_size - 1);
335  buffer[buffer_size - 1] = '\0';
336 
337  for (int i = 0; i < max_rows; ++i) {
338  if (i > 0)
339  buffer[i - 1] = '\n';
340  memcpy(&buffer[i], function_f, sizeof(function_f) - 1);
341  v8::Handle<v8::String> script_body = v8::String::New(buffer.start());
342  v8::Script::Compile(script_body, &origin)->Run();
344  env->Global()->Get(v8::String::New("f")));
345  CHECK_EQ(i, f->GetScriptLineNumber());
346  }
347 }
348 
349 
350 // Test that optimized code for different closures is actually shared
351 // immediately by the FastNewClosureStub when run in the same context.
352 TEST(OptimizedCodeSharing) {
353  // Skip test if --cache-optimized-code is not activated by default because
354  // FastNewClosureStub that is baked into the snapshot is incorrect.
355  if (!FLAG_cache_optimized_code) return;
356  FLAG_allow_natives_syntax = true;
357  InitializeVM();
358  v8::HandleScope scope;
359  for (int i = 0; i < 10; i++) {
360  LocalContext env;
361  env->Global()->Set(v8::String::New("x"), v8::Integer::New(i));
362  CompileRun("function MakeClosure() {"
363  " return function() { return x; };"
364  "}"
365  "var closure0 = MakeClosure();"
366  "%DebugPrint(closure0());"
367  "%OptimizeFunctionOnNextCall(closure0);"
368  "%DebugPrint(closure0());"
369  "var closure1 = MakeClosure();"
370  "var closure2 = MakeClosure();");
371  Handle<JSFunction> fun1 = v8::Utils::OpenHandle(
372  *v8::Local<v8::Function>::Cast(env->Global()->Get(v8_str("closure1"))));
373  Handle<JSFunction> fun2 = v8::Utils::OpenHandle(
374  *v8::Local<v8::Function>::Cast(env->Global()->Get(v8_str("closure2"))));
375  CHECK(fun1->IsOptimized() || !fun1->IsOptimizable());
376  CHECK(fun2->IsOptimized() || !fun2->IsOptimizable());
377  CHECK_EQ(fun1->code(), fun2->code());
378  }
379 }
380 
381 
382 #ifdef ENABLE_DISASSEMBLER
383 static Handle<JSFunction> GetJSFunction(v8::Handle<v8::Object> obj,
384  const char* property_name) {
386  v8::Local<v8::Function>::Cast(obj->Get(v8_str(property_name)));
387  return v8::Utils::OpenHandle(*fun);
388 }
389 
390 
391 static void CheckCodeForUnsafeLiteral(Handle<JSFunction> f) {
392  // Create a disassembler with default name lookup.
393  disasm::NameConverter name_converter;
394  disasm::Disassembler d(name_converter);
395 
396  if (f->code()->kind() == Code::FUNCTION) {
397  Address pc = f->code()->instruction_start();
398  int decode_size =
399  Min(f->code()->instruction_size(),
400  static_cast<int>(f->code()->stack_check_table_offset()));
401  Address end = pc + decode_size;
402 
405  Smi* smi = Smi::FromInt(12345678);
406  OS::SNPrintF(smi_hex_buffer, "0x%lx", reinterpret_cast<intptr_t>(smi));
407  while (pc < end) {
408  int num_const = d.ConstantPoolSizeAt(pc);
409  if (num_const >= 0) {
410  pc += (num_const + 1) * kPointerSize;
411  } else {
412  pc += d.InstructionDecode(decode_buffer, pc);
413  CHECK(strstr(decode_buffer.start(), smi_hex_buffer.start()) == NULL);
414  }
415  }
416  }
417 }
418 
419 
420 TEST(SplitConstantsInFullCompiler) {
421  v8::HandleScope scope;
422  LocalContext env;
423 
424  CompileRun("function f() { a = 12345678 }; f();");
425  CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
426  CompileRun("function f(x) { a = 12345678 + x}; f(1);");
427  CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
428  CompileRun("function f(x) { var arguments = 1; x += 12345678}; f(1);");
429  CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
430  CompileRun("function f(x) { var arguments = 1; x = 12345678}; f(1);");
431  CheckCodeForUnsafeLiteral(GetJSFunction(env->Global(), "f"));
432 }
433 #endif
byte * Address
Definition: globals.h:157
static Local< Script > Compile(Handle< String > source, ScriptOrigin *origin=NULL, ScriptData *pre_data=NULL, Handle< String > script_data=Handle< String >())
Definition: api.cc:1568
#define CHECK_EQ(expected, value)
Definition: checks.h:219
static Local< FunctionTemplate > New(InvocationCallback callback=0, Handle< Value > data=Handle< Value >(), Handle< Signature > signature=Handle< Signature >())
Definition: api.cc:951
static String * cast(Object *obj)
V8EXPORT Local< Value > Get(Handle< Value > key)
Definition: api.cc:2853
static Smi * FromInt(int value)
Definition: objects-inl.h:981
static V8EXPORT Local< String > New(const char *data, int length=-1)
Definition: api.cc:4779
v8::Handle< v8::Value > Print(const v8::Arguments &args)
#define CHECK(condition)
Definition: checks.h:56
Handle< Object > GetProperty(Handle< JSReceiver > obj, const char *name)
Definition: handles.cc:282
T * start() const
Definition: utils.h:390
virtual v8::Handle< v8::FunctionTemplate > GetNativeFunction(v8::Handle< v8::String > name)
const int kPointerSize
Definition: globals.h:220
Handle< Object > SetProperty(Handle< Object > object, Handle< Object > key, Handle< Object > value, PropertyAttributes attributes, StrictModeFlag strict_mode)
Definition: handles.cc:232
int Length() const
Definition: v8.h:4318
Local< Object > Global()
Definition: api.cc:4570
const Register pc
Definition: v8.h:105
static Handle< Object > Call(Handle< Object > callable, Handle< Object > receiver, int argc, Handle< Object > argv[], bool *pending_exception, bool convert_receiver=false)
Definition: execution.cc:150
Vector< const char > CStrVector(const char *data)
Definition: utils.h:526
static Local< T > Cast(Local< S > that)
Definition: v8.h:282
static int SNPrintF(Vector< char > str, const char *format,...)
int GetScriptLineNumber(Handle< Script > script, int code_pos)
Definition: handles.cc:479
static Handle< SharedFunctionInfo > Compile(Handle< String > source, Handle< Object > script_name, int line_offset, int column_offset, Handle< Context > context, v8::Extension *extension, ScriptDataImpl *pre_data, Handle< Object > script_data, NativesFlag is_natives_code)
Definition: compiler.cc:542
bool is_null() const
Definition: handles.h:87
#define HEAP
Definition: isolate.h:1433
static V8EXPORT Local< Integer > New(int32_t value)
Definition: api.cc:5228
V8EXPORT int GetScriptLineNumber() const
Definition: api.cc:3714
Handle< Primitive > V8EXPORT Undefined()
Definition: api.cc:549
bool IsEmpty() const
Definition: v8.h:209
#define FACTORY
Definition: isolate.h:1434
static v8::Handle< v8::Value > Print(const v8::Arguments &args)
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of MIPS FPU instructions if NULL
Definition: flags.cc:301
static Persistent< Context > New(ExtensionConfiguration *extensions=NULL, Handle< ObjectTemplate > global_template=Handle< ObjectTemplate >(), Handle< Value > global_object=Handle< Value >())
Definition: api.cc:4411
T Min(T a, T b)
Definition: utils.h:229
#define ARRAY_SIZE(a)
Definition: globals.h:281
Definition: v8.h:106