| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 | 172 |
| 173 info->set_prologue_offset(masm_->pc_offset()); | 173 info->set_prologue_offset(masm_->pc_offset()); |
| 174 __ Prologue(BUILD_FUNCTION_FRAME); | 174 __ Prologue(BUILD_FUNCTION_FRAME); |
| 175 info->AddNoFrameRange(0, masm_->pc_offset()); | 175 info->AddNoFrameRange(0, masm_->pc_offset()); |
| 176 | 176 |
| 177 { Comment cmnt(masm_, "[ Allocate locals"); | 177 { Comment cmnt(masm_, "[ Allocate locals"); |
| 178 int locals_count = info->scope()->num_stack_slots(); | 178 int locals_count = info->scope()->num_stack_slots(); |
| 179 // Generators allocate locals, if any, in context slots. | 179 // Generators allocate locals, if any, in context slots. |
| 180 ASSERT(!info->function()->is_generator() || locals_count == 0); | 180 ASSERT(!info->function()->is_generator() || locals_count == 0); |
| 181 if (locals_count > 0) { | 181 if (locals_count > 0) { |
| 182 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); | |
| 183 // Emit a loop to initialize stack cells for locals when optimizing for | 182 // Emit a loop to initialize stack cells for locals when optimizing for |
| 184 // size. Otherwise, unroll the loop for maximum performance. | 183 // size. Otherwise, unroll the loop for maximum performance. |
| 185 __ LoadRoot(t5, Heap::kUndefinedValueRootIndex); | 184 __ LoadRoot(t5, Heap::kUndefinedValueRootIndex); |
| 186 if (FLAG_optimize_for_size && locals_count > 4) { | 185 if ((FLAG_optimize_for_size && locals_count > 4) || |
| 186 !is_int16(locals_count)) { |
| 187 Label loop; | 187 Label loop; |
| 188 __ li(a2, Operand(locals_count)); | 188 __ Subu(a2, sp, Operand(locals_count * kPointerSize)); |
| 189 __ bind(&loop); | 189 __ bind(&loop); |
| 190 __ Subu(a2, a2, 1); | 190 __ Subu(sp, sp, Operand(kPointerSize)); |
| 191 __ push(t5); | 191 __ Branch(&loop, gt, sp, Operand(a2), USE_DELAY_SLOT); |
| 192 __ Branch(&loop, gt, a2, Operand(zero_reg)); | 192 __ sw(t5, MemOperand(sp, 0)); // Push in the delay slot. |
| 193 } else { | 193 } else { |
| 194 __ Subu(sp, sp, Operand(locals_count * kPointerSize)); |
| 194 for (int i = 0; i < locals_count; i++) { | 195 for (int i = 0; i < locals_count; i++) { |
| 195 __ push(t5); | 196 __ sw(t5, MemOperand(sp, i * kPointerSize)); |
| 196 } | 197 } |
| 197 } | 198 } |
| 198 } | 199 } |
| 199 } | 200 } |
| 200 | 201 |
| 201 bool function_in_register = true; | 202 bool function_in_register = true; |
| 202 | 203 |
| 203 // Possibly allocate a local context. | 204 // Possibly allocate a local context. |
| 204 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 205 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 205 if (heap_slots > 0) { | 206 if (heap_slots > 0) { |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { | 335 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { |
| 335 __ li(a2, Operand(profiling_counter_)); | 336 __ li(a2, Operand(profiling_counter_)); |
| 336 __ lw(a3, FieldMemOperand(a2, Cell::kValueOffset)); | 337 __ lw(a3, FieldMemOperand(a2, Cell::kValueOffset)); |
| 337 __ Subu(a3, a3, Operand(Smi::FromInt(delta))); | 338 __ Subu(a3, a3, Operand(Smi::FromInt(delta))); |
| 338 __ sw(a3, FieldMemOperand(a2, Cell::kValueOffset)); | 339 __ sw(a3, FieldMemOperand(a2, Cell::kValueOffset)); |
| 339 } | 340 } |
| 340 | 341 |
| 341 | 342 |
| 342 void FullCodeGenerator::EmitProfilingCounterReset() { | 343 void FullCodeGenerator::EmitProfilingCounterReset() { |
| 343 int reset_value = FLAG_interrupt_budget; | 344 int reset_value = FLAG_interrupt_budget; |
| 344 if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) { | |
| 345 // Self-optimization is a one-off thing: if it fails, don't try again. | |
| 346 reset_value = Smi::kMaxValue; | |
| 347 } | |
| 348 if (isolate()->IsDebuggerActive()) { | 345 if (isolate()->IsDebuggerActive()) { |
| 349 // Detect debug break requests as soon as possible. | 346 // Detect debug break requests as soon as possible. |
| 350 reset_value = FLAG_interrupt_budget >> 4; | 347 reset_value = FLAG_interrupt_budget >> 4; |
| 351 } | 348 } |
| 352 __ li(a2, Operand(profiling_counter_)); | 349 __ li(a2, Operand(profiling_counter_)); |
| 353 __ li(a3, Operand(Smi::FromInt(reset_value))); | 350 __ li(a3, Operand(Smi::FromInt(reset_value))); |
| 354 __ sw(a3, FieldMemOperand(a2, Cell::kValueOffset)); | 351 __ sw(a3, FieldMemOperand(a2, Cell::kValueOffset)); |
| 355 } | 352 } |
| 356 | 353 |
| 357 | 354 |
| 358 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, | 355 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, |
| 359 Label* back_edge_target) { | 356 Label* back_edge_target) { |
| 360 // The generated code is used in Deoptimizer::PatchStackCheckCodeAt so we need | 357 // The generated code is used in Deoptimizer::PatchStackCheckCodeAt so we need |
| 361 // to make sure it is constant. Branch may emit a skip-or-jump sequence | 358 // to make sure it is constant. Branch may emit a skip-or-jump sequence |
| 362 // instead of the normal Branch. It seems that the "skip" part of that | 359 // instead of the normal Branch. It seems that the "skip" part of that |
| 363 // sequence is about as long as this Branch would be so it is safe to ignore | 360 // sequence is about as long as this Branch would be so it is safe to ignore |
| 364 // that. | 361 // that. |
| 365 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | 362 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); |
| 366 Comment cmnt(masm_, "[ Back edge bookkeeping"); | 363 Comment cmnt(masm_, "[ Back edge bookkeeping"); |
| 367 Label ok; | 364 Label ok; |
| 368 int weight = 1; | 365 ASSERT(back_edge_target->is_bound()); |
| 369 if (FLAG_weighted_back_edges) { | 366 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); |
| 370 ASSERT(back_edge_target->is_bound()); | 367 int weight = Min(kMaxBackEdgeWeight, |
| 371 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); | 368 Max(1, distance / kCodeSizeMultiplier)); |
| 372 weight = Min(kMaxBackEdgeWeight, | |
| 373 Max(1, distance / kCodeSizeMultiplier)); | |
| 374 } | |
| 375 EmitProfilingCounterDecrement(weight); | 369 EmitProfilingCounterDecrement(weight); |
| 376 __ slt(at, a3, zero_reg); | 370 __ slt(at, a3, zero_reg); |
| 377 __ beq(at, zero_reg, &ok); | 371 __ beq(at, zero_reg, &ok); |
| 378 // Call will emit a li t9 first, so it is safe to use the delay slot. | 372 // Call will emit a li t9 first, so it is safe to use the delay slot. |
| 379 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); | 373 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); |
| 380 // Record a mapping of this PC offset to the OSR id. This is used to find | 374 // Record a mapping of this PC offset to the OSR id. This is used to find |
| 381 // the AST id from the unoptimized code in order to use it as a key into | 375 // the AST id from the unoptimized code in order to use it as a key into |
| 382 // the deoptimization input data found in the optimized code. | 376 // the deoptimization input data found in the optimized code. |
| 383 RecordBackEdge(stmt->OsrEntryId()); | 377 RecordBackEdge(stmt->OsrEntryId()); |
| 384 EmitProfilingCounterReset(); | 378 EmitProfilingCounterReset(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 397 if (return_label_.is_bound()) { | 391 if (return_label_.is_bound()) { |
| 398 __ Branch(&return_label_); | 392 __ Branch(&return_label_); |
| 399 } else { | 393 } else { |
| 400 __ bind(&return_label_); | 394 __ bind(&return_label_); |
| 401 if (FLAG_trace) { | 395 if (FLAG_trace) { |
| 402 // Push the return value on the stack as the parameter. | 396 // Push the return value on the stack as the parameter. |
| 403 // Runtime::TraceExit returns its parameter in v0. | 397 // Runtime::TraceExit returns its parameter in v0. |
| 404 __ push(v0); | 398 __ push(v0); |
| 405 __ CallRuntime(Runtime::kTraceExit, 1); | 399 __ CallRuntime(Runtime::kTraceExit, 1); |
| 406 } | 400 } |
| 407 if (FLAG_interrupt_at_exit || FLAG_self_optimization) { | 401 // Pretend that the exit is a backwards jump to the entry. |
| 408 // Pretend that the exit is a backwards jump to the entry. | 402 int weight = 1; |
| 409 int weight = 1; | 403 if (info_->ShouldSelfOptimize()) { |
| 410 if (info_->ShouldSelfOptimize()) { | 404 weight = FLAG_interrupt_budget / FLAG_self_opt_count; |
| 411 weight = FLAG_interrupt_budget / FLAG_self_opt_count; | 405 } else { |
| 412 } else if (FLAG_weighted_back_edges) { | 406 int distance = masm_->pc_offset(); |
| 413 int distance = masm_->pc_offset(); | 407 weight = Min(kMaxBackEdgeWeight, |
| 414 weight = Min(kMaxBackEdgeWeight, | 408 Max(1, distance / kCodeSizeMultiplier)); |
| 415 Max(1, distance / kCodeSizeMultiplier)); | |
| 416 } | |
| 417 EmitProfilingCounterDecrement(weight); | |
| 418 Label ok; | |
| 419 __ Branch(&ok, ge, a3, Operand(zero_reg)); | |
| 420 __ push(v0); | |
| 421 if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) { | |
| 422 __ lw(a2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | |
| 423 __ push(a2); | |
| 424 __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1); | |
| 425 } else { | |
| 426 __ Call(isolate()->builtins()->InterruptCheck(), | |
| 427 RelocInfo::CODE_TARGET); | |
| 428 } | |
| 429 __ pop(v0); | |
| 430 EmitProfilingCounterReset(); | |
| 431 __ bind(&ok); | |
| 432 } | 409 } |
| 410 EmitProfilingCounterDecrement(weight); |
| 411 Label ok; |
| 412 __ Branch(&ok, ge, a3, Operand(zero_reg)); |
| 413 __ push(v0); |
| 414 __ Call(isolate()->builtins()->InterruptCheck(), |
| 415 RelocInfo::CODE_TARGET); |
| 416 __ pop(v0); |
| 417 EmitProfilingCounterReset(); |
| 418 __ bind(&ok); |
| 433 | 419 |
| 434 #ifdef DEBUG | 420 #ifdef DEBUG |
| 435 // Add a label for checking the size of the code used for returning. | 421 // Add a label for checking the size of the code used for returning. |
| 436 Label check_exit_codesize; | 422 Label check_exit_codesize; |
| 437 masm_->bind(&check_exit_codesize); | 423 masm_->bind(&check_exit_codesize); |
| 438 #endif | 424 #endif |
| 439 // Make sure that the constant pool is not emitted inside of the return | 425 // Make sure that the constant pool is not emitted inside of the return |
| 440 // sequence. | 426 // sequence. |
| 441 { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | 427 { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); |
| 442 // Here we use masm_-> instead of the __ macro to avoid the code coverage | 428 // Here we use masm_-> instead of the __ macro to avoid the code coverage |
| (...skipping 604 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1047 | 1033 |
| 1048 __ bind(&slow_case); | 1034 __ bind(&slow_case); |
| 1049 } | 1035 } |
| 1050 | 1036 |
| 1051 // Record position before stub call for type feedback. | 1037 // Record position before stub call for type feedback. |
| 1052 SetSourcePosition(clause->position()); | 1038 SetSourcePosition(clause->position()); |
| 1053 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); | 1039 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); |
| 1054 CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId()); | 1040 CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId()); |
| 1055 patch_site.EmitPatchInfo(); | 1041 patch_site.EmitPatchInfo(); |
| 1056 | 1042 |
| 1043 Label skip; |
| 1044 __ Branch(&skip); |
| 1045 PrepareForBailout(clause, TOS_REG); |
| 1046 __ LoadRoot(at, Heap::kTrueValueRootIndex); |
| 1047 __ Branch(&next_test, ne, v0, Operand(at)); |
| 1048 __ Drop(1); |
| 1049 __ Branch(clause->body_target()); |
| 1050 __ bind(&skip); |
| 1051 |
| 1057 __ Branch(&next_test, ne, v0, Operand(zero_reg)); | 1052 __ Branch(&next_test, ne, v0, Operand(zero_reg)); |
| 1058 __ Drop(1); // Switch value is no longer needed. | 1053 __ Drop(1); // Switch value is no longer needed. |
| 1059 __ Branch(clause->body_target()); | 1054 __ Branch(clause->body_target()); |
| 1060 } | 1055 } |
| 1061 | 1056 |
| 1062 // Discard the test value and jump to the default if present, otherwise to | 1057 // Discard the test value and jump to the default if present, otherwise to |
| 1063 // the end of the statement. | 1058 // the end of the statement. |
| 1064 __ bind(&next_test); | 1059 __ bind(&next_test); |
| 1065 __ Drop(1); // Switch value is no longer needed. | 1060 __ Drop(1); // Switch value is no longer needed. |
| 1066 if (default_clause == NULL) { | 1061 if (default_clause == NULL) { |
| (...skipping 2689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3756 VisitForStackValue(args->at(0)); | 3751 VisitForStackValue(args->at(0)); |
| 3757 VisitForStackValue(args->at(1)); | 3752 VisitForStackValue(args->at(1)); |
| 3758 | 3753 |
| 3759 StringCompareStub stub; | 3754 StringCompareStub stub; |
| 3760 __ CallStub(&stub); | 3755 __ CallStub(&stub); |
| 3761 context()->Plug(v0); | 3756 context()->Plug(v0); |
| 3762 } | 3757 } |
| 3763 | 3758 |
| 3764 | 3759 |
| 3765 void FullCodeGenerator::EmitMathLog(CallRuntime* expr) { | 3760 void FullCodeGenerator::EmitMathLog(CallRuntime* expr) { |
| 3766 // Load the argument on the stack and call the stub. | 3761 // Load the argument on the stack and call the runtime function. |
| 3767 TranscendentalCacheStub stub(TranscendentalCache::LOG, | |
| 3768 TranscendentalCacheStub::TAGGED); | |
| 3769 ZoneList<Expression*>* args = expr->arguments(); | 3762 ZoneList<Expression*>* args = expr->arguments(); |
| 3770 ASSERT(args->length() == 1); | 3763 ASSERT(args->length() == 1); |
| 3771 VisitForStackValue(args->at(0)); | 3764 VisitForStackValue(args->at(0)); |
| 3772 __ mov(a0, result_register()); // Stub requires parameter in a0 and on tos. | 3765 __ CallRuntime(Runtime::kMath_log, 1); |
| 3773 __ CallStub(&stub); | |
| 3774 context()->Plug(v0); | 3766 context()->Plug(v0); |
| 3775 } | 3767 } |
| 3776 | 3768 |
| 3777 | 3769 |
| 3778 void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) { | 3770 void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) { |
| 3779 // Load the argument on the stack and call the runtime function. | 3771 // Load the argument on the stack and call the runtime function. |
| 3780 ZoneList<Expression*>* args = expr->arguments(); | 3772 ZoneList<Expression*>* args = expr->arguments(); |
| 3781 ASSERT(args->length() == 1); | 3773 ASSERT(args->length() == 1); |
| 3782 VisitForStackValue(args->at(0)); | 3774 VisitForStackValue(args->at(0)); |
| 3783 __ CallRuntime(Runtime::kMath_sqrt, 1); | 3775 __ CallRuntime(Runtime::kMath_sqrt, 1); |
| (...skipping 1193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4977 Assembler::target_address_at(pc_immediate_load_address)) == | 4969 Assembler::target_address_at(pc_immediate_load_address)) == |
| 4978 reinterpret_cast<uint32_t>( | 4970 reinterpret_cast<uint32_t>( |
| 4979 isolate->builtins()->OsrAfterStackCheck()->entry())); | 4971 isolate->builtins()->OsrAfterStackCheck()->entry())); |
| 4980 return OSR_AFTER_STACK_CHECK; | 4972 return OSR_AFTER_STACK_CHECK; |
| 4981 } | 4973 } |
| 4982 | 4974 |
| 4983 | 4975 |
| 4984 } } // namespace v8::internal | 4976 } } // namespace v8::internal |
| 4985 | 4977 |
| 4986 #endif // V8_TARGET_ARCH_MIPS | 4978 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |