1// Copyright 2009 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 "v8.h"
29
30#include "bootstrapper.h"
31#include "codegen-inl.h"
32#include "compiler.h"
33#include "debug.h"
34#include "liveedit.h"
35#include "oprofile-agent.h"
36#include "prettyprinter.h"
37#include "register-allocator-inl.h"
38#include "rewriter.h"
39#include "runtime.h"
40#include "scopeinfo.h"
41#include "stub-cache.h"
42
43namespace v8 {
44namespace internal {
45
46#define __ ACCESS_MASM(masm_)
47
48#ifdef DEBUG
49
50Comment::Comment(MacroAssembler* masm, const char* msg)
51    : masm_(masm), msg_(msg) {
52  __ RecordComment(msg);
53}
54
55
56Comment::~Comment() {
57  if (msg_[0] == '[') __ RecordComment("]");
58}
59
60#endif  // DEBUG
61
62#undef __
63
64
65CodeGenerator* CodeGeneratorScope::top_ = NULL;
66
67
68DeferredCode::DeferredCode()
69    : masm_(CodeGeneratorScope::Current()->masm()),
70      statement_position_(masm_->current_statement_position()),
71      position_(masm_->current_position()) {
72  ASSERT(statement_position_ != RelocInfo::kNoPosition);
73  ASSERT(position_ != RelocInfo::kNoPosition);
74
75  CodeGeneratorScope::Current()->AddDeferred(this);
76#ifdef DEBUG
77  comment_ = "";
78#endif
79
80  // Copy the register locations from the code generator's frame.
81  // These are the registers that will be spilled on entry to the
82  // deferred code and restored on exit.
83  VirtualFrame* frame = CodeGeneratorScope::Current()->frame();
84  int sp_offset = frame->fp_relative(frame->stack_pointer_);
85  for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
86    int loc = frame->register_location(i);
87    if (loc == VirtualFrame::kIllegalIndex) {
88      registers_[i] = kIgnore;
89    } else if (frame->elements_[loc].is_synced()) {
90      // Needs to be restored on exit but not saved on entry.
91      registers_[i] = frame->fp_relative(loc) | kSyncedFlag;
92    } else {
93      int offset = frame->fp_relative(loc);
94      registers_[i] = (offset < sp_offset) ? kPush : offset;
95    }
96  }
97}
98
99
100void CodeGenerator::ProcessDeferred() {
101  while (!deferred_.is_empty()) {
102    DeferredCode* code = deferred_.RemoveLast();
103    ASSERT(masm_ == code->masm());
104    // Record position of deferred code stub.
105    masm_->RecordStatementPosition(code->statement_position());
106    if (code->position() != RelocInfo::kNoPosition) {
107      masm_->RecordPosition(code->position());
108    }
109    // Generate the code.
110    Comment cmnt(masm_, code->comment());
111    masm_->bind(code->entry_label());
112    code->SaveRegisters();
113    code->Generate();
114    code->RestoreRegisters();
115    masm_->jmp(code->exit_label());
116  }
117}
118
119
120void CodeGenerator::SetFrame(VirtualFrame* new_frame,
121                             RegisterFile* non_frame_registers) {
122  RegisterFile saved_counts;
123  if (has_valid_frame()) {
124    frame_->DetachFromCodeGenerator();
125    // The remaining register reference counts are the non-frame ones.
126    allocator_->SaveTo(&saved_counts);
127  }
128
129  if (new_frame != NULL) {
130    // Restore the non-frame register references that go with the new frame.
131    allocator_->RestoreFrom(non_frame_registers);
132    new_frame->AttachToCodeGenerator();
133  }
134
135  frame_ = new_frame;
136  saved_counts.CopyTo(non_frame_registers);
137}
138
139
140void CodeGenerator::DeleteFrame() {
141  if (has_valid_frame()) {
142    frame_->DetachFromCodeGenerator();
143    frame_ = NULL;
144  }
145}
146
147
148void CodeGenerator::MakeCodePrologue(CompilationInfo* info) {
149#ifdef DEBUG
150  bool print_source = false;
151  bool print_ast = false;
152  bool print_json_ast = false;
153  const char* ftype;
154
155  if (Bootstrapper::IsActive()) {
156    print_source = FLAG_print_builtin_source;
157    print_ast = FLAG_print_builtin_ast;
158    print_json_ast = FLAG_print_builtin_json_ast;
159    ftype = "builtin";
160  } else {
161    print_source = FLAG_print_source;
162    print_ast = FLAG_print_ast;
163    print_json_ast = FLAG_print_json_ast;
164    ftype = "user-defined";
165  }
166
167  if (FLAG_trace_codegen || print_source || print_ast) {
168    PrintF("*** Generate code for %s function: ", ftype);
169    info->function()->name()->ShortPrint();
170    PrintF(" ***\n");
171  }
172
173  if (print_source) {
174    PrintF("--- Source from AST ---\n%s\n",
175           PrettyPrinter().PrintProgram(info->function()));
176  }
177
178  if (print_ast) {
179    PrintF("--- AST ---\n%s\n",
180           AstPrinter().PrintProgram(info->function()));
181  }
182
183  if (print_json_ast) {
184    JsonAstBuilder builder;
185    PrintF("%s", builder.BuildProgram(info->function()));
186  }
187#endif  // DEBUG
188}
189
190
191Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
192                                             Code::Flags flags,
193                                             CompilationInfo* info) {
194  // Allocate and install the code.
195  CodeDesc desc;
196  masm->GetCode(&desc);
197  ZoneScopeInfo sinfo(info->scope());
198  Handle<Code> code =
199      Factory::NewCode(desc, &sinfo, flags, masm->CodeObject());
200
201#ifdef ENABLE_DISASSEMBLER
202  bool print_code = Bootstrapper::IsActive()
203      ? FLAG_print_builtin_code
204      : FLAG_print_code;
205  if (print_code) {
206    // Print the source code if available.
207    Handle<Script> script = info->script();
208    FunctionLiteral* function = info->function();
209    if (!script->IsUndefined() && !script->source()->IsUndefined()) {
210      PrintF("--- Raw source ---\n");
211      StringInputBuffer stream(String::cast(script->source()));
212      stream.Seek(function->start_position());
213      // fun->end_position() points to the last character in the stream. We
214      // need to compensate by adding one to calculate the length.
215      int source_len =
216          function->end_position() - function->start_position() + 1;
217      for (int i = 0; i < source_len; i++) {
218        if (stream.has_more()) PrintF("%c", stream.GetNext());
219      }
220      PrintF("\n\n");
221    }
222    PrintF("--- Code ---\n");
223    code->Disassemble(*function->name()->ToCString());
224  }
225#endif  // ENABLE_DISASSEMBLER
226
227  if (!code.is_null()) {
228    Counters::total_compiled_code_size.Increment(code->instruction_size());
229  }
230  return code;
231}
232
233
234// Generate the code. Takes a function literal, generates code for it, assemble
235// all the pieces into a Code object. This function is only to be called by
236// the compiler.cc code.
237Handle<Code> CodeGenerator::MakeCode(CompilationInfo* info) {
238  LiveEditFunctionTracker live_edit_tracker(info->function());
239  Handle<Script> script = info->script();
240  if (!script->IsUndefined() && !script->source()->IsUndefined()) {
241    int len = String::cast(script->source())->length();
242    Counters::total_old_codegen_source_size.Increment(len);
243  }
244  MakeCodePrologue(info);
245  // Generate code.
246  const int kInitialBufferSize = 4 * KB;
247  MacroAssembler masm(NULL, kInitialBufferSize);
248  CodeGenerator cgen(&masm);
249  CodeGeneratorScope scope(&cgen);
250  live_edit_tracker.RecordFunctionScope(info->function()->scope());
251  cgen.Generate(info);
252  if (cgen.HasStackOverflow()) {
253    ASSERT(!Top::has_pending_exception());
254    return Handle<Code>::null();
255  }
256
257  InLoopFlag in_loop = (cgen.loop_nesting() != 0) ? IN_LOOP : NOT_IN_LOOP;
258  Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop);
259  Handle<Code> result = MakeCodeEpilogue(cgen.masm(), flags, info);
260  live_edit_tracker.RecordFunctionCode(result);
261  return result;
262}
263
264
265#ifdef ENABLE_LOGGING_AND_PROFILING
266
267bool CodeGenerator::ShouldGenerateLog(Expression* type) {
268  ASSERT(type != NULL);
269  if (!Logger::is_logging()) return false;
270  Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
271  if (FLAG_log_regexp) {
272    static Vector<const char> kRegexp = CStrVector("regexp");
273    if (name->IsEqualTo(kRegexp))
274      return true;
275  }
276  return false;
277}
278
279#endif
280
281
282Handle<Code> CodeGenerator::ComputeCallInitialize(
283    int argc,
284    InLoopFlag in_loop) {
285  if (in_loop == IN_LOOP) {
286    // Force the creation of the corresponding stub outside loops,
287    // because it may be used when clearing the ICs later - it is
288    // possible for a series of IC transitions to lose the in-loop
289    // information, and the IC clearing code can't generate a stub
290    // that it needs so we need to ensure it is generated already.
291    ComputeCallInitialize(argc, NOT_IN_LOOP);
292  }
293  CALL_HEAP_FUNCTION(StubCache::ComputeCallInitialize(argc, in_loop), Code);
294}
295
296
297void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
298  int length = declarations->length();
299  int globals = 0;
300  for (int i = 0; i < length; i++) {
301    Declaration* node = declarations->at(i);
302    Variable* var = node->proxy()->var();
303    Slot* slot = var->slot();
304
305    // If it was not possible to allocate the variable at compile
306    // time, we need to "declare" it at runtime to make sure it
307    // actually exists in the local context.
308    if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
309      VisitDeclaration(node);
310    } else {
311      // Count global variables and functions for later processing
312      globals++;
313    }
314  }
315
316  // Return in case of no declared global functions or variables.
317  if (globals == 0) return;
318
319  // Compute array of global variable and function declarations.
320  Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
321  for (int j = 0, i = 0; i < length; i++) {
322    Declaration* node = declarations->at(i);
323    Variable* var = node->proxy()->var();
324    Slot* slot = var->slot();
325
326    if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
327      // Skip - already processed.
328    } else {
329      array->set(j++, *(var->name()));
330      if (node->fun() == NULL) {
331        if (var->mode() == Variable::CONST) {
332          // In case this is const property use the hole.
333          array->set_the_hole(j++);
334        } else {
335          array->set_undefined(j++);
336        }
337      } else {
338        Handle<JSFunction> function =
339            Compiler::BuildBoilerplate(node->fun(), script(), this);
340        // Check for stack-overflow exception.
341        if (HasStackOverflow()) return;
342        array->set(j++, *function);
343      }
344    }
345  }
346
347  // Invoke the platform-dependent code generator to do the actual
348  // declaration the global variables and functions.
349  DeclareGlobals(array);
350}
351
352
353
354// Special cases: These 'runtime calls' manipulate the current
355// frame and are only used 1 or two places, so we generate them
356// inline instead of generating calls to them.  They are used
357// for implementing Function.prototype.call() and
358// Function.prototype.apply().
359CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
360  {&CodeGenerator::GenerateIsSmi, "_IsSmi"},
361  {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
362  {&CodeGenerator::GenerateIsArray, "_IsArray"},
363  {&CodeGenerator::GenerateIsRegExp, "_IsRegExp"},
364  {&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
365  {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
366  {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
367  {&CodeGenerator::GenerateClassOf, "_ClassOf"},
368  {&CodeGenerator::GenerateValueOf, "_ValueOf"},
369  {&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
370  {&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
371  {&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
372  {&CodeGenerator::GenerateLog, "_Log"},
373  {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
374  {&CodeGenerator::GenerateIsObject, "_IsObject"},
375  {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
376  {&CodeGenerator::GenerateIsUndetectableObject, "_IsUndetectableObject"},
377  {&CodeGenerator::GenerateStringAdd, "_StringAdd"},
378  {&CodeGenerator::GenerateSubString, "_SubString"},
379  {&CodeGenerator::GenerateStringCompare, "_StringCompare"},
380  {&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
381  {&CodeGenerator::GenerateNumberToString, "_NumberToString"},
382  {&CodeGenerator::GenerateMathSin, "_Math_sin"},
383  {&CodeGenerator::GenerateMathCos, "_Math_cos"},
384};
385
386
387CodeGenerator::InlineRuntimeLUT* CodeGenerator::FindInlineRuntimeLUT(
388    Handle<String> name) {
389  const int entries_count =
390      sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
391  for (int i = 0; i < entries_count; i++) {
392    InlineRuntimeLUT* entry = &kInlineRuntimeLUT[i];
393    if (name->IsEqualTo(CStrVector(entry->name))) {
394      return entry;
395    }
396  }
397  return NULL;
398}
399
400
401bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
402  ZoneList<Expression*>* args = node->arguments();
403  Handle<String> name = node->name();
404  if (name->length() > 0 && name->Get(0) == '_') {
405    InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name);
406    if (entry != NULL) {
407      ((*this).*(entry->method))(args);
408      return true;
409    }
410  }
411  return false;
412}
413
414
415bool CodeGenerator::PatchInlineRuntimeEntry(Handle<String> name,
416    const CodeGenerator::InlineRuntimeLUT& new_entry,
417    CodeGenerator::InlineRuntimeLUT* old_entry) {
418  InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name);
419  if (entry == NULL) return false;
420  if (old_entry != NULL) {
421    old_entry->name = entry->name;
422    old_entry->method = entry->method;
423  }
424  entry->name = new_entry.name;
425  entry->method = new_entry.method;
426  return true;
427}
428
429
430// Simple condition analysis.  ALWAYS_TRUE and ALWAYS_FALSE represent a
431// known result for the test expression, with no side effects.
432CodeGenerator::ConditionAnalysis CodeGenerator::AnalyzeCondition(
433    Expression* cond) {
434  if (cond == NULL) return ALWAYS_TRUE;
435
436  Literal* lit = cond->AsLiteral();
437  if (lit == NULL) return DONT_KNOW;
438
439  if (lit->IsTrue()) {
440    return ALWAYS_TRUE;
441  } else if (lit->IsFalse()) {
442    return ALWAYS_FALSE;
443  }
444
445  return DONT_KNOW;
446}
447
448
449void CodeGenerator::RecordPositions(MacroAssembler* masm, int pos) {
450  if (pos != RelocInfo::kNoPosition) {
451    masm->RecordStatementPosition(pos);
452    masm->RecordPosition(pos);
453  }
454}
455
456
457void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) {
458  if (FLAG_debug_info) RecordPositions(masm(), fun->start_position());
459}
460
461
462void CodeGenerator::CodeForReturnPosition(FunctionLiteral* fun) {
463  if (FLAG_debug_info) RecordPositions(masm(), fun->end_position());
464}
465
466
467void CodeGenerator::CodeForStatementPosition(Statement* stmt) {
468  if (FLAG_debug_info) RecordPositions(masm(), stmt->statement_pos());
469}
470
471void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) {
472  if (FLAG_debug_info) RecordPositions(masm(), stmt->condition_position());
473}
474
475void CodeGenerator::CodeForSourcePosition(int pos) {
476  if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
477    masm()->RecordPosition(pos);
478  }
479}
480
481
482const char* GenericUnaryOpStub::GetName() {
483  switch (op_) {
484    case Token::SUB:
485      return overwrite_
486          ? "GenericUnaryOpStub_SUB_Overwrite"
487          : "GenericUnaryOpStub_SUB_Alloc";
488    case Token::BIT_NOT:
489      return overwrite_
490          ? "GenericUnaryOpStub_BIT_NOT_Overwrite"
491          : "GenericUnaryOpStub_BIT_NOT_Alloc";
492    default:
493      UNREACHABLE();
494      return "<unknown>";
495  }
496}
497
498
499void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
500  switch (type_) {
501    case READ_LENGTH: GenerateReadLength(masm); break;
502    case READ_ELEMENT: GenerateReadElement(masm); break;
503    case NEW_OBJECT: GenerateNewObject(masm); break;
504  }
505}
506
507
508int CEntryStub::MinorKey() {
509  ASSERT(result_size_ <= 2);
510#ifdef _WIN64
511  return ExitFrameModeBits::encode(mode_)
512         | IndirectResultBits::encode(result_size_ > 1);
513#else
514  return ExitFrameModeBits::encode(mode_);
515#endif
516}
517
518
519bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
520  Object* cache = info()->load_stub_cache();
521  if (cache->IsUndefined()) {
522    return false;
523  } else {
524    *code_out = Code::cast(cache);
525    return true;
526  }
527}
528
529
530void ApiGetterEntryStub::SetCustomCache(Code* value) {
531  info()->set_load_stub_cache(value);
532}
533
534
535} }  // namespace v8::internal
536