| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if V8_TARGET_ARCH_PPC | 5 #if V8_TARGET_ARCH_PPC |
| 6 | 6 |
| 7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
| 8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
| 9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
| 10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
| (...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | 443 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); |
| 444 int32_t arg_count = info_->scope()->num_parameters() + 1; | 444 int32_t arg_count = info_->scope()->num_parameters() + 1; |
| 445 int32_t sp_delta = arg_count * kPointerSize; | 445 int32_t sp_delta = arg_count * kPointerSize; |
| 446 SetReturnPosition(literal()); | 446 SetReturnPosition(literal()); |
| 447 __ LeaveFrame(StackFrame::JAVA_SCRIPT, sp_delta); | 447 __ LeaveFrame(StackFrame::JAVA_SCRIPT, sp_delta); |
| 448 __ blr(); | 448 __ blr(); |
| 449 } | 449 } |
| 450 } | 450 } |
| 451 } | 451 } |
| 452 | 452 |
| 453 void FullCodeGenerator::RestoreContext() { |
| 454 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 455 } |
| 453 | 456 |
| 454 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const { | 457 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const { |
| 455 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 458 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
| 456 codegen()->GetVar(result_register(), var); | 459 codegen()->GetVar(result_register(), var); |
| 457 codegen()->PushOperand(result_register()); | 460 codegen()->PushOperand(result_register()); |
| 458 } | 461 } |
| 459 | 462 |
| 460 | 463 |
| 461 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {} | 464 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {} |
| 462 | 465 |
| (...skipping 910 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1373 __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index())); | 1376 __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index())); |
| 1374 __ mov(r4, Operand(constant_properties)); | 1377 __ mov(r4, Operand(constant_properties)); |
| 1375 int flags = expr->ComputeFlags(); | 1378 int flags = expr->ComputeFlags(); |
| 1376 __ LoadSmiLiteral(r3, Smi::FromInt(flags)); | 1379 __ LoadSmiLiteral(r3, Smi::FromInt(flags)); |
| 1377 if (MustCreateObjectLiteralWithRuntime(expr)) { | 1380 if (MustCreateObjectLiteralWithRuntime(expr)) { |
| 1378 __ Push(r6, r5, r4, r3); | 1381 __ Push(r6, r5, r4, r3); |
| 1379 __ CallRuntime(Runtime::kCreateObjectLiteral); | 1382 __ CallRuntime(Runtime::kCreateObjectLiteral); |
| 1380 } else { | 1383 } else { |
| 1381 FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); | 1384 FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); |
| 1382 __ CallStub(&stub); | 1385 __ CallStub(&stub); |
| 1383 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1386 RestoreContext(); |
| 1384 } | 1387 } |
| 1385 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); | 1388 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); |
| 1386 | 1389 |
| 1387 // If result_saved is true the result is on top of the stack. If | 1390 // If result_saved is true the result is on top of the stack. If |
| 1388 // result_saved is false the result is in r3. | 1391 // result_saved is false the result is in r3. |
| 1389 bool result_saved = false; | 1392 bool result_saved = false; |
| 1390 | 1393 |
| 1391 AccessorTable accessor_table(zone()); | 1394 AccessorTable accessor_table(zone()); |
| 1392 int property_index = 0; | 1395 int property_index = 0; |
| 1393 for (; property_index < expr->properties()->length(); property_index++) { | 1396 for (; property_index < expr->properties()->length(); property_index++) { |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1818 r0); | 1821 r0); |
| 1819 __ StoreP(cp, FieldMemOperand(r3, JSGeneratorObject::kContextOffset), r0); | 1822 __ StoreP(cp, FieldMemOperand(r3, JSGeneratorObject::kContextOffset), r0); |
| 1820 __ mr(r4, cp); | 1823 __ mr(r4, cp); |
| 1821 __ RecordWriteField(r3, JSGeneratorObject::kContextOffset, r4, r5, | 1824 __ RecordWriteField(r3, JSGeneratorObject::kContextOffset, r4, r5, |
| 1822 kLRHasBeenSaved, kDontSaveFPRegs); | 1825 kLRHasBeenSaved, kDontSaveFPRegs); |
| 1823 __ addi(r4, fp, Operand(StandardFrameConstants::kExpressionsOffset)); | 1826 __ addi(r4, fp, Operand(StandardFrameConstants::kExpressionsOffset)); |
| 1824 __ cmp(sp, r4); | 1827 __ cmp(sp, r4); |
| 1825 __ beq(&post_runtime); | 1828 __ beq(&post_runtime); |
| 1826 __ push(r3); // generator object | 1829 __ push(r3); // generator object |
| 1827 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); | 1830 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); |
| 1828 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1831 RestoreContext(); |
| 1829 __ bind(&post_runtime); | 1832 __ bind(&post_runtime); |
| 1830 PopOperand(result_register()); | 1833 PopOperand(result_register()); |
| 1831 EmitReturnSequence(); | 1834 EmitReturnSequence(); |
| 1832 | 1835 |
| 1833 __ bind(&resume); | 1836 __ bind(&resume); |
| 1834 context()->Plug(result_register()); | 1837 context()->Plug(result_register()); |
| 1835 } | 1838 } |
| 1836 | 1839 |
| 1837 void FullCodeGenerator::PushOperands(Register reg1, Register reg2) { | 1840 void FullCodeGenerator::PushOperands(Register reg1, Register reg2) { |
| 1838 OperandStackDepthIncrement(2); | 1841 OperandStackDepthIncrement(2); |
| (...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2514 CodeFactory::CallIC(isolate(), arg_count, mode, expr->tail_call_mode()) | 2517 CodeFactory::CallIC(isolate(), arg_count, mode, expr->tail_call_mode()) |
| 2515 .code(); | 2518 .code(); |
| 2516 __ LoadSmiLiteral(r6, SmiFromSlot(expr->CallFeedbackICSlot())); | 2519 __ LoadSmiLiteral(r6, SmiFromSlot(expr->CallFeedbackICSlot())); |
| 2517 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); | 2520 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); |
| 2518 // Don't assign a type feedback id to the IC, since type feedback is provided | 2521 // Don't assign a type feedback id to the IC, since type feedback is provided |
| 2519 // by the vector above. | 2522 // by the vector above. |
| 2520 CallIC(ic); | 2523 CallIC(ic); |
| 2521 OperandStackDepthDecrement(arg_count + 1); | 2524 OperandStackDepthDecrement(arg_count + 1); |
| 2522 | 2525 |
| 2523 RecordJSReturnSite(expr); | 2526 RecordJSReturnSite(expr); |
| 2524 // Restore context register. | 2527 RestoreContext(); |
| 2525 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
| 2526 context()->DropAndPlug(1, r3); | 2528 context()->DropAndPlug(1, r3); |
| 2527 } | 2529 } |
| 2528 | 2530 |
| 2529 | 2531 |
| 2530 void FullCodeGenerator::EmitResolvePossiblyDirectEval(Call* expr) { | 2532 void FullCodeGenerator::EmitResolvePossiblyDirectEval(Call* expr) { |
| 2531 int arg_count = expr->arguments()->length(); | 2533 int arg_count = expr->arguments()->length(); |
| 2532 // r7: copy of the first argument or undefined if it doesn't exist. | 2534 // r7: copy of the first argument or undefined if it doesn't exist. |
| 2533 if (arg_count > 0) { | 2535 if (arg_count > 0) { |
| 2534 __ LoadP(r7, MemOperand(sp, arg_count * kPointerSize), r0); | 2536 __ LoadP(r7, MemOperand(sp, arg_count * kPointerSize), r0); |
| 2535 } else { | 2537 } else { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2623 | 2625 |
| 2624 // Record source position for debugger. | 2626 // Record source position for debugger. |
| 2625 SetCallPosition(expr); | 2627 SetCallPosition(expr); |
| 2626 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); | 2628 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); |
| 2627 __ mov(r3, Operand(arg_count)); | 2629 __ mov(r3, Operand(arg_count)); |
| 2628 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny, | 2630 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny, |
| 2629 expr->tail_call_mode()), | 2631 expr->tail_call_mode()), |
| 2630 RelocInfo::CODE_TARGET); | 2632 RelocInfo::CODE_TARGET); |
| 2631 OperandStackDepthDecrement(arg_count + 1); | 2633 OperandStackDepthDecrement(arg_count + 1); |
| 2632 RecordJSReturnSite(expr); | 2634 RecordJSReturnSite(expr); |
| 2633 // Restore context register. | 2635 RestoreContext(); |
| 2634 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
| 2635 context()->DropAndPlug(1, r3); | 2636 context()->DropAndPlug(1, r3); |
| 2636 } | 2637 } |
| 2637 | 2638 |
| 2638 | 2639 |
| 2639 void FullCodeGenerator::VisitCallNew(CallNew* expr) { | 2640 void FullCodeGenerator::VisitCallNew(CallNew* expr) { |
| 2640 Comment cmnt(masm_, "[ CallNew"); | 2641 Comment cmnt(masm_, "[ CallNew"); |
| 2641 // According to ECMA-262, section 11.2.2, page 44, the function | 2642 // According to ECMA-262, section 11.2.2, page 44, the function |
| 2642 // expression in new calls must be evaluated before the | 2643 // expression in new calls must be evaluated before the |
| 2643 // arguments. | 2644 // arguments. |
| 2644 | 2645 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2664 __ LoadP(r4, MemOperand(sp, arg_count * kPointerSize), r0); | 2665 __ LoadP(r4, MemOperand(sp, arg_count * kPointerSize), r0); |
| 2665 | 2666 |
| 2666 // Record call targets in unoptimized code. | 2667 // Record call targets in unoptimized code. |
| 2667 __ EmitLoadTypeFeedbackVector(r5); | 2668 __ EmitLoadTypeFeedbackVector(r5); |
| 2668 __ LoadSmiLiteral(r6, SmiFromSlot(expr->CallNewFeedbackSlot())); | 2669 __ LoadSmiLiteral(r6, SmiFromSlot(expr->CallNewFeedbackSlot())); |
| 2669 | 2670 |
| 2670 CallConstructStub stub(isolate()); | 2671 CallConstructStub stub(isolate()); |
| 2671 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); | 2672 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); |
| 2672 OperandStackDepthDecrement(arg_count + 1); | 2673 OperandStackDepthDecrement(arg_count + 1); |
| 2673 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); | 2674 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); |
| 2674 // Restore context register. | 2675 RestoreContext(); |
| 2675 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
| 2676 context()->Plug(r3); | 2676 context()->Plug(r3); |
| 2677 } | 2677 } |
| 2678 | 2678 |
| 2679 | 2679 |
| 2680 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { | 2680 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { |
| 2681 SuperCallReference* super_call_ref = | 2681 SuperCallReference* super_call_ref = |
| 2682 expr->expression()->AsSuperCallReference(); | 2682 expr->expression()->AsSuperCallReference(); |
| 2683 DCHECK_NOT_NULL(super_call_ref); | 2683 DCHECK_NOT_NULL(super_call_ref); |
| 2684 | 2684 |
| 2685 // Push the super constructor target on the stack (may be null, | 2685 // Push the super constructor target on the stack (may be null, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2708 __ mr(r6, result_register()); | 2708 __ mr(r6, result_register()); |
| 2709 | 2709 |
| 2710 // Load function and argument count into r1 and r0. | 2710 // Load function and argument count into r1 and r0. |
| 2711 __ mov(r3, Operand(arg_count)); | 2711 __ mov(r3, Operand(arg_count)); |
| 2712 __ LoadP(r4, MemOperand(sp, arg_count * kPointerSize)); | 2712 __ LoadP(r4, MemOperand(sp, arg_count * kPointerSize)); |
| 2713 | 2713 |
| 2714 __ Call(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | 2714 __ Call(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
| 2715 OperandStackDepthDecrement(arg_count + 1); | 2715 OperandStackDepthDecrement(arg_count + 1); |
| 2716 | 2716 |
| 2717 RecordJSReturnSite(expr); | 2717 RecordJSReturnSite(expr); |
| 2718 | 2718 RestoreContext(); |
| 2719 // Restore context register. | |
| 2720 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
| 2721 context()->Plug(r3); | 2719 context()->Plug(r3); |
| 2722 } | 2720 } |
| 2723 | 2721 |
| 2724 | 2722 |
| 2725 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { | 2723 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { |
| 2726 ZoneList<Expression*>* args = expr->arguments(); | 2724 ZoneList<Expression*>* args = expr->arguments(); |
| 2727 DCHECK(args->length() == 1); | 2725 DCHECK(args->length() == 1); |
| 2728 | 2726 |
| 2729 VisitForAccumulatorValue(args->at(0)); | 2727 VisitForAccumulatorValue(args->at(0)); |
| 2730 | 2728 |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3096 VisitForStackValue(arg); | 3094 VisitForStackValue(arg); |
| 3097 } | 3095 } |
| 3098 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); | 3096 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); |
| 3099 // Move target to r4. | 3097 // Move target to r4. |
| 3100 int const argc = args->length() - 2; | 3098 int const argc = args->length() - 2; |
| 3101 __ LoadP(r4, MemOperand(sp, (argc + 1) * kPointerSize)); | 3099 __ LoadP(r4, MemOperand(sp, (argc + 1) * kPointerSize)); |
| 3102 // Call the target. | 3100 // Call the target. |
| 3103 __ mov(r3, Operand(argc)); | 3101 __ mov(r3, Operand(argc)); |
| 3104 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); | 3102 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
| 3105 OperandStackDepthDecrement(argc + 1); | 3103 OperandStackDepthDecrement(argc + 1); |
| 3106 // Restore context register. | 3104 RestoreContext(); |
| 3107 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
| 3108 // Discard the function left on TOS. | 3105 // Discard the function left on TOS. |
| 3109 context()->DropAndPlug(1, r3); | 3106 context()->DropAndPlug(1, r3); |
| 3110 } | 3107 } |
| 3111 | 3108 |
| 3112 | 3109 |
| 3113 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { | 3110 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { |
| 3114 ZoneList<Expression*>* args = expr->arguments(); | 3111 ZoneList<Expression*>* args = expr->arguments(); |
| 3115 VisitForAccumulatorValue(args->at(0)); | 3112 VisitForAccumulatorValue(args->at(0)); |
| 3116 | 3113 |
| 3117 Label materialize_true, materialize_false; | 3114 Label materialize_true, materialize_false; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3215 void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) { | 3212 void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) { |
| 3216 ZoneList<Expression*>* args = expr->arguments(); | 3213 ZoneList<Expression*>* args = expr->arguments(); |
| 3217 int arg_count = args->length(); | 3214 int arg_count = args->length(); |
| 3218 | 3215 |
| 3219 SetCallPosition(expr); | 3216 SetCallPosition(expr); |
| 3220 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); | 3217 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); |
| 3221 __ mov(r3, Operand(arg_count)); | 3218 __ mov(r3, Operand(arg_count)); |
| 3222 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined), | 3219 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined), |
| 3223 RelocInfo::CODE_TARGET); | 3220 RelocInfo::CODE_TARGET); |
| 3224 OperandStackDepthDecrement(arg_count + 1); | 3221 OperandStackDepthDecrement(arg_count + 1); |
| 3225 | 3222 RestoreContext(); |
| 3226 // Restore context register. | |
| 3227 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
| 3228 } | 3223 } |
| 3229 | 3224 |
| 3230 | 3225 |
| 3231 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3226 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 3232 switch (expr->op()) { | 3227 switch (expr->op()) { |
| 3233 case Token::DELETE: { | 3228 case Token::DELETE: { |
| 3234 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3229 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 3235 Property* property = expr->expression()->AsProperty(); | 3230 Property* property = expr->expression()->AsProperty(); |
| 3236 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 3231 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 3237 | 3232 |
| (...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3682 Label* fall_through = NULL; | 3677 Label* fall_through = NULL; |
| 3683 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, | 3678 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
| 3684 &if_false, &fall_through); | 3679 &if_false, &fall_through); |
| 3685 | 3680 |
| 3686 Token::Value op = expr->op(); | 3681 Token::Value op = expr->op(); |
| 3687 VisitForStackValue(expr->left()); | 3682 VisitForStackValue(expr->left()); |
| 3688 switch (op) { | 3683 switch (op) { |
| 3689 case Token::IN: | 3684 case Token::IN: |
| 3690 VisitForStackValue(expr->right()); | 3685 VisitForStackValue(expr->right()); |
| 3691 SetExpressionPosition(expr); | 3686 SetExpressionPosition(expr); |
| 3692 CallRuntimeWithOperands(Runtime::kHasProperty); | 3687 EmitHasProperty(); |
| 3693 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); | 3688 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); |
| 3694 __ CompareRoot(r3, Heap::kTrueValueRootIndex); | 3689 __ CompareRoot(r3, Heap::kTrueValueRootIndex); |
| 3695 Split(eq, if_true, if_false, fall_through); | 3690 Split(eq, if_true, if_false, fall_through); |
| 3696 break; | 3691 break; |
| 3697 | 3692 |
| 3698 case Token::INSTANCEOF: { | 3693 case Token::INSTANCEOF: { |
| 3699 VisitForAccumulatorValue(expr->right()); | 3694 VisitForAccumulatorValue(expr->right()); |
| 3700 SetExpressionPosition(expr); | 3695 SetExpressionPosition(expr); |
| 3701 PopOperand(r4); | 3696 PopOperand(r4); |
| 3702 InstanceOfStub stub(isolate()); | 3697 InstanceOfStub stub(isolate()); |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3940 | 3935 |
| 3941 DCHECK(Assembler::IsCrSet(Assembler::instr_at(cmp_address))); | 3936 DCHECK(Assembler::IsCrSet(Assembler::instr_at(cmp_address))); |
| 3942 | 3937 |
| 3943 DCHECK(interrupt_address == | 3938 DCHECK(interrupt_address == |
| 3944 isolate->builtins()->OnStackReplacement()->entry()); | 3939 isolate->builtins()->OnStackReplacement()->entry()); |
| 3945 return ON_STACK_REPLACEMENT; | 3940 return ON_STACK_REPLACEMENT; |
| 3946 } | 3941 } |
| 3947 } // namespace internal | 3942 } // namespace internal |
| 3948 } // namespace v8 | 3943 } // namespace v8 |
| 3949 #endif // V8_TARGET_ARCH_PPC | 3944 #endif // V8_TARGET_ARCH_PPC |
| OLD | NEW |