00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "v8.h"
00029
00030 #include "bootstrapper.h"
00031 #include "codegen-inl.h"
00032 #include "debug.h"
00033 #include "prettyprinter.h"
00034 #include "scopeinfo.h"
00035 #include "runtime.h"
00036 #include "stub-cache.h"
00037
00038 namespace v8 { namespace internal {
00039
00040 DeferredCode::DeferredCode(CodeGenerator* generator)
00041 : masm_(generator->masm()),
00042 generator_(generator),
00043 statement_position_(masm_->last_statement_position()),
00044 position_(masm_->last_position()) {
00045 generator->AddDeferred(this);
00046 #ifdef DEBUG
00047 comment_ = "";
00048 #endif
00049 }
00050
00051
00052 void CodeGenerator::ProcessDeferred() {
00053 while (!deferred_.is_empty()) {
00054 DeferredCode* code = deferred_.RemoveLast();
00055 MacroAssembler* masm = code->masm();
00056
00057 if (code->statement_position() != RelocInfo::kNoPosition) {
00058 masm->RecordStatementPosition(code->statement_position());
00059 }
00060 if (code->position() != RelocInfo::kNoPosition) {
00061 masm->RecordPosition(code->position());
00062 }
00063
00064 masm->bind(code->enter());
00065 Comment cmnt(masm, code->comment());
00066 code->Generate();
00067 if (code->exit()->is_bound()) {
00068 masm->jmp(code->exit());
00069 }
00070 }
00071 }
00072
00073
00074
00075
00076
00077 Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* flit,
00078 Handle<Script> script,
00079 bool is_eval) {
00080 #ifdef ENABLE_DISASSEMBLER
00081 bool print_code = FLAG_print_code && !Bootstrapper::IsActive();
00082 #endif
00083
00084 #ifdef DEBUG
00085 bool print_source = false;
00086 bool print_ast = false;
00087 const char* ftype;
00088
00089 if (Bootstrapper::IsActive()) {
00090 print_source = FLAG_print_builtin_source;
00091 print_ast = FLAG_print_builtin_ast;
00092 print_code = FLAG_print_builtin_code;
00093 ftype = "builtin";
00094 } else {
00095 print_source = FLAG_print_source;
00096 print_ast = FLAG_print_ast;
00097 ftype = "user-defined";
00098 }
00099
00100 if (FLAG_trace_codegen || print_source || print_ast) {
00101 PrintF("*** Generate code for %s function: ", ftype);
00102 flit->name()->ShortPrint();
00103 PrintF(" ***\n");
00104 }
00105
00106 if (print_source) {
00107 PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit));
00108 }
00109
00110 if (print_ast) {
00111 PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit));
00112 }
00113 #endif // DEBUG
00114
00115
00116 const int initial_buffer_size = 4 * KB;
00117 CodeGenerator cgen(initial_buffer_size, script, is_eval);
00118 cgen.GenCode(flit);
00119 if (cgen.HasStackOverflow()) {
00120 ASSERT(!Top::has_pending_exception());
00121 return Handle<Code>::null();
00122 }
00123
00124
00125 cgen.ProcessDeferred();
00126
00127
00128 CodeDesc desc;
00129 cgen.masm()->GetCode(&desc);
00130 ScopeInfo<> sinfo(flit->scope());
00131 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
00132 Handle<Code> code = Factory::NewCode(desc, &sinfo, flags);
00133
00134
00135 Bootstrapper::AddFixup(*code, cgen.masm());
00136
00137 #ifdef ENABLE_DISASSEMBLER
00138 if (print_code) {
00139
00140 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
00141 PrintF("--- Raw source ---\n");
00142 StringInputBuffer stream(String::cast(script->source()));
00143 stream.Seek(flit->start_position());
00144
00145
00146 int source_len = flit->end_position() - flit->start_position() + 1;
00147 for (int i = 0; i < source_len; i++) {
00148 if (stream.has_more()) PrintF("%c", stream.GetNext());
00149 }
00150 PrintF("\n\n");
00151 }
00152 PrintF("--- Code ---\n");
00153 code->Disassemble();
00154 }
00155 #endif // ENABLE_DISASSEMBLER
00156
00157 if (!code.is_null()) {
00158 Counters::total_compiled_code_size.Increment(code->instruction_size());
00159 }
00160
00161 return code;
00162 }
00163
00164
00165
00166
00167
00168
00169 void CodeGenerator::SetFunctionInfo(Handle<JSFunction> fun,
00170 int length,
00171 int function_token_position,
00172 int start_position,
00173 int end_position,
00174 bool is_expression,
00175 bool is_toplevel,
00176 Handle<Script> script) {
00177 fun->shared()->set_length(length);
00178 fun->shared()->set_formal_parameter_count(length);
00179 fun->shared()->set_script(*script);
00180 fun->shared()->set_function_token_position(function_token_position);
00181 fun->shared()->set_start_position(start_position);
00182 fun->shared()->set_end_position(end_position);
00183 fun->shared()->set_is_expression(is_expression);
00184 fun->shared()->set_is_toplevel(is_toplevel);
00185 }
00186
00187
00188 static Handle<Code> ComputeLazyCompile(int argc) {
00189 CALL_HEAP_FUNCTION(StubCache::ComputeLazyCompile(argc), Code);
00190 }
00191
00192
00193 Handle<JSFunction> CodeGenerator::BuildBoilerplate(FunctionLiteral* node) {
00194
00195
00196
00197
00198
00199 bool allow_lazy = node->AllowsLazyCompilation();
00200
00201
00202 Handle<Code> code;
00203 if (FLAG_lazy && allow_lazy) {
00204 code = ComputeLazyCompile(node->num_parameters());
00205 } else {
00206 code = MakeCode(node, script_, false);
00207
00208
00209 if (code.is_null()) {
00210 SetStackOverflow();
00211 return Handle<JSFunction>::null();
00212 }
00213
00214
00215 LOG(CodeCreateEvent("Function", *code, *node->name()));
00216 }
00217
00218
00219 Handle<JSFunction> function =
00220 Factory::NewFunctionBoilerplate(node->name(),
00221 node->materialized_literal_count(),
00222 node->contains_array_literal(),
00223 code);
00224 CodeGenerator::SetFunctionInfo(function, node->num_parameters(),
00225 node->function_token_position(),
00226 node->start_position(), node->end_position(),
00227 node->is_expression(), false, script_);
00228
00229
00230 Debugger::OnNewFunction(function);
00231
00232
00233
00234 SetExpectedNofPropertiesFromEstimate(function,
00235 node->expected_property_count());
00236 return function;
00237 }
00238
00239
00240 Handle<Code> CodeGenerator::ComputeCallInitialize(int argc) {
00241 CALL_HEAP_FUNCTION(StubCache::ComputeCallInitialize(argc), Code);
00242 }
00243
00244
00245 void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
00246 int length = declarations->length();
00247 int globals = 0;
00248 for (int i = 0; i < length; i++) {
00249 Declaration* node = declarations->at(i);
00250 Variable* var = node->proxy()->var();
00251 Slot* slot = var->slot();
00252
00253
00254
00255
00256 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
00257 VisitDeclaration(node);
00258 } else {
00259
00260 globals++;
00261 }
00262 }
00263
00264
00265 if (globals == 0) return;
00266
00267
00268 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
00269 for (int j = 0, i = 0; i < length; i++) {
00270 Declaration* node = declarations->at(i);
00271 Variable* var = node->proxy()->var();
00272 Slot* slot = var->slot();
00273
00274 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
00275
00276 } else {
00277 array->set(j++, *(var->name()));
00278 if (node->fun() == NULL) {
00279 if (var->mode() == Variable::CONST) {
00280
00281 array->set_the_hole(j++);
00282 } else {
00283 array->set_undefined(j++);
00284 }
00285 } else {
00286 Handle<JSFunction> function = BuildBoilerplate(node->fun());
00287
00288 if (HasStackOverflow()) return;
00289 array->set(j++, *function);
00290 }
00291 }
00292 }
00293
00294
00295
00296 DeclareGlobals(array);
00297 }
00298
00299
00300 struct InlineRuntimeLUT {
00301 void (CodeGenerator::*method)(ZoneList<Expression*>*);
00302 const char* name;
00303 };
00304
00305
00306 bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
00307 ZoneList<Expression*>* args = node->arguments();
00308
00309
00310
00311
00312
00313 static const InlineRuntimeLUT kInlineRuntimeLUT[] = {
00314 {&v8::internal::CodeGenerator::GenerateIsSmi,
00315 "_IsSmi"},
00316 {&v8::internal::CodeGenerator::GenerateIsNonNegativeSmi,
00317 "_IsNonNegativeSmi"},
00318 {&v8::internal::CodeGenerator::GenerateIsArray,
00319 "_IsArray"},
00320 {&v8::internal::CodeGenerator::GenerateArgumentsLength,
00321 "_ArgumentsLength"},
00322 {&v8::internal::CodeGenerator::GenerateArgumentsAccess,
00323 "_Arguments"},
00324 {&v8::internal::CodeGenerator::GenerateValueOf,
00325 "_ValueOf"},
00326 {&v8::internal::CodeGenerator::GenerateSetValueOf,
00327 "_SetValueOf"},
00328 {&v8::internal::CodeGenerator::GenerateFastCharCodeAt,
00329 "_FastCharCodeAt"},
00330 {&v8::internal::CodeGenerator::GenerateObjectEquals,
00331 "_ObjectEquals"}
00332 };
00333 if (node->name()->length() > 0 && node->name()->Get(0) == '_') {
00334 for (unsigned i = 0;
00335 i < sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
00336 i++) {
00337 const InlineRuntimeLUT* entry = kInlineRuntimeLUT + i;
00338 if (node->name()->IsEqualTo(CStrVector(entry->name))) {
00339 ((*this).*(entry->method))(args);
00340 return true;
00341 }
00342 }
00343 }
00344 return false;
00345 }
00346
00347
00348 void CodeGenerator::GenerateFastCaseSwitchStatement(SwitchStatement* node,
00349 int min_index,
00350 int range,
00351 int default_index) {
00352 ZoneList<CaseClause*>* cases = node->cases();
00353 int length = cases->length();
00354
00355
00356 SmartPointer<Label*> case_targets(NewArray<Label*>(range));
00357
00358
00359 SmartPointer<Label> case_labels(NewArray<Label>(length));
00360
00361 Label* fail_label = default_index >= 0 ? &(case_labels[default_index])
00362 : node->break_target();
00363
00364
00365
00366 for (int i = 0; i < range; i++) {
00367 case_targets[i] = fail_label;
00368 }
00369
00370
00371
00372
00373 for (int i = length-1; i >= 0 ; i--) {
00374 CaseClause* clause = cases->at(i);
00375 if (!clause->is_default()) {
00376 Object* label_value = *(clause->label()->AsLiteral()->handle());
00377 int case_value = Smi::cast(label_value)->value();
00378 case_targets[case_value - min_index] = &(case_labels[i]);
00379 }
00380 }
00381
00382 GenerateFastCaseSwitchJumpTable(node,
00383 min_index,
00384 range,
00385 fail_label,
00386 Vector<Label*>(*case_targets, range),
00387 Vector<Label>(*case_labels, length));
00388 }
00389
00390
00391 void CodeGenerator::GenerateFastCaseSwitchCases(
00392 SwitchStatement* node,
00393 Vector<Label> case_labels) {
00394 ZoneList<CaseClause*>* cases = node->cases();
00395 int length = cases->length();
00396
00397 for (int i = 0; i < length; i++) {
00398 Comment cmnt(masm(), "[ Case clause");
00399 masm()->bind(&(case_labels[i]));
00400 VisitStatements(cases->at(i)->statements());
00401 }
00402
00403 masm()->bind(node->break_target());
00404 }
00405
00406
00407 bool CodeGenerator::TryGenerateFastCaseSwitchStatement(SwitchStatement* node) {
00408 ZoneList<CaseClause*>* cases = node->cases();
00409 int length = cases->length();
00410
00411 if (length < FastCaseSwitchMinCaseCount()) {
00412 return false;
00413 }
00414
00415
00416 int default_index = -1;
00417 int min_index = Smi::kMaxValue;
00418 int max_index = Smi::kMinValue;
00419 for (int i = 0; i < length; i++) {
00420 CaseClause* clause = cases->at(i);
00421 if (clause->is_default()) {
00422 if (default_index >= 0) {
00423 return false;
00424
00425 }
00426 default_index = i;
00427 } else {
00428 Expression* label = clause->label();
00429 Literal* literal = label->AsLiteral();
00430 if (literal == NULL) {
00431 return false;
00432 }
00433 Object* value = *(literal->handle());
00434 if (!value->IsSmi()) {
00435 return false;
00436 }
00437 int smi = Smi::cast(value)->value();
00438 if (smi < min_index) { min_index = smi; }
00439 if (smi > max_index) { max_index = smi; }
00440 }
00441 }
00442
00443
00444 int range = max_index - min_index + 1;
00445 if (range / FastCaseSwitchMaxOverheadFactor() > length) {
00446 return false;
00447 }
00448
00449
00450 GenerateFastCaseSwitchStatement(node, min_index, range, default_index);
00451 return true;
00452 }
00453
00454
00455 const char* RuntimeStub::GetName() {
00456 return Runtime::FunctionForId(id_)->stub_name;
00457 }
00458
00459
00460 void RuntimeStub::Generate(MacroAssembler* masm) {
00461 masm->TailCallRuntime(ExternalReference(id_), num_arguments_);
00462 }
00463
00464
00465 void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
00466 switch (type_) {
00467 case READ_LENGTH: GenerateReadLength(masm); break;
00468 case READ_ELEMENT: GenerateReadElement(masm); break;
00469 case NEW_OBJECT: GenerateNewObject(masm); break;
00470 }
00471 }
00472
00473
00474 } }