blob: fd7e0e80b7775cca0648efd4e8e30b241201df6c [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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"
Steve Blockd0582a62009-12-15 09:54:21 +000032#include "compiler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000033#include "debug.h"
34#include "oprofile-agent.h"
35#include "prettyprinter.h"
36#include "register-allocator-inl.h"
37#include "rewriter.h"
38#include "runtime.h"
39#include "scopeinfo.h"
40#include "stub-cache.h"
41
42namespace v8 {
43namespace internal {
44
45
46CodeGenerator* CodeGeneratorScope::top_ = NULL;
47
48
49DeferredCode::DeferredCode()
50 : masm_(CodeGeneratorScope::Current()->masm()),
51 statement_position_(masm_->current_statement_position()),
52 position_(masm_->current_position()) {
53 ASSERT(statement_position_ != RelocInfo::kNoPosition);
54 ASSERT(position_ != RelocInfo::kNoPosition);
55
56 CodeGeneratorScope::Current()->AddDeferred(this);
57#ifdef DEBUG
58 comment_ = "";
59#endif
60
61 // Copy the register locations from the code generator's frame.
62 // These are the registers that will be spilled on entry to the
63 // deferred code and restored on exit.
64 VirtualFrame* frame = CodeGeneratorScope::Current()->frame();
65 int sp_offset = frame->fp_relative(frame->stack_pointer_);
66 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
67 int loc = frame->register_location(i);
68 if (loc == VirtualFrame::kIllegalIndex) {
69 registers_[i] = kIgnore;
70 } else if (frame->elements_[loc].is_synced()) {
71 // Needs to be restored on exit but not saved on entry.
72 registers_[i] = frame->fp_relative(loc) | kSyncedFlag;
73 } else {
74 int offset = frame->fp_relative(loc);
75 registers_[i] = (offset < sp_offset) ? kPush : offset;
76 }
77 }
78}
79
80
81void CodeGenerator::ProcessDeferred() {
82 while (!deferred_.is_empty()) {
83 DeferredCode* code = deferred_.RemoveLast();
84 ASSERT(masm_ == code->masm());
85 // Record position of deferred code stub.
86 masm_->RecordStatementPosition(code->statement_position());
87 if (code->position() != RelocInfo::kNoPosition) {
88 masm_->RecordPosition(code->position());
89 }
90 // Generate the code.
91 Comment cmnt(masm_, code->comment());
92 masm_->bind(code->entry_label());
93 code->SaveRegisters();
94 code->Generate();
95 code->RestoreRegisters();
96 masm_->jmp(code->exit_label());
97 }
98}
99
100
101void CodeGenerator::SetFrame(VirtualFrame* new_frame,
102 RegisterFile* non_frame_registers) {
103 RegisterFile saved_counts;
104 if (has_valid_frame()) {
105 frame_->DetachFromCodeGenerator();
106 // The remaining register reference counts are the non-frame ones.
107 allocator_->SaveTo(&saved_counts);
108 }
109
110 if (new_frame != NULL) {
111 // Restore the non-frame register references that go with the new frame.
112 allocator_->RestoreFrom(non_frame_registers);
113 new_frame->AttachToCodeGenerator();
114 }
115
116 frame_ = new_frame;
117 saved_counts.CopyTo(non_frame_registers);
118}
119
120
121void CodeGenerator::DeleteFrame() {
122 if (has_valid_frame()) {
123 frame_->DetachFromCodeGenerator();
124 frame_ = NULL;
125 }
126}
127
128
Steve Block3ce2e202009-11-05 08:53:23 +0000129void CodeGenerator::MakeCodePrologue(FunctionLiteral* fun) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000130#ifdef DEBUG
131 bool print_source = false;
132 bool print_ast = false;
Steve Block3ce2e202009-11-05 08:53:23 +0000133 bool print_json_ast = false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000134 const char* ftype;
135
136 if (Bootstrapper::IsActive()) {
137 print_source = FLAG_print_builtin_source;
138 print_ast = FLAG_print_builtin_ast;
Steve Block3ce2e202009-11-05 08:53:23 +0000139 print_json_ast = FLAG_print_builtin_json_ast;
Steve Blocka7e24c12009-10-30 11:49:00 +0000140 ftype = "builtin";
141 } else {
142 print_source = FLAG_print_source;
143 print_ast = FLAG_print_ast;
Steve Block3ce2e202009-11-05 08:53:23 +0000144 print_json_ast = FLAG_print_json_ast;
Steve Blocka7e24c12009-10-30 11:49:00 +0000145 ftype = "user-defined";
146 }
147
148 if (FLAG_trace_codegen || print_source || print_ast) {
149 PrintF("*** Generate code for %s function: ", ftype);
Steve Block3ce2e202009-11-05 08:53:23 +0000150 fun->name()->ShortPrint();
Steve Blocka7e24c12009-10-30 11:49:00 +0000151 PrintF(" ***\n");
152 }
153
154 if (print_source) {
Steve Block3ce2e202009-11-05 08:53:23 +0000155 PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(fun));
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 }
157
158 if (print_ast) {
Steve Block3ce2e202009-11-05 08:53:23 +0000159 PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(fun));
160 }
161
162 if (print_json_ast) {
163 JsonAstBuilder builder;
164 PrintF("%s", builder.BuildProgram(fun));
Steve Blocka7e24c12009-10-30 11:49:00 +0000165 }
166#endif // DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000167}
Steve Blocka7e24c12009-10-30 11:49:00 +0000168
Steve Blocka7e24c12009-10-30 11:49:00 +0000169
Steve Block3ce2e202009-11-05 08:53:23 +0000170Handle<Code> CodeGenerator::MakeCodeEpilogue(FunctionLiteral* fun,
171 MacroAssembler* masm,
172 Code::Flags flags,
173 Handle<Script> script) {
174 // Allocate and install the code.
Steve Blocka7e24c12009-10-30 11:49:00 +0000175 CodeDesc desc;
Steve Block3ce2e202009-11-05 08:53:23 +0000176 masm->GetCode(&desc);
177 ZoneScopeInfo sinfo(fun->scope());
178 Handle<Code> code =
179 Factory::NewCode(desc, &sinfo, flags, masm->CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +0000180
181 // Add unresolved entries in the code to the fixup list.
Steve Block3ce2e202009-11-05 08:53:23 +0000182 Bootstrapper::AddFixup(*code, masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000183
184#ifdef ENABLE_DISASSEMBLER
Steve Block3ce2e202009-11-05 08:53:23 +0000185 bool print_code = Bootstrapper::IsActive()
186 ? FLAG_print_builtin_code
187 : FLAG_print_code;
Steve Blocka7e24c12009-10-30 11:49:00 +0000188 if (print_code) {
189 // Print the source code if available.
190 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
191 PrintF("--- Raw source ---\n");
192 StringInputBuffer stream(String::cast(script->source()));
Steve Block3ce2e202009-11-05 08:53:23 +0000193 stream.Seek(fun->start_position());
194 // fun->end_position() points to the last character in the stream. We
Steve Blocka7e24c12009-10-30 11:49:00 +0000195 // need to compensate by adding one to calculate the length.
Steve Block3ce2e202009-11-05 08:53:23 +0000196 int source_len = fun->end_position() - fun->start_position() + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000197 for (int i = 0; i < source_len; i++) {
198 if (stream.has_more()) PrintF("%c", stream.GetNext());
199 }
200 PrintF("\n\n");
201 }
202 PrintF("--- Code ---\n");
Steve Block3ce2e202009-11-05 08:53:23 +0000203 code->Disassemble(*fun->name()->ToCString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000204 }
205#endif // ENABLE_DISASSEMBLER
206
207 if (!code.is_null()) {
208 Counters::total_compiled_code_size.Increment(code->instruction_size());
209 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 return code;
211}
212
213
Steve Block3ce2e202009-11-05 08:53:23 +0000214// Generate the code. Takes a function literal, generates code for it, assemble
215// all the pieces into a Code object. This function is only to be called by
216// the compiler.cc code.
217Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun,
218 Handle<Script> script,
219 bool is_eval) {
220 MakeCodePrologue(fun);
221 // Generate code.
222 const int kInitialBufferSize = 4 * KB;
223 CodeGenerator cgen(kInitialBufferSize, script, is_eval);
224 CodeGeneratorScope scope(&cgen);
225 cgen.GenCode(fun);
226 if (cgen.HasStackOverflow()) {
227 ASSERT(!Top::has_pending_exception());
228 return Handle<Code>::null();
229 }
230
231 InLoopFlag in_loop = (cgen.loop_nesting() != 0) ? IN_LOOP : NOT_IN_LOOP;
232 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop);
233 return MakeCodeEpilogue(fun, cgen.masm(), flags, script);
234}
235
236
Steve Blocka7e24c12009-10-30 11:49:00 +0000237#ifdef ENABLE_LOGGING_AND_PROFILING
238
239bool CodeGenerator::ShouldGenerateLog(Expression* type) {
240 ASSERT(type != NULL);
241 if (!Logger::is_logging()) return false;
242 Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
243 if (FLAG_log_regexp) {
244 static Vector<const char> kRegexp = CStrVector("regexp");
245 if (name->IsEqualTo(kRegexp))
246 return true;
247 }
248 return false;
249}
250
251#endif
252
253
Steve Blocka7e24c12009-10-30 11:49:00 +0000254Handle<Code> CodeGenerator::ComputeCallInitialize(
255 int argc,
256 InLoopFlag in_loop) {
257 if (in_loop == IN_LOOP) {
258 // Force the creation of the corresponding stub outside loops,
259 // because it may be used when clearing the ICs later - it is
260 // possible for a series of IC transitions to lose the in-loop
261 // information, and the IC clearing code can't generate a stub
262 // that it needs so we need to ensure it is generated already.
263 ComputeCallInitialize(argc, NOT_IN_LOOP);
264 }
265 CALL_HEAP_FUNCTION(StubCache::ComputeCallInitialize(argc, in_loop), Code);
266}
267
268
269void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
270 int length = declarations->length();
271 int globals = 0;
272 for (int i = 0; i < length; i++) {
273 Declaration* node = declarations->at(i);
274 Variable* var = node->proxy()->var();
275 Slot* slot = var->slot();
276
277 // If it was not possible to allocate the variable at compile
278 // time, we need to "declare" it at runtime to make sure it
279 // actually exists in the local context.
280 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
281 VisitDeclaration(node);
282 } else {
283 // Count global variables and functions for later processing
284 globals++;
285 }
286 }
287
288 // Return in case of no declared global functions or variables.
289 if (globals == 0) return;
290
291 // Compute array of global variable and function declarations.
292 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
293 for (int j = 0, i = 0; i < length; i++) {
294 Declaration* node = declarations->at(i);
295 Variable* var = node->proxy()->var();
296 Slot* slot = var->slot();
297
298 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
299 // Skip - already processed.
300 } else {
301 array->set(j++, *(var->name()));
302 if (node->fun() == NULL) {
303 if (var->mode() == Variable::CONST) {
304 // In case this is const property use the hole.
305 array->set_the_hole(j++);
306 } else {
307 array->set_undefined(j++);
308 }
309 } else {
Steve Blockd0582a62009-12-15 09:54:21 +0000310 Handle<JSFunction> function =
311 Compiler::BuildBoilerplate(node->fun(), script(), this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000312 // Check for stack-overflow exception.
313 if (HasStackOverflow()) return;
314 array->set(j++, *function);
315 }
316 }
317 }
318
319 // Invoke the platform-dependent code generator to do the actual
320 // declaration the global variables and functions.
321 DeclareGlobals(array);
322}
323
324
325
326// Special cases: These 'runtime calls' manipulate the current
327// frame and are only used 1 or two places, so we generate them
328// inline instead of generating calls to them. They are used
329// for implementing Function.prototype.call() and
330// Function.prototype.apply().
331CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
332 {&CodeGenerator::GenerateIsSmi, "_IsSmi"},
333 {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
334 {&CodeGenerator::GenerateIsArray, "_IsArray"},
335 {&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
336 {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
337 {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
338 {&CodeGenerator::GenerateClassOf, "_ClassOf"},
339 {&CodeGenerator::GenerateValueOf, "_ValueOf"},
340 {&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
341 {&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
342 {&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
343 {&CodeGenerator::GenerateLog, "_Log"},
344 {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
Steve Blockd0582a62009-12-15 09:54:21 +0000345 {&CodeGenerator::GenerateIsObject, "_IsObject"},
346 {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
347 {&CodeGenerator::GenerateStringAdd, "_StringAdd"},
Leon Clarkee46be812010-01-19 14:06:41 +0000348 {&CodeGenerator::GenerateSubString, "_SubString"},
349 {&CodeGenerator::GenerateStringCompare, "_StringCompare"},
350 {&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
Steve Blocka7e24c12009-10-30 11:49:00 +0000351};
352
353
354CodeGenerator::InlineRuntimeLUT* CodeGenerator::FindInlineRuntimeLUT(
355 Handle<String> name) {
356 const int entries_count =
357 sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
358 for (int i = 0; i < entries_count; i++) {
359 InlineRuntimeLUT* entry = &kInlineRuntimeLUT[i];
360 if (name->IsEqualTo(CStrVector(entry->name))) {
361 return entry;
362 }
363 }
364 return NULL;
365}
366
367
368bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
369 ZoneList<Expression*>* args = node->arguments();
370 Handle<String> name = node->name();
371 if (name->length() > 0 && name->Get(0) == '_') {
372 InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name);
373 if (entry != NULL) {
374 ((*this).*(entry->method))(args);
375 return true;
376 }
377 }
378 return false;
379}
380
381
382bool CodeGenerator::PatchInlineRuntimeEntry(Handle<String> name,
383 const CodeGenerator::InlineRuntimeLUT& new_entry,
384 CodeGenerator::InlineRuntimeLUT* old_entry) {
385 InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name);
386 if (entry == NULL) return false;
387 if (old_entry != NULL) {
388 old_entry->name = entry->name;
389 old_entry->method = entry->method;
390 }
391 entry->name = new_entry.name;
392 entry->method = new_entry.method;
393 return true;
394}
395
396
Steve Block3ce2e202009-11-05 08:53:23 +0000397// 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
416void CodeGenerator::RecordPositions(MacroAssembler* masm, int pos) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000417 if (pos != RelocInfo::kNoPosition) {
Steve Block3ce2e202009-11-05 08:53:23 +0000418 masm->RecordStatementPosition(pos);
419 masm->RecordPosition(pos);
Steve Blocka7e24c12009-10-30 11:49:00 +0000420 }
421}
422
423
424void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) {
Steve Block3ce2e202009-11-05 08:53:23 +0000425 if (FLAG_debug_info) RecordPositions(masm(), fun->start_position());
Steve Blocka7e24c12009-10-30 11:49:00 +0000426}
427
428
429void CodeGenerator::CodeForReturnPosition(FunctionLiteral* fun) {
Steve Block3ce2e202009-11-05 08:53:23 +0000430 if (FLAG_debug_info) RecordPositions(masm(), fun->end_position());
Steve Blocka7e24c12009-10-30 11:49:00 +0000431}
432
433
434void CodeGenerator::CodeForStatementPosition(Statement* stmt) {
Steve Block3ce2e202009-11-05 08:53:23 +0000435 if (FLAG_debug_info) RecordPositions(masm(), stmt->statement_pos());
Steve Blocka7e24c12009-10-30 11:49:00 +0000436}
437
Steve Blockd0582a62009-12-15 09:54:21 +0000438void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) {
439 if (FLAG_debug_info) RecordPositions(masm(), stmt->condition_position());
440}
Steve Blocka7e24c12009-10-30 11:49:00 +0000441
442void CodeGenerator::CodeForSourcePosition(int pos) {
443 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
444 masm()->RecordPosition(pos);
445 }
446}
447
448
449const char* RuntimeStub::GetName() {
450 return Runtime::FunctionForId(id_)->stub_name;
451}
452
453
Leon Clarkee46be812010-01-19 14:06:41 +0000454const char* GenericUnaryOpStub::GetName() {
455 switch (op_) {
456 case Token::SUB:
457 return overwrite_
458 ? "GenericUnaryOpStub_SUB_Overwrite"
459 : "GenericUnaryOpStub_SUB_Alloc";
460 case Token::BIT_NOT:
461 return overwrite_
462 ? "GenericUnaryOpStub_BIT_NOT_Overwrite"
463 : "GenericUnaryOpStub_BIT_NOT_Alloc";
464 default:
465 UNREACHABLE();
466 return "<unknown>";
467 }
468}
469
470
Steve Blocka7e24c12009-10-30 11:49:00 +0000471void RuntimeStub::Generate(MacroAssembler* masm) {
472 Runtime::Function* f = Runtime::FunctionForId(id_);
473 masm->TailCallRuntime(ExternalReference(f),
474 num_arguments_,
475 f->result_size);
476}
477
478
479void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
480 switch (type_) {
481 case READ_LENGTH: GenerateReadLength(masm); break;
482 case READ_ELEMENT: GenerateReadElement(masm); break;
483 case NEW_OBJECT: GenerateNewObject(masm); break;
484 }
485}
486
487
Steve Blockd0582a62009-12-15 09:54:21 +0000488bool ApiGetterEntryStub::GetCustomCache(Code** code_out) {
489 Object* cache = info()->load_stub_cache();
490 if (cache->IsUndefined()) {
491 return false;
492 } else {
493 *code_out = Code::cast(cache);
494 return true;
495 }
496}
497
498
499void ApiGetterEntryStub::SetCustomCache(Code* value) {
500 info()->set_load_stub_cache(value);
501}
502
503
Steve Blocka7e24c12009-10-30 11:49:00 +0000504} } // namespace v8::internal