1// Copyright 2012 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 "src/bootstrapper.h"
8#include "src/codegen.h"
9#include "src/compiler.h"
10#include "src/cpu-profiler.h"
11#include "src/debug.h"
12#include "src/prettyprinter.h"
13#include "src/rewriter.h"
14#include "src/runtime.h"
15
16namespace v8 {
17namespace internal {
18
19
20#if defined(_WIN64)
21typedef double (*ModuloFunction)(double, double);
22static ModuloFunction modulo_function = NULL;
23// Defined in codegen-x64.cc.
24ModuloFunction CreateModuloFunction();
25
26void init_modulo_function() {
27  modulo_function = CreateModuloFunction();
28}
29
30
31double modulo(double x, double y) {
32  // Note: here we rely on dependent reads being ordered. This is true
33  // on all architectures we currently support.
34  return (*modulo_function)(x, y);
35}
36#elif defined(_WIN32)
37
38double modulo(double x, double y) {
39  // Workaround MS fmod bugs. ECMA-262 says:
40  // dividend is finite and divisor is an infinity => result equals dividend
41  // dividend is a zero and divisor is nonzero finite => result equals dividend
42  if (!(std::isfinite(x) && (!std::isfinite(y) && !std::isnan(y))) &&
43      !(x == 0 && (y != 0 && std::isfinite(y)))) {
44    x = fmod(x, y);
45  }
46  return x;
47}
48#else  // POSIX
49
50double modulo(double x, double y) {
51  return std::fmod(x, y);
52}
53#endif  // defined(_WIN64)
54
55
56#define UNARY_MATH_FUNCTION(name, generator)             \
57static UnaryMathFunction fast_##name##_function = NULL;  \
58void init_fast_##name##_function() {                     \
59  fast_##name##_function = generator;                    \
60}                                                        \
61double fast_##name(double x) {                           \
62  return (*fast_##name##_function)(x);                   \
63}
64
65UNARY_MATH_FUNCTION(exp, CreateExpFunction())
66UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction())
67
68#undef UNARY_MATH_FUNCTION
69
70
71void lazily_initialize_fast_exp() {
72  if (fast_exp_function == NULL) {
73    init_fast_exp_function();
74  }
75}
76
77
78#define __ ACCESS_MASM(masm_)
79
80#ifdef DEBUG
81
82Comment::Comment(MacroAssembler* masm, const char* msg)
83    : masm_(masm), msg_(msg) {
84  __ RecordComment(msg);
85}
86
87
88Comment::~Comment() {
89  if (msg_[0] == '[') __ RecordComment("]");
90}
91
92#endif  // DEBUG
93
94#undef __
95
96
97void CodeGenerator::MakeCodePrologue(CompilationInfo* info, const char* kind) {
98  bool print_source = false;
99  bool print_ast = false;
100  const char* ftype;
101
102  if (info->isolate()->bootstrapper()->IsActive()) {
103    print_source = FLAG_print_builtin_source;
104    print_ast = FLAG_print_builtin_ast;
105    ftype = "builtin";
106  } else {
107    print_source = FLAG_print_source;
108    print_ast = FLAG_print_ast;
109    ftype = "user-defined";
110  }
111
112  if (FLAG_trace_codegen || print_source || print_ast) {
113    PrintF("[generating %s code for %s function: ", kind, ftype);
114    if (info->IsStub()) {
115      const char* name =
116          CodeStub::MajorName(info->code_stub()->MajorKey(), true);
117      PrintF("%s", name == NULL ? "<unknown>" : name);
118    } else {
119      AllowDeferredHandleDereference allow_deference_for_trace;
120      PrintF("%s", info->function()->debug_name()->ToCString().get());
121    }
122    PrintF("]\n");
123  }
124
125#ifdef DEBUG
126  if (!info->IsStub() && print_source) {
127    PrintF("--- Source from AST ---\n%s\n",
128           PrettyPrinter(info->zone()).PrintProgram(info->function()));
129  }
130
131  if (!info->IsStub() && print_ast) {
132    PrintF("--- AST ---\n%s\n",
133           AstPrinter(info->zone()).PrintProgram(info->function()));
134  }
135#endif  // DEBUG
136}
137
138
139Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
140                                             Code::Flags flags,
141                                             CompilationInfo* info) {
142  Isolate* isolate = info->isolate();
143
144  // Allocate and install the code.
145  CodeDesc desc;
146  bool is_crankshafted =
147      Code::ExtractKindFromFlags(flags) == Code::OPTIMIZED_FUNCTION ||
148      info->IsStub();
149  masm->GetCode(&desc);
150  Handle<Code> code =
151      isolate->factory()->NewCode(desc, flags, masm->CodeObject(),
152                                  false, is_crankshafted,
153                                  info->prologue_offset(),
154                                  info->is_debug() && !is_crankshafted);
155  isolate->counters()->total_compiled_code_size()->Increment(
156      code->instruction_size());
157  isolate->heap()->IncrementCodeGeneratedBytes(is_crankshafted,
158      code->instruction_size());
159  return code;
160}
161
162
163void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
164#ifdef ENABLE_DISASSEMBLER
165  AllowDeferredHandleDereference allow_deference_for_print_code;
166  bool print_code = info->isolate()->bootstrapper()->IsActive()
167      ? FLAG_print_builtin_code
168      : (FLAG_print_code ||
169         (info->IsStub() && FLAG_print_code_stubs) ||
170         (info->IsOptimizing() && FLAG_print_opt_code));
171  if (print_code) {
172    // Print the source code if available.
173    FunctionLiteral* function = info->function();
174    bool print_source = code->kind() == Code::OPTIMIZED_FUNCTION ||
175        code->kind() == Code::FUNCTION;
176
177    CodeTracer::Scope tracing_scope(info->isolate()->GetCodeTracer());
178    OFStream os(tracing_scope.file());
179    if (print_source) {
180      Handle<Script> script = info->script();
181      if (!script->IsUndefined() && !script->source()->IsUndefined()) {
182        os << "--- Raw source ---\n";
183        ConsStringIteratorOp op;
184        StringCharacterStream stream(String::cast(script->source()),
185                                     &op,
186                                     function->start_position());
187        // fun->end_position() points to the last character in the stream. We
188        // need to compensate by adding one to calculate the length.
189        int source_len =
190            function->end_position() - function->start_position() + 1;
191        for (int i = 0; i < source_len; i++) {
192          if (stream.HasMore()) {
193            os << AsReversiblyEscapedUC16(stream.GetNext());
194          }
195        }
196        os << "\n\n";
197      }
198    }
199    if (info->IsOptimizing()) {
200      if (FLAG_print_unopt_code) {
201        os << "--- Unoptimized code ---\n";
202        info->closure()->shared()->code()->Disassemble(
203            function->debug_name()->ToCString().get(), os);
204      }
205      os << "--- Optimized code ---\n"
206         << "optimization_id = " << info->optimization_id() << "\n";
207    } else {
208      os << "--- Code ---\n";
209    }
210    if (print_source) {
211      os << "source_position = " << function->start_position() << "\n";
212    }
213    if (info->IsStub()) {
214      CodeStub::Major major_key = info->code_stub()->MajorKey();
215      code->Disassemble(CodeStub::MajorName(major_key, false), os);
216    } else {
217      code->Disassemble(function->debug_name()->ToCString().get(), os);
218    }
219    os << "--- End code ---\n";
220  }
221#endif  // ENABLE_DISASSEMBLER
222}
223
224
225bool CodeGenerator::RecordPositions(MacroAssembler* masm,
226                                    int pos,
227                                    bool right_here) {
228  if (pos != RelocInfo::kNoPosition) {
229    masm->positions_recorder()->RecordStatementPosition(pos);
230    masm->positions_recorder()->RecordPosition(pos);
231    if (right_here) {
232      return masm->positions_recorder()->WriteRecordedPositions();
233    }
234  }
235  return false;
236}
237
238} }  // namespace v8::internal
239