codegen.cc revision 44f0eee88ff00398ff7f715fab053374d808c90d
1// Copyright 2010 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 "prettyprinter.h"
35#include "register-allocator-inl.h"
36#include "rewriter.h"
37#include "runtime.h"
38#include "scopeinfo.h"
39#include "stub-cache.h"
40#include "virtual-frame-inl.h"
41
42namespace v8 {
43namespace internal {
44
45#define __ ACCESS_MASM(masm_)
46
47#ifdef DEBUG
48
49Comment::Comment(MacroAssembler* masm, const char* msg)
50    : masm_(masm), msg_(msg) {
51  __ RecordComment(msg);
52}
53
54
55Comment::~Comment() {
56  if (msg_[0] == '[') __ RecordComment("]");
57}
58
59#endif  // DEBUG
60
61#undef __
62
63
64void CodeGenerator::ProcessDeferred() {
65  while (!deferred_.is_empty()) {
66    DeferredCode* code = deferred_.RemoveLast();
67    ASSERT(masm_ == code->masm());
68    // Record position of deferred code stub.
69    masm_->positions_recorder()->RecordStatementPosition(
70        code->statement_position());
71    if (code->position() != RelocInfo::kNoPosition) {
72      masm_->positions_recorder()->RecordPosition(code->position());
73    }
74    // Generate the code.
75    Comment cmnt(masm_, code->comment());
76    masm_->bind(code->entry_label());
77    if (code->AutoSaveAndRestore()) {
78      code->SaveRegisters();
79    }
80    code->Generate();
81    if (code->AutoSaveAndRestore()) {
82      code->RestoreRegisters();
83      code->Exit();
84    }
85  }
86}
87
88
89void DeferredCode::Exit() {
90  masm_->jmp(exit_label());
91}
92
93
94void CodeGenerator::SetFrame(VirtualFrame* new_frame,
95                             RegisterFile* non_frame_registers) {
96  RegisterFile saved_counts;
97  if (has_valid_frame()) {
98    frame_->DetachFromCodeGenerator();
99    // The remaining register reference counts are the non-frame ones.
100    allocator_->SaveTo(&saved_counts);
101  }
102
103  if (new_frame != NULL) {
104    // Restore the non-frame register references that go with the new frame.
105    allocator_->RestoreFrom(non_frame_registers);
106    new_frame->AttachToCodeGenerator();
107  }
108
109  frame_ = new_frame;
110  saved_counts.CopyTo(non_frame_registers);
111}
112
113
114void CodeGenerator::DeleteFrame() {
115  if (has_valid_frame()) {
116    frame_->DetachFromCodeGenerator();
117    frame_ = NULL;
118  }
119}
120
121
122void CodeGenerator::MakeCodePrologue(CompilationInfo* info) {
123#ifdef DEBUG
124  bool print_source = false;
125  bool print_ast = false;
126  bool print_json_ast = false;
127  const char* ftype;
128
129  if (Isolate::Current()->bootstrapper()->IsActive()) {
130    print_source = FLAG_print_builtin_source;
131    print_ast = FLAG_print_builtin_ast;
132    print_json_ast = FLAG_print_builtin_json_ast;
133    ftype = "builtin";
134  } else {
135    print_source = FLAG_print_source;
136    print_ast = FLAG_print_ast;
137    print_json_ast = FLAG_print_json_ast;
138    Vector<const char> filter = CStrVector(FLAG_hydrogen_filter);
139    if (print_source && !filter.is_empty()) {
140      print_source = info->function()->name()->IsEqualTo(filter);
141    }
142    if (print_ast && !filter.is_empty()) {
143      print_ast = info->function()->name()->IsEqualTo(filter);
144    }
145    if (print_json_ast && !filter.is_empty()) {
146      print_json_ast = info->function()->name()->IsEqualTo(filter);
147    }
148    ftype = "user-defined";
149  }
150
151  if (FLAG_trace_codegen || print_source || print_ast) {
152    PrintF("*** Generate code for %s function: ", ftype);
153    info->function()->name()->ShortPrint();
154    PrintF(" ***\n");
155  }
156
157  if (print_source) {
158    PrintF("--- Source from AST ---\n%s\n",
159           PrettyPrinter().PrintProgram(info->function()));
160  }
161
162  if (print_ast) {
163    PrintF("--- AST ---\n%s\n",
164           AstPrinter().PrintProgram(info->function()));
165  }
166
167  if (print_json_ast) {
168    JsonAstBuilder builder;
169    PrintF("%s", builder.BuildProgram(info->function()));
170  }
171#endif  // DEBUG
172}
173
174
175Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
176                                             Code::Flags flags,
177                                             CompilationInfo* info) {
178  Isolate* isolate = info->isolate();
179
180  // Allocate and install the code.
181  CodeDesc desc;
182  masm->GetCode(&desc);
183  Handle<Code> code =
184      isolate->factory()->NewCode(desc, flags, masm->CodeObject());
185
186  if (!code.is_null()) {
187    isolate->counters()->total_compiled_code_size()->Increment(
188        code->instruction_size());
189  }
190  return code;
191}
192
193
194void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
195#ifdef ENABLE_DISASSEMBLER
196  bool print_code = Isolate::Current()->bootstrapper()->IsActive()
197      ? FLAG_print_builtin_code
198      : (FLAG_print_code || (info->IsOptimizing() && FLAG_print_opt_code));
199  Vector<const char> filter = CStrVector(FLAG_hydrogen_filter);
200  FunctionLiteral* function = info->function();
201  bool match = filter.is_empty() || function->debug_name()->IsEqualTo(filter);
202  if (print_code && match) {
203    // Print the source code if available.
204    Handle<Script> script = info->script();
205    if (!script->IsUndefined() && !script->source()->IsUndefined()) {
206      PrintF("--- Raw source ---\n");
207      StringInputBuffer stream(String::cast(script->source()));
208      stream.Seek(function->start_position());
209      // fun->end_position() points to the last character in the stream. We
210      // need to compensate by adding one to calculate the length.
211      int source_len =
212          function->end_position() - function->start_position() + 1;
213      for (int i = 0; i < source_len; i++) {
214        if (stream.has_more()) PrintF("%c", stream.GetNext());
215      }
216      PrintF("\n\n");
217    }
218    if (info->IsOptimizing()) {
219      if (FLAG_print_unopt_code) {
220        PrintF("--- Unoptimized code ---\n");
221        info->closure()->shared()->code()->Disassemble(
222            *function->debug_name()->ToCString());
223      }
224      PrintF("--- Optimized code ---\n");
225    } else {
226      PrintF("--- Code ---\n");
227    }
228    code->Disassemble(*function->debug_name()->ToCString());
229  }
230#endif  // ENABLE_DISASSEMBLER
231}
232
233
234// Generate the code.  Compile the AST and assemble all the pieces into a
235// Code object.
236bool CodeGenerator::MakeCode(CompilationInfo* info) {
237  // When using Crankshaft the classic backend should never be used.
238  ASSERT(!V8::UseCrankshaft());
239  Handle<Script> script = info->script();
240  if (!script->IsUndefined() && !script->source()->IsUndefined()) {
241    int len = String::cast(script->source())->length();
242    Counters* counters = info->isolate()->counters();
243    counters->total_old_codegen_source_size()->Increment(len);
244  }
245  if (FLAG_trace_codegen) {
246    PrintF("Classic Compiler - ");
247  }
248  MakeCodePrologue(info);
249  // Generate code.
250  const int kInitialBufferSize = 4 * KB;
251  MacroAssembler masm(NULL, kInitialBufferSize);
252#ifdef ENABLE_GDB_JIT_INTERFACE
253  masm.positions_recorder()->StartGDBJITLineInfoRecording();
254#endif
255  CodeGenerator cgen(&masm);
256  CodeGeneratorScope scope(Isolate::Current(), &cgen);
257  cgen.Generate(info);
258  if (cgen.HasStackOverflow()) {
259    ASSERT(!Isolate::Current()->has_pending_exception());
260    return false;
261  }
262
263  InLoopFlag in_loop = info->is_in_loop() ? IN_LOOP : NOT_IN_LOOP;
264  Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop);
265  Handle<Code> code = MakeCodeEpilogue(cgen.masm(), flags, info);
266  // There is no stack check table in code generated by the classic backend.
267  code->SetNoStackCheckTable();
268  CodeGenerator::PrintCode(code, info);
269  info->SetCode(code);  // May be an empty handle.
270#ifdef ENABLE_GDB_JIT_INTERFACE
271  if (FLAG_gdbjit && !code.is_null()) {
272    GDBJITLineInfo* lineinfo =
273        masm.positions_recorder()->DetachGDBJITLineInfo();
274
275    GDBJIT(RegisterDetailedLineInfo(*code, lineinfo));
276  }
277#endif
278  return !code.is_null();
279}
280
281
282#ifdef ENABLE_LOGGING_AND_PROFILING
283
284
285static Vector<const char> kRegexp = CStrVector("regexp");
286
287
288bool CodeGenerator::ShouldGenerateLog(Expression* type) {
289  ASSERT(type != NULL);
290  if (!LOGGER->is_logging() && !CpuProfiler::is_profiling()) return false;
291  Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
292  if (FLAG_log_regexp) {
293    if (name->IsEqualTo(kRegexp))
294      return true;
295  }
296  return false;
297}
298
299#endif
300
301
302void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
303  int length = declarations->length();
304  int globals = 0;
305  for (int i = 0; i < length; i++) {
306    Declaration* node = declarations->at(i);
307    Variable* var = node->proxy()->var();
308    Slot* slot = var->AsSlot();
309
310    // If it was not possible to allocate the variable at compile
311    // time, we need to "declare" it at runtime to make sure it
312    // actually exists in the local context.
313    if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
314      VisitDeclaration(node);
315    } else {
316      // Count global variables and functions for later processing
317      globals++;
318    }
319  }
320
321  // Return in case of no declared global functions or variables.
322  if (globals == 0) return;
323
324  // Compute array of global variable and function declarations.
325  Handle<FixedArray> array = FACTORY->NewFixedArray(2 * globals, TENURED);
326  for (int j = 0, i = 0; i < length; i++) {
327    Declaration* node = declarations->at(i);
328    Variable* var = node->proxy()->var();
329    Slot* slot = var->AsSlot();
330
331    if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
332      // Skip - already processed.
333    } else {
334      array->set(j++, *(var->name()));
335      if (node->fun() == NULL) {
336        if (var->mode() == Variable::CONST) {
337          // In case this is const property use the hole.
338          array->set_the_hole(j++);
339        } else {
340          array->set_undefined(j++);
341        }
342      } else {
343        Handle<SharedFunctionInfo> function =
344            Compiler::BuildFunctionInfo(node->fun(), script());
345        // Check for stack-overflow exception.
346        if (function.is_null()) {
347          SetStackOverflow();
348          return;
349        }
350        array->set(j++, *function);
351      }
352    }
353  }
354
355  // Invoke the platform-dependent code generator to do the actual
356  // declaration the global variables and functions.
357  DeclareGlobals(array);
358}
359
360
361void CodeGenerator::VisitIncrementOperation(IncrementOperation* expr) {
362  UNREACHABLE();
363}
364
365
366// Lookup table for code generators for special runtime calls which are
367// generated inline.
368#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize)          \
369    &CodeGenerator::Generate##Name,
370
371const CodeGenerator::InlineFunctionGenerator
372    CodeGenerator::kInlineFunctionGenerators[] = {
373        INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
374        INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
375};
376#undef INLINE_FUNCTION_GENERATOR_ADDRESS
377
378
379bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
380  ZoneList<Expression*>* args = node->arguments();
381  Handle<String> name = node->name();
382  const Runtime::Function* function = node->function();
383  if (function != NULL && function->intrinsic_type == Runtime::INLINE) {
384    int lookup_index = static_cast<int>(function->function_id) -
385        static_cast<int>(Runtime::kFirstInlineFunction);
386    ASSERT(lookup_index >= 0);
387    ASSERT(static_cast<size_t>(lookup_index) <
388           ARRAY_SIZE(kInlineFunctionGenerators));
389    InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
390    (this->*generator)(args);
391    return true;
392  }
393  return false;
394}
395
396
397// Simple condition analysis.  ALWAYS_TRUE and ALWAYS_FALSE represent a
398// known result for the test expression, with no side effects.
399CodeGenerator::ConditionAnalysis CodeGenerator::AnalyzeCondition(
400    Expression* cond) {
401  if (cond == NULL) return ALWAYS_TRUE;
402
403  Literal* lit = cond->AsLiteral();
404  if (lit == NULL) return DONT_KNOW;
405
406  if (lit->IsTrue()) {
407    return ALWAYS_TRUE;
408  } else if (lit->IsFalse()) {
409    return ALWAYS_FALSE;
410  }
411
412  return DONT_KNOW;
413}
414
415
416bool CodeGenerator::RecordPositions(MacroAssembler* masm,
417                                    int pos,
418                                    bool right_here) {
419  if (pos != RelocInfo::kNoPosition) {
420    masm->positions_recorder()->RecordStatementPosition(pos);
421    masm->positions_recorder()->RecordPosition(pos);
422    if (right_here) {
423      return masm->positions_recorder()->WriteRecordedPositions();
424    }
425  }
426  return false;
427}
428
429
430void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) {
431  if (FLAG_debug_info) RecordPositions(masm(), fun->start_position(), false);
432}
433
434
435void CodeGenerator::CodeForReturnPosition(FunctionLiteral* fun) {
436  if (FLAG_debug_info) RecordPositions(masm(), fun->end_position() - 1, false);
437}
438
439
440void CodeGenerator::CodeForStatementPosition(Statement* stmt) {
441  if (FLAG_debug_info) RecordPositions(masm(), stmt->statement_pos(), false);
442}
443
444
445void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) {
446  if (FLAG_debug_info)
447    RecordPositions(masm(), stmt->condition_position(), false);
448}
449
450
451void CodeGenerator::CodeForSourcePosition(int pos) {
452  if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
453    masm()->positions_recorder()->RecordPosition(pos);
454  }
455}
456
457
458const char* GenericUnaryOpStub::GetName() {
459  switch (op_) {
460    case Token::SUB:
461      if (negative_zero_ == kStrictNegativeZero) {
462        return overwrite_ == UNARY_OVERWRITE
463            ? "GenericUnaryOpStub_SUB_Overwrite_Strict0"
464            : "GenericUnaryOpStub_SUB_Alloc_Strict0";
465      } else {
466        return overwrite_ == UNARY_OVERWRITE
467            ? "GenericUnaryOpStub_SUB_Overwrite_Ignore0"
468            : "GenericUnaryOpStub_SUB_Alloc_Ignore0";
469      }
470    case Token::BIT_NOT:
471      return overwrite_ == UNARY_OVERWRITE
472          ? "GenericUnaryOpStub_BIT_NOT_Overwrite"
473          : "GenericUnaryOpStub_BIT_NOT_Alloc";
474    default:
475      UNREACHABLE();
476      return "<unknown>";
477  }
478}
479
480
481void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
482  switch (type_) {
483    case READ_ELEMENT:
484      GenerateReadElement(masm);
485      break;
486    case NEW_NON_STRICT:
487    case NEW_STRICT:
488      GenerateNewObject(masm);
489      break;
490  }
491}
492
493
494int CEntryStub::MinorKey() {
495  ASSERT(result_size_ == 1 || result_size_ == 2);
496  int result = save_doubles_ ? 1 : 0;
497#ifdef _WIN64
498  return result | ((result_size_ == 1) ? 0 : 2);
499#else
500  return result;
501#endif
502}
503
504
505} }  // namespace v8::internal
506