| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 // - fp: our caller's frame pointer. | 122 // - fp: our caller's frame pointer. |
| 123 // - jssp: stack pointer. | 123 // - jssp: stack pointer. |
| 124 // - lr: return address. | 124 // - lr: return address. |
| 125 // | 125 // |
| 126 // The function builds a JS frame. See JavaScriptFrameConstants in | 126 // The function builds a JS frame. See JavaScriptFrameConstants in |
| 127 // frames-arm.h for its layout. | 127 // frames-arm.h for its layout. |
| 128 void FullCodeGenerator::Generate() { | 128 void FullCodeGenerator::Generate() { |
| 129 CompilationInfo* info = info_; | 129 CompilationInfo* info = info_; |
| 130 handler_table_ = | 130 handler_table_ = |
| 131 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); | 131 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); |
| 132 profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell( | 132 profiling_counter_ = isolate()->factory()->NewCell( |
| 133 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); | 133 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); |
| 134 SetFunctionPosition(function()); | 134 SetFunctionPosition(function()); |
| 135 Comment cmnt(masm_, "[ Function compiled by full code generator"); | 135 Comment cmnt(masm_, "[ Function compiled by full code generator"); |
| 136 | 136 |
| 137 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 137 ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| 138 | 138 |
| 139 #ifdef DEBUG | 139 #ifdef DEBUG |
| 140 if (strlen(FLAG_stop_at) > 0 && | 140 if (strlen(FLAG_stop_at) > 0 && |
| 141 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 141 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| 142 __ Debug("stop-at", __LINE__, BREAK); | 142 __ Debug("stop-at", __LINE__, BREAK); |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 | 316 |
| 317 | 317 |
| 318 void FullCodeGenerator::ClearAccumulator() { | 318 void FullCodeGenerator::ClearAccumulator() { |
| 319 __ Mov(x0, Operand(Smi::FromInt(0))); | 319 __ Mov(x0, Operand(Smi::FromInt(0))); |
| 320 } | 320 } |
| 321 | 321 |
| 322 | 322 |
| 323 // TODO(mcapewel): untested, ported as part of merge. | 323 // TODO(mcapewel): untested, ported as part of merge. |
| 324 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { | 324 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { |
| 325 __ Mov(x2, Operand(profiling_counter_)); | 325 __ Mov(x2, Operand(profiling_counter_)); |
| 326 __ Ldr(x3, FieldMemOperand(x2, JSGlobalPropertyCell::kValueOffset)); | 326 __ Ldr(x3, FieldMemOperand(x2, Cell::kValueOffset)); |
| 327 __ Subs(x3, x3, Operand(Smi::FromInt(delta))); | 327 __ Subs(x3, x3, Operand(Smi::FromInt(delta))); |
| 328 __ Str(x3, FieldMemOperand(x2, JSGlobalPropertyCell::kValueOffset)); | 328 __ Str(x3, FieldMemOperand(x2, Cell::kValueOffset)); |
| 329 } | 329 } |
| 330 | 330 |
| 331 | 331 |
| 332 // TODO(mcapewel): untested, ported as part of merge. | 332 // TODO(mcapewel): untested, ported as part of merge. |
| 333 void FullCodeGenerator::EmitProfilingCounterReset() { | 333 void FullCodeGenerator::EmitProfilingCounterReset() { |
| 334 int reset_value = FLAG_interrupt_budget; | 334 int reset_value = FLAG_interrupt_budget; |
| 335 if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) { | 335 if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) { |
| 336 // Self-optimization is a one-off thing. if it fails, don't try again. | 336 // Self-optimization is a one-off thing. if it fails, don't try again. |
| 337 reset_value = Smi::kMaxValue; | 337 reset_value = Smi::kMaxValue; |
| 338 } | 338 } |
| 339 if (isolate()->IsDebuggerActive()) { | 339 if (isolate()->IsDebuggerActive()) { |
| 340 // Detect debug break requests as soon as possible. | 340 // Detect debug break requests as soon as possible. |
| 341 reset_value = FLAG_interrupt_budget >> 4; | 341 reset_value = FLAG_interrupt_budget >> 4; |
| 342 } | 342 } |
| 343 __ Mov(x2, Operand(profiling_counter_)); | 343 __ Mov(x2, Operand(profiling_counter_)); |
| 344 __ Mov(x3, Operand(Smi::FromInt(reset_value))); | 344 __ Mov(x3, Operand(Smi::FromInt(reset_value))); |
| 345 __ Str(x3, FieldMemOperand(x2, JSGlobalPropertyCell::kValueOffset)); | 345 __ Str(x3, FieldMemOperand(x2, Cell::kValueOffset)); |
| 346 } | 346 } |
| 347 | 347 |
| 348 | 348 |
| 349 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, | 349 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, |
| 350 Label* back_edge_target) { | 350 Label* back_edge_target) { |
| 351 ASSERT(jssp.Is(__ StackPointer())); | 351 ASSERT(jssp.Is(__ StackPointer())); |
| 352 Comment cmnt(masm_, "[ Back edge bookkeeping"); | 352 Comment cmnt(masm_, "[ Back edge bookkeeping"); |
| 353 // Block literal pools whilst emitting back edge code. | 353 // Block literal pools whilst emitting back edge code. |
| 354 Assembler::BlockConstPoolScope block_const_pool(masm_); | 354 Assembler::BlockConstPoolScope block_const_pool(masm_); |
| 355 Label ok; | 355 Label ok; |
| 356 | 356 |
| 357 int weight = 1; | 357 int weight = 1; |
| 358 if (FLAG_weighted_back_edges) { | 358 if (FLAG_weighted_back_edges) { |
| 359 ASSERT(back_edge_target->is_bound()); | 359 ASSERT(back_edge_target->is_bound()); |
| 360 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); | 360 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target); |
| 361 weight = Min(kMaxBackEdgeWeight, | 361 weight = Min(kMaxBackEdgeWeight, |
| 362 Max(1, distance / kBackEdgeDistanceUnit)); | 362 Max(1, distance / kCodeSizeMultiplier)); |
| 363 } | 363 } |
| 364 EmitProfilingCounterDecrement(weight); | 364 EmitProfilingCounterDecrement(weight); |
| 365 __ B(pl, &ok); | 365 __ B(pl, &ok); |
| 366 InterruptStub stub; | 366 InterruptStub stub; |
| 367 __ CallStub(&stub); | 367 __ CallStub(&stub); |
| 368 | 368 |
| 369 // TODO(all): Implement OSR/Crankshaft code. | 369 // TODO(all): Implement OSR/Crankshaft code. |
| 370 | 370 |
| 371 EmitProfilingCounterReset(); | 371 EmitProfilingCounterReset(); |
| 372 | 372 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 396 ASSERT(x0.Is(result_register())); | 396 ASSERT(x0.Is(result_register())); |
| 397 } | 397 } |
| 398 if (FLAG_interrupt_at_exit || FLAG_self_optimization) { | 398 if (FLAG_interrupt_at_exit || FLAG_self_optimization) { |
| 399 // Pretend that the exit is a backwards jump to the entry. | 399 // Pretend that the exit is a backwards jump to the entry. |
| 400 int weight = 1; | 400 int weight = 1; |
| 401 if (info_->ShouldSelfOptimize()) { | 401 if (info_->ShouldSelfOptimize()) { |
| 402 weight = FLAG_interrupt_budget / FLAG_self_opt_count; | 402 weight = FLAG_interrupt_budget / FLAG_self_opt_count; |
| 403 } else if (FLAG_weighted_back_edges) { | 403 } else if (FLAG_weighted_back_edges) { |
| 404 int distance = masm_->pc_offset(); | 404 int distance = masm_->pc_offset(); |
| 405 weight = Min(kMaxBackEdgeWeight, | 405 weight = Min(kMaxBackEdgeWeight, |
| 406 Max(1, distance / kBackEdgeDistanceUnit)); | 406 Max(1, distance / kCodeSizeMultiplier)); |
| 407 } | 407 } |
| 408 EmitProfilingCounterDecrement(weight); | 408 EmitProfilingCounterDecrement(weight); |
| 409 Label ok; | 409 Label ok; |
| 410 __ B(pl, &ok); | 410 __ B(pl, &ok); |
| 411 __ Push(x0); | 411 __ Push(x0); |
| 412 if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) { | 412 if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) { |
| 413 __ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 413 __ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 414 __ Push(x10); | 414 __ Push(x10); |
| 415 __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1); | 415 __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1); |
| 416 } else { | 416 } else { |
| (...skipping 741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1158 __ B(&loop); | 1158 __ B(&loop); |
| 1159 | 1159 |
| 1160 __ Bind(&no_descriptors); | 1160 __ Bind(&no_descriptors); |
| 1161 __ Drop(1); | 1161 __ Drop(1); |
| 1162 __ B(&exit); | 1162 __ B(&exit); |
| 1163 | 1163 |
| 1164 // We got a fixed array in register x0. Iterate through that. | 1164 // We got a fixed array in register x0. Iterate through that. |
| 1165 Label non_proxy; | 1165 Label non_proxy; |
| 1166 __ Bind(&fixed_array); | 1166 __ Bind(&fixed_array); |
| 1167 | 1167 |
| 1168 Handle<JSGlobalPropertyCell> cell = | 1168 Handle<Cell> cell = isolate()->factory()->NewCell( |
| 1169 isolate()->factory()->NewJSGlobalPropertyCell( | 1169 Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), |
| 1170 Handle<Object>( | 1170 isolate())); |
| 1171 Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), | |
| 1172 isolate())); | |
| 1173 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); | 1171 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); |
| 1174 __ LoadHeapObject(x1, cell); | 1172 __ LoadHeapObject(x1, cell); |
| 1175 __ Mov(x10, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); | 1173 __ Mov(x10, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); |
| 1176 __ Str(x10, FieldMemOperand(x1, JSGlobalPropertyCell::kValueOffset)); | 1174 __ Str(x10, FieldMemOperand(x1, Cell::kValueOffset)); |
| 1177 | 1175 |
| 1178 __ Mov(x1, Operand(Smi::FromInt(1))); // Smi indicates slow check. | 1176 __ Mov(x1, Operand(Smi::FromInt(1))); // Smi indicates slow check. |
| 1179 __ Peek(x10, 0); // Get enumerated object. | 1177 __ Peek(x10, 0); // Get enumerated object. |
| 1180 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 1178 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 1181 // TODO(all): similar check was done already. Can we avoid it here? | 1179 // TODO(all): similar check was done already. Can we avoid it here? |
| 1182 __ JumpIfObjectType(x10, x11, x12, LAST_JS_PROXY_TYPE, &non_proxy, gt); | 1180 __ JumpIfObjectType(x10, x11, x12, LAST_JS_PROXY_TYPE, &non_proxy, gt); |
| 1183 // TODO(all): use csel here | 1181 // TODO(all): use csel here |
| 1184 __ Mov(x1, Operand(Smi::FromInt(0))); // Zero indicates proxy. | 1182 __ Mov(x1, Operand(Smi::FromInt(0))); // Zero indicates proxy. |
| 1185 __ Bind(&non_proxy); | 1183 __ Bind(&non_proxy); |
| 1186 __ Push(x1, x0); // Smi and array | 1184 __ Push(x1, x0); // Smi and array |
| (...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1827 Expression* subexpr = subexprs->at(i); | 1825 Expression* subexpr = subexprs->at(i); |
| 1828 // If the subexpression is a literal or a simple materialized literal it | 1826 // If the subexpression is a literal or a simple materialized literal it |
| 1829 // is already set in the cloned array. | 1827 // is already set in the cloned array. |
| 1830 if (subexpr->AsLiteral() != NULL || | 1828 if (subexpr->AsLiteral() != NULL || |
| 1831 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 1829 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
| 1832 continue; | 1830 continue; |
| 1833 } | 1831 } |
| 1834 | 1832 |
| 1835 if (!result_saved) { | 1833 if (!result_saved) { |
| 1836 __ Push(x0); | 1834 __ Push(x0); |
| 1835 __ Push(Smi::FromInt(expr->literal_index())); |
| 1837 result_saved = true; | 1836 result_saved = true; |
| 1838 } | 1837 } |
| 1839 VisitForAccumulatorValue(subexpr); | 1838 VisitForAccumulatorValue(subexpr); |
| 1840 | 1839 |
| 1841 if (IsFastObjectElementsKind(constant_elements_kind)) { | 1840 if (IsFastObjectElementsKind(constant_elements_kind)) { |
| 1842 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1841 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 1843 __ Peek(x6, 0); // Copy of array literal. | 1842 __ Peek(x6, kPointerSize); // Copy of array literal. |
| 1844 __ Ldr(x1, FieldMemOperand(x6, JSObject::kElementsOffset)); | 1843 __ Ldr(x1, FieldMemOperand(x6, JSObject::kElementsOffset)); |
| 1845 __ Str(result_register(), FieldMemOperand(x1, offset)); | 1844 __ Str(result_register(), FieldMemOperand(x1, offset)); |
| 1846 // Update the write barrier for the array store. | 1845 // Update the write barrier for the array store. |
| 1847 __ RecordWriteField(x1, offset, result_register(), x10, | 1846 __ RecordWriteField(x1, offset, result_register(), x10, |
| 1848 kLRHasBeenSaved, kDontSaveFPRegs, | 1847 kLRHasBeenSaved, kDontSaveFPRegs, |
| 1849 EMIT_REMEMBERED_SET, INLINE_SMI_CHECK); | 1848 EMIT_REMEMBERED_SET, INLINE_SMI_CHECK); |
| 1850 } else { | 1849 } else { |
| 1851 __ Peek(x1, 0); // Copy of array literal. | |
| 1852 __ Ldr(x2, FieldMemOperand(x1, JSObject::kMapOffset)); | |
| 1853 __ Mov(x3, Operand(Smi::FromInt(i))); | 1850 __ Mov(x3, Operand(Smi::FromInt(i))); |
| 1854 __ Mov(x4, Operand(Smi::FromInt(expr->literal_index()))); | |
| 1855 StoreArrayLiteralElementStub stub; | 1851 StoreArrayLiteralElementStub stub; |
| 1856 __ CallStub(&stub); | 1852 __ CallStub(&stub); |
| 1857 } | 1853 } |
| 1858 | 1854 |
| 1859 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); | 1855 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
| 1860 } | 1856 } |
| 1861 | 1857 |
| 1862 if (result_saved) { | 1858 if (result_saved) { |
| 1859 __ Drop(1); // literal index |
| 1863 context()->PlugTOS(); | 1860 context()->PlugTOS(); |
| 1864 } else { | 1861 } else { |
| 1865 context()->Plug(x0); | 1862 context()->Plug(x0); |
| 1866 } | 1863 } |
| 1867 } | 1864 } |
| 1868 | 1865 |
| 1869 | 1866 |
| 1870 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1867 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
| 1871 Comment cmnt(masm_, "[ Assignment"); | 1868 Comment cmnt(masm_, "[ Assignment"); |
| 1872 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1869 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| (...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2406 VisitForStackValue(args->at(i)); | 2403 VisitForStackValue(args->at(i)); |
| 2407 } | 2404 } |
| 2408 } | 2405 } |
| 2409 // Record source position for debugger. | 2406 // Record source position for debugger. |
| 2410 SetSourcePosition(expr->position()); | 2407 SetSourcePosition(expr->position()); |
| 2411 | 2408 |
| 2412 // Record call targets in unoptimized code. | 2409 // Record call targets in unoptimized code. |
| 2413 flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); | 2410 flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET); |
| 2414 Handle<Object> uninitialized = | 2411 Handle<Object> uninitialized = |
| 2415 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2412 TypeFeedbackCells::UninitializedSentinel(isolate()); |
| 2416 Handle<JSGlobalPropertyCell> cell = | 2413 Handle<Cell> cell = |
| 2417 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); | 2414 isolate()->factory()->NewCell(uninitialized); |
| 2418 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell); | 2415 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell); |
| 2419 __ Mov(x2, Operand(cell)); | 2416 __ Mov(x2, Operand(cell)); |
| 2420 | 2417 |
| 2421 CallFunctionStub stub(arg_count, flags); | 2418 CallFunctionStub stub(arg_count, flags); |
| 2422 __ Peek(x1, (arg_count + 1) * kXRegSizeInBytes); | 2419 __ Peek(x1, (arg_count + 1) * kXRegSizeInBytes); |
| 2423 __ CallStub(&stub, expr->CallFeedbackId()); | 2420 __ CallStub(&stub, expr->CallFeedbackId()); |
| 2424 RecordJSReturnSite(expr); | 2421 RecordJSReturnSite(expr); |
| 2425 // Restore context register. | 2422 // Restore context register. |
| 2426 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2423 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2427 context()->DropAndPlug(1, x0); | 2424 context()->DropAndPlug(1, x0); |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2612 // constructor invocation. | 2609 // constructor invocation. |
| 2613 SetSourcePosition(expr->position()); | 2610 SetSourcePosition(expr->position()); |
| 2614 | 2611 |
| 2615 // Load function and argument count into x1 and x0. | 2612 // Load function and argument count into x1 and x0. |
| 2616 __ Mov(x0, arg_count); | 2613 __ Mov(x0, arg_count); |
| 2617 __ Peek(x1, arg_count * kXRegSizeInBytes); | 2614 __ Peek(x1, arg_count * kXRegSizeInBytes); |
| 2618 | 2615 |
| 2619 // Record call targets in unoptimized code. | 2616 // Record call targets in unoptimized code. |
| 2620 Handle<Object> uninitialized = | 2617 Handle<Object> uninitialized = |
| 2621 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2618 TypeFeedbackCells::UninitializedSentinel(isolate()); |
| 2622 Handle<JSGlobalPropertyCell> cell = | 2619 Handle<Cell> cell = |
| 2623 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized); | 2620 isolate()->factory()->NewCell(uninitialized); |
| 2624 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell); | 2621 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell); |
| 2625 __ Mov(x2, Operand(cell)); | 2622 __ Mov(x2, Operand(cell)); |
| 2626 | 2623 |
| 2627 CallConstructStub stub(RECORD_CALL_TARGET); | 2624 CallConstructStub stub(RECORD_CALL_TARGET); |
| 2628 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); | 2625 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); |
| 2629 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); | 2626 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); |
| 2630 context()->Plug(x0); | 2627 context()->Plug(x0); |
| 2631 } | 2628 } |
| 2632 | 2629 |
| 2633 | 2630 |
| (...skipping 1894 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4528 } | 4525 } |
| 4529 | 4526 |
| 4530 | 4527 |
| 4531 void FullCodeGenerator::VisitYield(Yield* expr) { | 4528 void FullCodeGenerator::VisitYield(Yield* expr) { |
| 4532 Comment cmnt(masm_, "[ Yield"); | 4529 Comment cmnt(masm_, "[ Yield"); |
| 4533 // Evaluate yielded value first; the initial iterator definition depends on | 4530 // Evaluate yielded value first; the initial iterator definition depends on |
| 4534 // this. It stays on the stack while we update the iterator. | 4531 // this. It stays on the stack while we update the iterator. |
| 4535 VisitForStackValue(expr->expression()); | 4532 VisitForStackValue(expr->expression()); |
| 4536 | 4533 |
| 4537 switch (expr->yield_kind()) { | 4534 switch (expr->yield_kind()) { |
| 4538 case Yield::INITIAL: | 4535 case Yield::SUSPEND: |
| 4539 case Yield::SUSPEND: { | 4536 // Pop value from top-of-stack slot; box result into result register. |
| 4537 EmitCreateIteratorResult(false); |
| 4538 __ Push(result_register()); |
| 4539 // Fall through. |
| 4540 case Yield::INITIAL: { |
| 4540 VisitForStackValue(expr->generator_object()); | 4541 VisitForStackValue(expr->generator_object()); |
| 4541 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); | 4542 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); |
| 4542 __ Ldr(context_register(), | 4543 __ Ldr(context_register(), |
| 4543 MemOperand(fp, StandardFrameConstants::kContextOffset)); | 4544 MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 4544 | 4545 |
| 4545 Label resume; | 4546 Label resume; |
| 4546 __ JumpIfNotRoot(result_register(), Heap::kTheHoleValueRootIndex, | 4547 __ JumpIfNotRoot(result_register(), Heap::kTheHoleValueRootIndex, |
| 4547 &resume); | 4548 &resume); |
| 4548 if (expr->yield_kind() == Yield::SUSPEND) { | 4549 __ Pop(result_register()); |
| 4549 EmitReturnIteratorResult(false); | 4550 EmitReturnSequence(); |
| 4550 } else { | |
| 4551 __ Pop(result_register()); | |
| 4552 EmitReturnSequence(); | |
| 4553 } | |
| 4554 | 4551 |
| 4555 __ Bind(&resume); | 4552 __ Bind(&resume); |
| 4556 context()->Plug(result_register()); | 4553 context()->Plug(result_register()); |
| 4557 break; | 4554 break; |
| 4558 } | 4555 } |
| 4559 | 4556 |
| 4560 case Yield::FINAL: { | 4557 case Yield::FINAL: { |
| 4561 VisitForAccumulatorValue(expr->generator_object()); | 4558 VisitForAccumulatorValue(expr->generator_object()); |
| 4562 __ Mov(x1, Operand(Smi::FromInt(JSGeneratorObject::kGeneratorClosed))); | 4559 __ Mov(x1, Operand(Smi::FromInt(JSGeneratorObject::kGeneratorClosed))); |
| 4563 __ Str(x1, FieldMemOperand(result_register(), | 4560 __ Str(x1, FieldMemOperand(result_register(), |
| 4564 JSGeneratorObject::kContinuationOffset)); | 4561 JSGeneratorObject::kContinuationOffset)); |
| 4565 EmitReturnIteratorResult(true); | 4562 // Pop value from top-of-stack slot, box result into result register. |
| 4563 EmitCreateIteratorResult(true); |
| 4564 EmitUnwindBeforeReturn(); |
| 4565 EmitReturnSequence(); |
| 4566 break; | 4566 break; |
| 4567 } | 4567 } |
| 4568 | 4568 |
| 4569 case Yield::DELEGATING: { | 4569 case Yield::DELEGATING: { |
| 4570 VisitForStackValue(expr->generator_object()); | 4570 VisitForStackValue(expr->generator_object()); |
| 4571 | 4571 |
| 4572 // Initial stack layout is as follows: | 4572 // Initial stack layout is as follows: |
| 4573 // [sp + 1 * kPointerSize] iter | 4573 // [sp + 1 * kPointerSize] iter |
| 4574 // [sp + 0 * kPointerSize] g | 4574 // [sp + 0 * kPointerSize] g |
| 4575 | 4575 |
| 4576 // TODO(jbramley): Tidy this up once the merge is done, using named | 4576 // TODO(jbramley): Tidy this up once the merge is done, using named |
| 4577 // registers and suchlike. The implementation changes a little by | 4577 // registers and suchlike. The implementation changes a little by |
| 4578 // bleeding_edge so I don't want to spend too much time on it now. | 4578 // bleeding_edge so I don't want to spend too much time on it now. |
| 4579 | 4579 |
| 4580 Label l_catch, l_try, l_resume, l_next, l_call, l_loop; | 4580 Label l_catch, l_try, l_resume, l_next, l_call, l_loop; |
| 4581 // Initial send value is undefined. | 4581 // Initial send value is undefined. |
| 4582 __ LoadRoot(x0, Heap::kUndefinedValueRootIndex); | 4582 __ LoadRoot(x0, Heap::kUndefinedValueRootIndex); |
| 4583 __ B(&l_next); | 4583 __ B(&l_next); |
| 4584 | 4584 |
| 4585 // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; } | 4585 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; } |
| 4586 __ Bind(&l_catch); | 4586 __ Bind(&l_catch); |
| 4587 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); | 4587 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); |
| 4588 __ LoadRoot(x2, Heap::kthrow_stringRootIndex); // "throw" |
| 4588 __ Peek(x3, 1 * kPointerSize); // iter | 4589 __ Peek(x3, 1 * kPointerSize); // iter |
| 4589 __ Push(x3); // iter | 4590 __ Push(x3); // iter |
| 4590 __ Push(x0); // exception | 4591 __ Push(x0); // exception |
| 4591 __ Mov(x0, x3); // iter | |
| 4592 __ LoadRoot(x2, Heap::kthrow_stringRootIndex); // "throw" | |
| 4593 Handle<Code> throw_ic = isolate()->builtins()->LoadIC_Initialize(); | |
| 4594 CallIC(throw_ic); // iter.throw in x0 | |
| 4595 __ B(&l_call); | 4592 __ B(&l_call); |
| 4596 | 4593 |
| 4597 // try { received = yield result.value } | 4594 // try { received = %yield result } |
| 4595 // Shuffle the received result above a try handler and yield it without |
| 4596 // re-boxing. |
| 4598 __ Bind(&l_try); | 4597 __ Bind(&l_try); |
| 4599 __ Pop(x0); // result.value | 4598 __ Pop(x0); // result |
| 4600 __ PushTryHandler(StackHandler::CATCH, expr->index()); | 4599 __ PushTryHandler(StackHandler::CATCH, expr->index()); |
| 4601 const int handler_size = StackHandlerConstants::kSize; | 4600 const int handler_size = StackHandlerConstants::kSize; |
| 4602 __ Push(x0); // result.value | 4601 __ Push(x0); // result |
| 4603 __ Peek(x3, (1 * kPointerSize) + handler_size); // g | 4602 __ Peek(x3, (1 * kPointerSize) + handler_size); // g |
| 4604 __ Push(x3); // g | 4603 __ Push(x3); // g |
| 4605 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); | 4604 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); |
| 4606 __ Ldr(context_register(), | 4605 __ Ldr(context_register(), |
| 4607 MemOperand(fp, StandardFrameConstants::kContextOffset)); | 4606 MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 4608 __ JumpIfNotRoot(x0, Heap::kTheHoleValueRootIndex, &l_resume); | 4607 __ JumpIfNotRoot(x0, Heap::kTheHoleValueRootIndex, &l_resume); |
| 4609 EmitReturnIteratorResult(false); | 4608 __ Pop(x0); // result |
| 4609 EmitReturnSequence(); |
| 4610 __ Bind(&l_resume); // received in x0 | 4610 __ Bind(&l_resume); // received in x0 |
| 4611 __ PopTryHandler(); | 4611 __ PopTryHandler(); |
| 4612 | 4612 |
| 4613 // receiver = iter; f = iter.next; arg = received; | 4613 // receiver = iter; f = 'next'; arg = received; |
| 4614 __ Bind(&l_next); | 4614 __ Bind(&l_next); |
| 4615 __ LoadRoot(x2, Heap::knext_stringRootIndex); // "next" |
| 4615 __ Peek(x3, 1 * kPointerSize); // iter | 4616 __ Peek(x3, 1 * kPointerSize); // iter |
| 4616 __ Push(x3); // iter | 4617 __ Push(x3); // iter |
| 4617 __ Push(x0); // received | 4618 __ Push(x0); // received |
| 4618 __ Mov(x0, x3); // iter | |
| 4619 __ LoadRoot(x2, Heap::knext_stringRootIndex); // "next" | |
| 4620 Handle<Code> next_ic = isolate()->builtins()->LoadIC_Initialize(); | |
| 4621 CallIC(next_ic); // iter.next in r0 | |
| 4622 | 4619 |
| 4623 // result = f.call(receiver, arg); | 4620 // result = receiver[f](arg); |
| 4624 __ Bind(&l_call); | 4621 __ Bind(&l_call); |
| 4625 Label l_call_runtime; | 4622 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); |
| 4626 __ JumpIfSmi(x0, &l_call_runtime); | 4623 CallIC(ic); |
| 4627 __ JumpIfNotObjectType(x0, x1, x1, JS_FUNCTION_TYPE, &l_call_runtime); | |
| 4628 __ Mov(x1, x0); | |
| 4629 ParameterCount count(1); | |
| 4630 __ InvokeFunction(x1, count, CALL_FUNCTION, | |
| 4631 NullCallWrapper(), CALL_AS_METHOD); | |
| 4632 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 4624 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 4633 __ B(&l_loop); | |
| 4634 __ Bind(&l_call_runtime); | |
| 4635 __ Push(x0); | |
| 4636 __ CallRuntime(Runtime::kCall, 3); | |
| 4637 | 4625 |
| 4638 // val = result.value; if (!result.done) goto l_try; | 4626 // if (!result.done) goto l_try; |
| 4639 __ Bind(&l_loop); | 4627 __ Bind(&l_loop); |
| 4640 // result.value | |
| 4641 __ Push(x0); // save result | 4628 __ Push(x0); // save result |
| 4642 __ LoadRoot(x2, Heap::kvalue_stringRootIndex); // "value" | |
| 4643 Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize(); | |
| 4644 CallIC(value_ic); // result.value in x0 | |
| 4645 __ Pop(x1); // result | |
| 4646 __ Push(x0); // result.value | |
| 4647 __ Mov(x0, x1); // result | |
| 4648 __ LoadRoot(x2, Heap::kdone_stringRootIndex); // "done" | 4629 __ LoadRoot(x2, Heap::kdone_stringRootIndex); // "done" |
| 4649 Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize(); | 4630 Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize(); |
| 4650 CallIC(done_ic); // result.done in x0 | 4631 CallIC(done_ic); // result.done in x0 |
| 4651 // The ToBooleanStub argument (result.done) is in x0. | 4632 // The ToBooleanStub argument (result.done) is in x0. |
| 4652 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); | 4633 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); |
| 4653 CallIC(bool_ic); | 4634 CallIC(bool_ic); |
| 4654 __ Cbz(x0, &l_try); | 4635 __ Cbz(x0, &l_try); |
| 4655 | 4636 |
| 4656 // result.value | 4637 // result.value |
| 4657 __ Pop(x0); // result.value | 4638 __ Pop(x0); // result |
| 4639 __ LoadRoot(x2, Heap::kvalue_stringRootIndex); // "value" |
| 4640 Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize(); |
| 4641 CallIC(value_ic); // result.value in x0 |
| 4658 context()->DropAndPlug(2, x0); // drop iter and g | 4642 context()->DropAndPlug(2, x0); // drop iter and g |
| 4659 break; | 4643 break; |
| 4660 } | 4644 } |
| 4661 } | 4645 } |
| 4662 } | 4646 } |
| 4663 | 4647 |
| 4664 | 4648 |
| 4665 void FullCodeGenerator::EmitGeneratorResume(Expression *generator, | 4649 void FullCodeGenerator::EmitGeneratorResume(Expression *generator, |
| 4666 Expression *value, | 4650 Expression *value, |
| 4667 JSGeneratorObject::ResumeMode resume_mode) { | 4651 JSGeneratorObject::ResumeMode resume_mode) { |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4778 // Throw error if we attempt to operate on a running generator. | 4762 // Throw error if we attempt to operate on a running generator. |
| 4779 __ Bind(&wrong_state); | 4763 __ Bind(&wrong_state); |
| 4780 __ Push(generator_object); | 4764 __ Push(generator_object); |
| 4781 __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); | 4765 __ CallRuntime(Runtime::kThrowGeneratorStateError, 1); |
| 4782 | 4766 |
| 4783 __ Bind(&done); | 4767 __ Bind(&done); |
| 4784 context()->Plug(result_register()); | 4768 context()->Plug(result_register()); |
| 4785 } | 4769 } |
| 4786 | 4770 |
| 4787 | 4771 |
| 4788 void FullCodeGenerator::EmitReturnIteratorResult(bool done) { | 4772 void FullCodeGenerator::EmitCreateIteratorResult(bool done) { |
| 4789 Label gc_required; | 4773 Label gc_required; |
| 4790 Label allocated; | 4774 Label allocated; |
| 4791 | 4775 |
| 4792 Handle<Map> map(isolate()->native_context()->generator_result_map()); | 4776 Handle<Map> map(isolate()->native_context()->generator_result_map()); |
| 4793 | 4777 |
| 4794 // Allocate and populate an object with this form: { value: VAL, done: DONE } | 4778 // Allocate and populate an object with this form: { value: VAL, done: DONE } |
| 4795 | 4779 |
| 4796 Register result = x0; | 4780 Register result = x0; |
| 4797 __ Allocate(map->instance_size(), result, x10, x11, &gc_required, TAG_OBJECT); | 4781 __ Allocate(map->instance_size(), result, x10, x11, &gc_required, TAG_OBJECT); |
| 4782 __ B(&allocated); |
| 4783 |
| 4784 __ Bind(&gc_required); |
| 4785 __ Push(Smi::FromInt(map->instance_size())); |
| 4786 __ CallRuntime(Runtime::kAllocateInNewSpace, 1); |
| 4787 __ Ldr(context_register(), |
| 4788 MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 4789 |
| 4798 __ Bind(&allocated); | 4790 __ Bind(&allocated); |
| 4799 | |
| 4800 Register map_reg = x1; | 4791 Register map_reg = x1; |
| 4801 Register result_value = x2; | 4792 Register result_value = x2; |
| 4802 Register boolean_done = x3; | 4793 Register boolean_done = x3; |
| 4803 Register empty_fixed_array = x4; | 4794 Register empty_fixed_array = x4; |
| 4804 __ Mov(map_reg, Operand(map)); | 4795 __ Mov(map_reg, Operand(map)); |
| 4805 __ Pop(result_value); | 4796 __ Pop(result_value); |
| 4806 __ Mov(boolean_done, Operand(isolate()->factory()->ToBoolean(done))); | 4797 __ Mov(boolean_done, Operand(isolate()->factory()->ToBoolean(done))); |
| 4807 __ Mov(empty_fixed_array, Operand(isolate()->factory()->empty_fixed_array())); | 4798 __ Mov(empty_fixed_array, Operand(isolate()->factory()->empty_fixed_array())); |
| 4808 ASSERT_EQ(map->instance_size(), 5 * kPointerSize); | 4799 ASSERT_EQ(map->instance_size(), 5 * kPointerSize); |
| 4809 // TODO(jbramley): Use Stp if possible. | 4800 // TODO(jbramley): Use Stp if possible. |
| 4810 __ Str(map_reg, FieldMemOperand(result, HeapObject::kMapOffset)); | 4801 __ Str(map_reg, FieldMemOperand(result, HeapObject::kMapOffset)); |
| 4811 __ Str(empty_fixed_array, | 4802 __ Str(empty_fixed_array, |
| 4812 FieldMemOperand(result, JSObject::kPropertiesOffset)); | 4803 FieldMemOperand(result, JSObject::kPropertiesOffset)); |
| 4813 __ Str(empty_fixed_array, FieldMemOperand(result, JSObject::kElementsOffset)); | 4804 __ Str(empty_fixed_array, FieldMemOperand(result, JSObject::kElementsOffset)); |
| 4814 __ Str(result_value, | 4805 __ Str(result_value, |
| 4815 FieldMemOperand(result, | 4806 FieldMemOperand(result, |
| 4816 JSGeneratorObject::kResultValuePropertyOffset)); | 4807 JSGeneratorObject::kResultValuePropertyOffset)); |
| 4817 __ Str(boolean_done, | 4808 __ Str(boolean_done, |
| 4818 FieldMemOperand(result, | 4809 FieldMemOperand(result, |
| 4819 JSGeneratorObject::kResultDonePropertyOffset)); | 4810 JSGeneratorObject::kResultDonePropertyOffset)); |
| 4820 | 4811 |
| 4821 // Only the value field needs a write barrier, as the other values are in the | 4812 // Only the value field needs a write barrier, as the other values are in the |
| 4822 // root set. | 4813 // root set. |
| 4823 __ RecordWriteField(result, JSGeneratorObject::kResultValuePropertyOffset, | 4814 __ RecordWriteField(result, JSGeneratorObject::kResultValuePropertyOffset, |
| 4824 x10, x11, kLRHasBeenSaved, kDontSaveFPRegs); | 4815 x10, x11, kLRHasBeenSaved, kDontSaveFPRegs); |
| 4825 | |
| 4826 if (done) { | |
| 4827 // Exit all nested statements. | |
| 4828 NestedStatement* current = nesting_stack_; | |
| 4829 int stack_depth = 0; | |
| 4830 int context_length = 0; | |
| 4831 while (current != NULL) { | |
| 4832 current = current->Exit(&stack_depth, &context_length); | |
| 4833 } | |
| 4834 __ Drop(stack_depth); | |
| 4835 } | |
| 4836 | |
| 4837 EmitReturnSequence(); | |
| 4838 | |
| 4839 __ Bind(&gc_required); | |
| 4840 __ Push(Smi::FromInt(map->instance_size())); | |
| 4841 __ CallRuntime(Runtime::kAllocateInNewSpace, 1); | |
| 4842 __ Ldr(context_register(), | |
| 4843 MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
| 4844 __ B(&allocated); | |
| 4845 } | 4816 } |
| 4846 | 4817 |
| 4847 | 4818 |
| 4848 // TODO(all): I don't like this method. | 4819 // TODO(all): I don't like this method. |
| 4849 // It seems to me that in too many places x0 is used in place of this. | 4820 // It seems to me that in too many places x0 is used in place of this. |
| 4850 // Also, this function is not suitable for all places where x0 should be | 4821 // Also, this function is not suitable for all places where x0 should be |
| 4851 // abstracted (eg. when used as an argument). But some places assume that the | 4822 // abstracted (eg. when used as an argument). But some places assume that the |
| 4852 // first argument register is x0, and use this function instead. | 4823 // first argument register is x0, and use this function instead. |
| 4853 // Considering that most of the register allocation is hard-coded in the | 4824 // Considering that most of the register allocation is hard-coded in the |
| 4854 // FullCodeGen, that it is unlikely we will need to change it extensively, and | 4825 // FullCodeGen, that it is unlikely we will need to change it extensively, and |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4992 return previous_; | 4963 return previous_; |
| 4993 } | 4964 } |
| 4994 | 4965 |
| 4995 | 4966 |
| 4996 #undef __ | 4967 #undef __ |
| 4997 | 4968 |
| 4998 | 4969 |
| 4999 } } // namespace v8::internal | 4970 } } // namespace v8::internal |
| 5000 | 4971 |
| 5001 #endif // V8_TARGET_ARCH_A64 | 4972 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |