| 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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 | 112 |
| 113 | 113 |
| 114 // Generate code for a JS function. On entry to the function the receiver | 114 // Generate code for a JS function. On entry to the function the receiver |
| 115 // and arguments have been pushed on the stack left to right. The actual | 115 // and arguments have been pushed on the stack left to right. The actual |
| 116 // argument count matches the formal parameter count expected by the | 116 // argument count matches the formal parameter count expected by the |
| 117 // function. | 117 // function. |
| 118 // | 118 // |
| 119 // The live registers are: | 119 // The live registers are: |
| 120 // o r1: the JS function object being called (i.e., ourselves) | 120 // o r1: the JS function object being called (i.e., ourselves) |
| 121 // o cp: our context | 121 // o cp: our context |
| 122 // o pp: our caller's constant pool pointer (if FLAG_enable_ool_constant_pool) |
| 122 // o fp: our caller's frame pointer | 123 // o fp: our caller's frame pointer |
| 123 // o sp: stack pointer | 124 // o sp: stack pointer |
| 124 // o lr: return address | 125 // o lr: return address |
| 125 // | 126 // |
| 126 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 127 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
| 127 // frames-arm.h for its layout. | 128 // frames-arm.h for its layout. |
| 128 void FullCodeGenerator::Generate() { | 129 void FullCodeGenerator::Generate() { |
| 129 CompilationInfo* info = info_; | 130 CompilationInfo* info = info_; |
| 130 handler_table_ = | 131 handler_table_ = |
| 131 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); | 132 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 155 } | 156 } |
| 156 | 157 |
| 157 // Open a frame scope to indicate that there is a frame on the stack. The | 158 // Open a frame scope to indicate that there is a frame on the stack. The |
| 158 // MANUAL indicates that the scope shouldn't actually generate code to set up | 159 // MANUAL indicates that the scope shouldn't actually generate code to set up |
| 159 // the frame (that is done below). | 160 // the frame (that is done below). |
| 160 FrameScope frame_scope(masm_, StackFrame::MANUAL); | 161 FrameScope frame_scope(masm_, StackFrame::MANUAL); |
| 161 | 162 |
| 162 info->set_prologue_offset(masm_->pc_offset()); | 163 info->set_prologue_offset(masm_->pc_offset()); |
| 163 __ Prologue(BUILD_FUNCTION_FRAME); | 164 __ Prologue(BUILD_FUNCTION_FRAME); |
| 164 info->AddNoFrameRange(0, masm_->pc_offset()); | 165 info->AddNoFrameRange(0, masm_->pc_offset()); |
| 166 __ LoadConstantPoolPointerRegister(); |
| 165 | 167 |
| 166 { Comment cmnt(masm_, "[ Allocate locals"); | 168 { Comment cmnt(masm_, "[ Allocate locals"); |
| 167 int locals_count = info->scope()->num_stack_slots(); | 169 int locals_count = info->scope()->num_stack_slots(); |
| 168 // Generators allocate locals, if any, in context slots. | 170 // Generators allocate locals, if any, in context slots. |
| 169 ASSERT(!info->function()->is_generator() || locals_count == 0); | 171 ASSERT(!info->function()->is_generator() || locals_count == 0); |
| 170 if (locals_count > 0) { | 172 if (locals_count > 0) { |
| 171 // Emit a loop to initialize stack cells for locals when optimizing for | 173 // Emit a loop to initialize stack cells for locals when optimizing for |
| 172 // size. Otherwise, unroll the loop for maximum performance. | 174 // size. Otherwise, unroll the loop for maximum performance. |
| 173 __ LoadRoot(r9, Heap::kUndefinedValueRootIndex); | 175 __ LoadRoot(r9, Heap::kUndefinedValueRootIndex); |
| 174 if (FLAG_optimize_for_size && locals_count > 4) { | 176 if (FLAG_optimize_for_size && locals_count > 4) { |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { | 329 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { |
| 328 __ mov(r2, Operand(profiling_counter_)); | 330 __ mov(r2, Operand(profiling_counter_)); |
| 329 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset)); | 331 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset)); |
| 330 __ sub(r3, r3, Operand(Smi::FromInt(delta)), SetCC); | 332 __ sub(r3, r3, Operand(Smi::FromInt(delta)), SetCC); |
| 331 __ str(r3, FieldMemOperand(r2, Cell::kValueOffset)); | 333 __ str(r3, FieldMemOperand(r2, Cell::kValueOffset)); |
| 332 } | 334 } |
| 333 | 335 |
| 334 | 336 |
| 335 void FullCodeGenerator::EmitProfilingCounterReset() { | 337 void FullCodeGenerator::EmitProfilingCounterReset() { |
| 336 int reset_value = FLAG_interrupt_budget; | 338 int reset_value = FLAG_interrupt_budget; |
| 337 if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) { | |
| 338 // Self-optimization is a one-off thing: if it fails, don't try again. | |
| 339 reset_value = Smi::kMaxValue; | |
| 340 } | |
| 341 if (isolate()->IsDebuggerActive()) { | 339 if (isolate()->IsDebuggerActive()) { |
| 342 // Detect debug break requests as soon as possible. | 340 // Detect debug break requests as soon as possible. |
| 343 reset_value = FLAG_interrupt_budget >> 4; | 341 reset_value = FLAG_interrupt_budget >> 4; |
| 344 } | 342 } |
| 345 __ mov(r2, Operand(profiling_counter_)); | 343 __ mov(r2, Operand(profiling_counter_)); |
| 346 __ mov(r3, Operand(Smi::FromInt(reset_value))); | 344 __ mov(r3, Operand(Smi::FromInt(reset_value))); |
| 347 __ str(r3, FieldMemOperand(r2, Cell::kValueOffset)); | 345 __ str(r3, FieldMemOperand(r2, Cell::kValueOffset)); |
| 348 } | 346 } |
| 349 | 347 |
| 350 | 348 |
| 351 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, | 349 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, |
| 352 Label* back_edge_target) { | 350 Label* back_edge_target) { |
| 353 Comment cmnt(masm_, "[ Back edge bookkeeping"); | 351 Comment cmnt(masm_, "[ Back edge bookkeeping"); |
| 354 // Block literal pools whilst emitting back edge code. | 352 // Block literal pools whilst emitting back edge code. |
| 355 Assembler::BlockConstPoolScope block_const_pool(masm_); | 353 Assembler::BlockConstPoolScope block_const_pool(masm_); |
| 356 Label ok; | 354 Label ok; |
| 357 | 355 |
| 358 int weight = 1; | 356 ASSERT(back_edge_target->is_bound()); |
| 359 if (FLAG_weighted_back_edges) { | 357 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); |
| 360 ASSERT(back_edge_target->is_bound()); | 358 int weight = Min(kMaxBackEdgeWeight, |
| 361 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); | 359 Max(1, distance / kCodeSizeMultiplier)); |
| 362 weight = Min(kMaxBackEdgeWeight, | |
| 363 Max(1, distance / kCodeSizeMultiplier)); | |
| 364 } | |
| 365 EmitProfilingCounterDecrement(weight); | 360 EmitProfilingCounterDecrement(weight); |
| 366 __ b(pl, &ok); | 361 __ b(pl, &ok); |
| 367 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); | 362 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); |
| 368 | 363 |
| 369 // Record a mapping of this PC offset to the OSR id. This is used to find | 364 // Record a mapping of this PC offset to the OSR id. This is used to find |
| 370 // the AST id from the unoptimized code in order to use it as a key into | 365 // the AST id from the unoptimized code in order to use it as a key into |
| 371 // the deoptimization input data found in the optimized code. | 366 // the deoptimization input data found in the optimized code. |
| 372 RecordBackEdge(stmt->OsrEntryId()); | 367 RecordBackEdge(stmt->OsrEntryId()); |
| 373 | 368 |
| 374 EmitProfilingCounterReset(); | 369 EmitProfilingCounterReset(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 387 if (return_label_.is_bound()) { | 382 if (return_label_.is_bound()) { |
| 388 __ b(&return_label_); | 383 __ b(&return_label_); |
| 389 } else { | 384 } else { |
| 390 __ bind(&return_label_); | 385 __ bind(&return_label_); |
| 391 if (FLAG_trace) { | 386 if (FLAG_trace) { |
| 392 // Push the return value on the stack as the parameter. | 387 // Push the return value on the stack as the parameter. |
| 393 // Runtime::TraceExit returns its parameter in r0. | 388 // Runtime::TraceExit returns its parameter in r0. |
| 394 __ push(r0); | 389 __ push(r0); |
| 395 __ CallRuntime(Runtime::kTraceExit, 1); | 390 __ CallRuntime(Runtime::kTraceExit, 1); |
| 396 } | 391 } |
| 397 if (FLAG_interrupt_at_exit || FLAG_self_optimization) { | 392 // Pretend that the exit is a backwards jump to the entry. |
| 398 // Pretend that the exit is a backwards jump to the entry. | 393 int weight = 1; |
| 399 int weight = 1; | 394 if (info_->ShouldSelfOptimize()) { |
| 400 if (info_->ShouldSelfOptimize()) { | 395 weight = FLAG_interrupt_budget / FLAG_self_opt_count; |
| 401 weight = FLAG_interrupt_budget / FLAG_self_opt_count; | 396 } else { |
| 402 } else if (FLAG_weighted_back_edges) { | 397 int distance = masm_->pc_offset(); |
| 403 int distance = masm_->pc_offset(); | 398 weight = Min(kMaxBackEdgeWeight, |
| 404 weight = Min(kMaxBackEdgeWeight, | 399 Max(1, distance / kCodeSizeMultiplier)); |
| 405 Max(1, distance / kCodeSizeMultiplier)); | |
| 406 } | |
| 407 EmitProfilingCounterDecrement(weight); | |
| 408 Label ok; | |
| 409 __ b(pl, &ok); | |
| 410 __ push(r0); | |
| 411 if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) { | |
| 412 __ ldr(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | |
| 413 __ push(r2); | |
| 414 __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1); | |
| 415 } else { | |
| 416 __ Call(isolate()->builtins()->InterruptCheck(), | |
| 417 RelocInfo::CODE_TARGET); | |
| 418 } | |
| 419 __ pop(r0); | |
| 420 EmitProfilingCounterReset(); | |
| 421 __ bind(&ok); | |
| 422 } | 400 } |
| 401 EmitProfilingCounterDecrement(weight); |
| 402 Label ok; |
| 403 __ b(pl, &ok); |
| 404 __ push(r0); |
| 405 __ Call(isolate()->builtins()->InterruptCheck(), |
| 406 RelocInfo::CODE_TARGET); |
| 407 __ pop(r0); |
| 408 EmitProfilingCounterReset(); |
| 409 __ bind(&ok); |
| 423 | 410 |
| 424 #ifdef DEBUG | 411 #ifdef DEBUG |
| 425 // Add a label for checking the size of the code used for returning. | 412 // Add a label for checking the size of the code used for returning. |
| 426 Label check_exit_codesize; | 413 Label check_exit_codesize; |
| 427 masm_->bind(&check_exit_codesize); | 414 __ bind(&check_exit_codesize); |
| 428 #endif | 415 #endif |
| 429 // Make sure that the constant pool is not emitted inside of the return | 416 // Make sure that the constant pool is not emitted inside of the return |
| 430 // sequence. | 417 // sequence. |
| 431 { Assembler::BlockConstPoolScope block_const_pool(masm_); | 418 { Assembler::BlockConstPoolScope block_const_pool(masm_); |
| 432 // Here we use masm_-> instead of the __ macro to avoid the code coverage | |
| 433 // tool from instrumenting as we rely on the code size here. | |
| 434 int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize; | 419 int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize; |
| 435 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); | 420 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); |
| 436 // TODO(svenpanne) The code below is sometimes 4 words, sometimes 5! | 421 // TODO(svenpanne) The code below is sometimes 4 words, sometimes 5! |
| 437 PredictableCodeSizeScope predictable(masm_, -1); | 422 PredictableCodeSizeScope predictable(masm_, -1); |
| 438 __ RecordJSReturn(); | 423 __ RecordJSReturn(); |
| 439 masm_->mov(sp, fp); | 424 int no_frame_start = __ LeaveFrame(StackFrame::JAVA_SCRIPT); |
| 440 int no_frame_start = masm_->pc_offset(); | 425 __ add(sp, sp, Operand(sp_delta)); |
| 441 masm_->ldm(ia_w, sp, fp.bit() | lr.bit()); | 426 __ Jump(lr); |
| 442 masm_->add(sp, sp, Operand(sp_delta)); | |
| 443 masm_->Jump(lr); | |
| 444 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset()); | 427 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset()); |
| 445 } | 428 } |
| 446 | 429 |
| 447 #ifdef DEBUG | 430 #ifdef DEBUG |
| 448 // Check that the size of the code used for returning is large enough | 431 // Check that the size of the code used for returning is large enough |
| 449 // for the debugger's requirements. | 432 // for the debugger's requirements. |
| 450 ASSERT(Assembler::kJSReturnSequenceInstructions <= | 433 ASSERT(Assembler::kJSReturnSequenceInstructions <= |
| 451 masm_->InstructionsGeneratedSince(&check_exit_codesize)); | 434 masm_->InstructionsGeneratedSince(&check_exit_codesize)); |
| 452 #endif | 435 #endif |
| 453 } | 436 } |
| (...skipping 579 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1033 __ b(clause->body_target()); | 1016 __ b(clause->body_target()); |
| 1034 __ bind(&slow_case); | 1017 __ bind(&slow_case); |
| 1035 } | 1018 } |
| 1036 | 1019 |
| 1037 // Record position before stub call for type feedback. | 1020 // Record position before stub call for type feedback. |
| 1038 SetSourcePosition(clause->position()); | 1021 SetSourcePosition(clause->position()); |
| 1039 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); | 1022 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); |
| 1040 CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId()); | 1023 CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId()); |
| 1041 patch_site.EmitPatchInfo(); | 1024 patch_site.EmitPatchInfo(); |
| 1042 | 1025 |
| 1026 Label skip; |
| 1027 __ b(&skip); |
| 1028 PrepareForBailout(clause, TOS_REG); |
| 1029 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 1030 __ cmp(r0, ip); |
| 1031 __ b(ne, &next_test); |
| 1032 __ Drop(1); |
| 1033 __ jmp(clause->body_target()); |
| 1034 __ bind(&skip); |
| 1035 |
| 1043 __ cmp(r0, Operand::Zero()); | 1036 __ cmp(r0, Operand::Zero()); |
| 1044 __ b(ne, &next_test); | 1037 __ b(ne, &next_test); |
| 1045 __ Drop(1); // Switch value is no longer needed. | 1038 __ Drop(1); // Switch value is no longer needed. |
| 1046 __ b(clause->body_target()); | 1039 __ b(clause->body_target()); |
| 1047 } | 1040 } |
| 1048 | 1041 |
| 1049 // Discard the test value and jump to the default if present, otherwise to | 1042 // Discard the test value and jump to the default if present, otherwise to |
| 1050 // the end of the statement. | 1043 // the end of the statement. |
| 1051 __ bind(&next_test); | 1044 __ bind(&next_test); |
| 1052 __ Drop(1); // Switch value is no longer needed. | 1045 __ Drop(1); // Switch value is no longer needed. |
| (...skipping 1109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2162 | 2155 |
| 2163 // Enter a new JavaScript frame, and initialize its slots as they were when | 2156 // Enter a new JavaScript frame, and initialize its slots as they were when |
| 2164 // the generator was suspended. | 2157 // the generator was suspended. |
| 2165 Label resume_frame; | 2158 Label resume_frame; |
| 2166 __ bind(&push_frame); | 2159 __ bind(&push_frame); |
| 2167 __ bl(&resume_frame); | 2160 __ bl(&resume_frame); |
| 2168 __ jmp(&done); | 2161 __ jmp(&done); |
| 2169 __ bind(&resume_frame); | 2162 __ bind(&resume_frame); |
| 2170 // lr = return address. | 2163 // lr = return address. |
| 2171 // fp = caller's frame pointer. | 2164 // fp = caller's frame pointer. |
| 2165 // pp = caller's constant pool (if FLAG_enable_ool_constant_pool), |
| 2172 // cp = callee's context, | 2166 // cp = callee's context, |
| 2173 // r4 = callee's JS function. | 2167 // r4 = callee's JS function. |
| 2174 __ Push(lr, fp, cp, r4); | 2168 __ PushFixedFrame(r4); |
| 2175 // Adjust FP to point to saved FP. | 2169 // Adjust FP to point to saved FP. |
| 2176 __ add(fp, sp, Operand(2 * kPointerSize)); | 2170 __ add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); |
| 2177 | 2171 |
| 2178 // Load the operand stack size. | 2172 // Load the operand stack size. |
| 2179 __ ldr(r3, FieldMemOperand(r1, JSGeneratorObject::kOperandStackOffset)); | 2173 __ ldr(r3, FieldMemOperand(r1, JSGeneratorObject::kOperandStackOffset)); |
| 2180 __ ldr(r3, FieldMemOperand(r3, FixedArray::kLengthOffset)); | 2174 __ ldr(r3, FieldMemOperand(r3, FixedArray::kLengthOffset)); |
| 2181 __ SmiUntag(r3); | 2175 __ SmiUntag(r3); |
| 2182 | 2176 |
| 2183 // If we are sending a value and there is no operand stack, we can jump back | 2177 // If we are sending a value and there is no operand stack, we can jump back |
| 2184 // in directly. | 2178 // in directly. |
| 2185 if (resume_mode == JSGeneratorObject::NEXT) { | 2179 if (resume_mode == JSGeneratorObject::NEXT) { |
| 2186 Label slow_resume; | 2180 Label slow_resume; |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2447 __ ldr(r1, GlobalObjectOperand()); | 2441 __ ldr(r1, GlobalObjectOperand()); |
| 2448 Handle<Code> ic = is_classic_mode() | 2442 Handle<Code> ic = is_classic_mode() |
| 2449 ? isolate()->builtins()->StoreIC_Initialize() | 2443 ? isolate()->builtins()->StoreIC_Initialize() |
| 2450 : isolate()->builtins()->StoreIC_Initialize_Strict(); | 2444 : isolate()->builtins()->StoreIC_Initialize_Strict(); |
| 2451 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | 2445 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 2452 | 2446 |
| 2453 } else if (op == Token::INIT_CONST) { | 2447 } else if (op == Token::INIT_CONST) { |
| 2454 // Const initializers need a write barrier. | 2448 // Const initializers need a write barrier. |
| 2455 ASSERT(!var->IsParameter()); // No const parameters. | 2449 ASSERT(!var->IsParameter()); // No const parameters. |
| 2456 if (var->IsStackLocal()) { | 2450 if (var->IsStackLocal()) { |
| 2457 Label skip; | |
| 2458 __ ldr(r1, StackOperand(var)); | 2451 __ ldr(r1, StackOperand(var)); |
| 2459 __ CompareRoot(r1, Heap::kTheHoleValueRootIndex); | 2452 __ CompareRoot(r1, Heap::kTheHoleValueRootIndex); |
| 2460 __ b(ne, &skip); | 2453 __ str(result_register(), StackOperand(var), eq); |
| 2461 __ str(result_register(), StackOperand(var)); | |
| 2462 __ bind(&skip); | |
| 2463 } else { | 2454 } else { |
| 2464 ASSERT(var->IsContextSlot() || var->IsLookupSlot()); | 2455 ASSERT(var->IsContextSlot() || var->IsLookupSlot()); |
| 2465 // Like var declarations, const declarations are hoisted to function | 2456 // Like var declarations, const declarations are hoisted to function |
| 2466 // scope. However, unlike var initializers, const initializers are | 2457 // scope. However, unlike var initializers, const initializers are |
| 2467 // able to drill a hole to that function context, even from inside a | 2458 // able to drill a hole to that function context, even from inside a |
| 2468 // 'with' context. We thus bypass the normal static scope lookup for | 2459 // 'with' context. We thus bypass the normal static scope lookup for |
| 2469 // var->IsContextSlot(). | 2460 // var->IsContextSlot(). |
| 2470 __ push(r0); | 2461 __ push(r0); |
| 2471 __ mov(r0, Operand(var->name())); | 2462 __ mov(r0, Operand(var->name())); |
| 2472 __ Push(cp, r0); // Context and name. | 2463 __ Push(cp, r0); // Context and name. |
| (...skipping 716 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3189 Label* if_true = NULL; | 3180 Label* if_true = NULL; |
| 3190 Label* if_false = NULL; | 3181 Label* if_false = NULL; |
| 3191 Label* fall_through = NULL; | 3182 Label* fall_through = NULL; |
| 3192 context()->PrepareTest(&materialize_true, &materialize_false, | 3183 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3193 &if_true, &if_false, &fall_through); | 3184 &if_true, &if_false, &fall_through); |
| 3194 | 3185 |
| 3195 // Get the frame pointer for the calling frame. | 3186 // Get the frame pointer for the calling frame. |
| 3196 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 3187 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 3197 | 3188 |
| 3198 // Skip the arguments adaptor frame if it exists. | 3189 // Skip the arguments adaptor frame if it exists. |
| 3199 Label check_frame_marker; | |
| 3200 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kContextOffset)); | 3190 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kContextOffset)); |
| 3201 __ cmp(r1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 3191 __ cmp(r1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 3202 __ b(ne, &check_frame_marker); | 3192 __ ldr(r2, MemOperand(r2, StandardFrameConstants::kCallerFPOffset), eq); |
| 3203 __ ldr(r2, MemOperand(r2, StandardFrameConstants::kCallerFPOffset)); | |
| 3204 | 3193 |
| 3205 // Check the marker in the calling frame. | 3194 // Check the marker in the calling frame. |
| 3206 __ bind(&check_frame_marker); | |
| 3207 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset)); | 3195 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset)); |
| 3208 __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT))); | 3196 __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT))); |
| 3209 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 3197 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 3210 Split(eq, if_true, if_false, fall_through); | 3198 Split(eq, if_true, if_false, fall_through); |
| 3211 | 3199 |
| 3212 context()->Plug(if_true, if_false); | 3200 context()->Plug(if_true, if_false); |
| 3213 } | 3201 } |
| 3214 | 3202 |
| 3215 | 3203 |
| 3216 void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) { | 3204 void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 3247 __ mov(r1, r0); | 3235 __ mov(r1, r0); |
| 3248 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters()))); | 3236 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters()))); |
| 3249 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 3237 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 3250 __ CallStub(&stub); | 3238 __ CallStub(&stub); |
| 3251 context()->Plug(r0); | 3239 context()->Plug(r0); |
| 3252 } | 3240 } |
| 3253 | 3241 |
| 3254 | 3242 |
| 3255 void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { | 3243 void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) { |
| 3256 ASSERT(expr->arguments()->length() == 0); | 3244 ASSERT(expr->arguments()->length() == 0); |
| 3257 Label exit; | 3245 |
| 3258 // Get the number of formal parameters. | 3246 // Get the number of formal parameters. |
| 3259 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters()))); | 3247 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters()))); |
| 3260 | 3248 |
| 3261 // Check if the calling frame is an arguments adaptor frame. | 3249 // Check if the calling frame is an arguments adaptor frame. |
| 3262 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 3250 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 3263 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); | 3251 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); |
| 3264 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 3252 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 3265 __ b(ne, &exit); | |
| 3266 | 3253 |
| 3267 // Arguments adaptor case: Read the arguments length from the | 3254 // Arguments adaptor case: Read the arguments length from the |
| 3268 // adaptor frame. | 3255 // adaptor frame. |
| 3269 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 3256 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset), eq); |
| 3270 | 3257 |
| 3271 __ bind(&exit); | |
| 3272 context()->Plug(r0); | 3258 context()->Plug(r0); |
| 3273 } | 3259 } |
| 3274 | 3260 |
| 3275 | 3261 |
| 3276 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { | 3262 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { |
| 3277 ZoneList<Expression*>* args = expr->arguments(); | 3263 ZoneList<Expression*>* args = expr->arguments(); |
| 3278 ASSERT(args->length() == 1); | 3264 ASSERT(args->length() == 1); |
| 3279 Label done, null, function, non_function_constructor; | 3265 Label done, null, function, non_function_constructor; |
| 3280 | 3266 |
| 3281 VisitForAccumulatorValue(args->at(0)); | 3267 VisitForAccumulatorValue(args->at(0)); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3386 void FullCodeGenerator::EmitValueOf(CallRuntime* expr) { | 3372 void FullCodeGenerator::EmitValueOf(CallRuntime* expr) { |
| 3387 ZoneList<Expression*>* args = expr->arguments(); | 3373 ZoneList<Expression*>* args = expr->arguments(); |
| 3388 ASSERT(args->length() == 1); | 3374 ASSERT(args->length() == 1); |
| 3389 VisitForAccumulatorValue(args->at(0)); // Load the object. | 3375 VisitForAccumulatorValue(args->at(0)); // Load the object. |
| 3390 | 3376 |
| 3391 Label done; | 3377 Label done; |
| 3392 // If the object is a smi return the object. | 3378 // If the object is a smi return the object. |
| 3393 __ JumpIfSmi(r0, &done); | 3379 __ JumpIfSmi(r0, &done); |
| 3394 // If the object is not a value type, return the object. | 3380 // If the object is not a value type, return the object. |
| 3395 __ CompareObjectType(r0, r1, r1, JS_VALUE_TYPE); | 3381 __ CompareObjectType(r0, r1, r1, JS_VALUE_TYPE); |
| 3396 __ b(ne, &done); | 3382 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset), eq); |
| 3397 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); | |
| 3398 | 3383 |
| 3399 __ bind(&done); | 3384 __ bind(&done); |
| 3400 context()->Plug(r0); | 3385 context()->Plug(r0); |
| 3401 } | 3386 } |
| 3402 | 3387 |
| 3403 | 3388 |
| 3404 void FullCodeGenerator::EmitDateField(CallRuntime* expr) { | 3389 void FullCodeGenerator::EmitDateField(CallRuntime* expr) { |
| 3405 ZoneList<Expression*>* args = expr->arguments(); | 3390 ZoneList<Expression*>* args = expr->arguments(); |
| 3406 ASSERT(args->length() == 2); | 3391 ASSERT(args->length() == 2); |
| 3407 ASSERT_NE(NULL, args->at(1)->AsLiteral()); | 3392 ASSERT_NE(NULL, args->at(1)->AsLiteral()); |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3706 VisitForStackValue(args->at(0)); | 3691 VisitForStackValue(args->at(0)); |
| 3707 VisitForStackValue(args->at(1)); | 3692 VisitForStackValue(args->at(1)); |
| 3708 | 3693 |
| 3709 StringCompareStub stub; | 3694 StringCompareStub stub; |
| 3710 __ CallStub(&stub); | 3695 __ CallStub(&stub); |
| 3711 context()->Plug(r0); | 3696 context()->Plug(r0); |
| 3712 } | 3697 } |
| 3713 | 3698 |
| 3714 | 3699 |
| 3715 void FullCodeGenerator::EmitMathLog(CallRuntime* expr) { | 3700 void FullCodeGenerator::EmitMathLog(CallRuntime* expr) { |
| 3716 // Load the argument on the stack and call the stub. | 3701 // Load the argument on the stack and call the runtime function. |
| 3717 TranscendentalCacheStub stub(TranscendentalCache::LOG, | |
| 3718 TranscendentalCacheStub::TAGGED); | |
| 3719 ZoneList<Expression*>* args = expr->arguments(); | 3702 ZoneList<Expression*>* args = expr->arguments(); |
| 3720 ASSERT(args->length() == 1); | 3703 ASSERT(args->length() == 1); |
| 3721 VisitForStackValue(args->at(0)); | 3704 VisitForStackValue(args->at(0)); |
| 3722 __ CallStub(&stub); | 3705 __ CallRuntime(Runtime::kMath_log, 1); |
| 3723 context()->Plug(r0); | 3706 context()->Plug(r0); |
| 3724 } | 3707 } |
| 3725 | 3708 |
| 3726 | 3709 |
| 3727 void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) { | 3710 void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) { |
| 3728 // Load the argument on the stack and call the runtime function. | 3711 // Load the argument on the stack and call the runtime function. |
| 3729 ZoneList<Expression*>* args = expr->arguments(); | 3712 ZoneList<Expression*>* args = expr->arguments(); |
| 3730 ASSERT(args->length() == 1); | 3713 ASSERT(args->length() == 1); |
| 3731 VisitForStackValue(args->at(0)); | 3714 VisitForStackValue(args->at(0)); |
| 3732 __ CallRuntime(Runtime::kMath_sqrt, 1); | 3715 __ CallRuntime(Runtime::kMath_sqrt, 1); |
| (...skipping 1195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4928 ASSERT(Memory::uint32_at(interrupt_address_pointer) == | 4911 ASSERT(Memory::uint32_at(interrupt_address_pointer) == |
| 4929 reinterpret_cast<uint32_t>( | 4912 reinterpret_cast<uint32_t>( |
| 4930 isolate->builtins()->OsrAfterStackCheck()->entry())); | 4913 isolate->builtins()->OsrAfterStackCheck()->entry())); |
| 4931 return OSR_AFTER_STACK_CHECK; | 4914 return OSR_AFTER_STACK_CHECK; |
| 4932 } | 4915 } |
| 4933 | 4916 |
| 4934 | 4917 |
| 4935 } } // namespace v8::internal | 4918 } } // namespace v8::internal |
| 4936 | 4919 |
| 4937 #endif // V8_TARGET_ARCH_ARM | 4920 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |