| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 | 270 |
| 271 __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT); | 271 __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT); |
| 272 frame_->EmitPush(rsi); // The context is the first argument. | 272 frame_->EmitPush(rsi); // The context is the first argument. |
| 273 frame_->EmitPush(kScratchRegister); | 273 frame_->EmitPush(kScratchRegister); |
| 274 frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0)); | 274 frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0)); |
| 275 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 275 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| 276 // Return value is ignored. | 276 // Return value is ignored. |
| 277 } | 277 } |
| 278 | 278 |
| 279 | 279 |
| 280 void CodeGenerator::Generate(CompilationInfo* info, Mode mode) { | 280 void CodeGenerator::Generate(CompilationInfo* info) { |
| 281 // Record the position for debugging purposes. | 281 // Record the position for debugging purposes. |
| 282 CodeForFunctionPosition(info->function()); | 282 CodeForFunctionPosition(info->function()); |
| 283 | 283 |
| 284 // Initialize state. | 284 // Initialize state. |
| 285 info_ = info; | 285 info_ = info; |
| 286 ASSERT(allocator_ == NULL); | 286 ASSERT(allocator_ == NULL); |
| 287 RegisterAllocator register_allocator(this); | 287 RegisterAllocator register_allocator(this); |
| 288 allocator_ = ®ister_allocator; | 288 allocator_ = ®ister_allocator; |
| 289 ASSERT(frame_ == NULL); | 289 ASSERT(frame_ == NULL); |
| 290 frame_ = new VirtualFrame(); | 290 frame_ = new VirtualFrame(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 309 CodeGenState state(this); | 309 CodeGenState state(this); |
| 310 | 310 |
| 311 // Entry: | 311 // Entry: |
| 312 // Stack: receiver, arguments, return address. | 312 // Stack: receiver, arguments, return address. |
| 313 // rbp: caller's frame pointer | 313 // rbp: caller's frame pointer |
| 314 // rsp: stack pointer | 314 // rsp: stack pointer |
| 315 // rdi: called JS function | 315 // rdi: called JS function |
| 316 // rsi: callee's context | 316 // rsi: callee's context |
| 317 allocator_->Initialize(); | 317 allocator_->Initialize(); |
| 318 | 318 |
| 319 if (mode == PRIMARY) { | 319 if (info->mode() == CompilationInfo::PRIMARY) { |
| 320 frame_->Enter(); | 320 frame_->Enter(); |
| 321 | 321 |
| 322 // Allocate space for locals and initialize them. | 322 // Allocate space for locals and initialize them. |
| 323 frame_->AllocateStackSlots(); | 323 frame_->AllocateStackSlots(); |
| 324 | 324 |
| 325 // Allocate the local context if needed. | 325 // Allocate the local context if needed. |
| 326 int heap_slots = scope()->num_heap_slots(); | 326 int heap_slots = scope()->num_heap_slots(); |
| 327 if (heap_slots > 0) { | 327 if (heap_slots > 0) { |
| 328 Comment cmnt(masm_, "[ allocate local context"); | 328 Comment cmnt(masm_, "[ allocate local context"); |
| 329 // Allocate local context. | 329 // Allocate local context. |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 if (scope()->is_function_scope() && scope()->function() != NULL) { | 400 if (scope()->is_function_scope() && scope()->function() != NULL) { |
| 401 frame_->Push(Factory::the_hole_value()); | 401 frame_->Push(Factory::the_hole_value()); |
| 402 StoreToSlot(scope()->function()->slot(), NOT_CONST_INIT); | 402 StoreToSlot(scope()->function()->slot(), NOT_CONST_INIT); |
| 403 } | 403 } |
| 404 } else { | 404 } else { |
| 405 // When used as the secondary compiler for splitting, rbp, rsi, | 405 // When used as the secondary compiler for splitting, rbp, rsi, |
| 406 // and rdi have been pushed on the stack. Adjust the virtual | 406 // and rdi have been pushed on the stack. Adjust the virtual |
| 407 // frame to match this state. | 407 // frame to match this state. |
| 408 frame_->Adjust(3); | 408 frame_->Adjust(3); |
| 409 allocator_->Unuse(rdi); | 409 allocator_->Unuse(rdi); |
| 410 |
| 411 // Bind all the bailout labels to the beginning of the function. |
| 412 List<CompilationInfo::Bailout*>* bailouts = info->bailouts(); |
| 413 for (int i = 0; i < bailouts->length(); i++) { |
| 414 __ bind(bailouts->at(i)->label()); |
| 415 } |
| 410 } | 416 } |
| 411 | 417 |
| 412 // Initialize the function return target after the locals are set | 418 // Initialize the function return target after the locals are set |
| 413 // up, because it needs the expected frame height from the frame. | 419 // up, because it needs the expected frame height from the frame. |
| 414 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); | 420 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); |
| 415 function_return_is_shadowed_ = false; | 421 function_return_is_shadowed_ = false; |
| 416 | 422 |
| 417 // Generate code to 'execute' declarations and initialize functions | 423 // Generate code to 'execute' declarations and initialize functions |
| 418 // (source elements). In case of an illegal redeclaration we need to | 424 // (source elements). In case of an illegal redeclaration we need to |
| 419 // handle that instead of processing the declarations. | 425 // handle that instead of processing the declarations. |
| (...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1214 | 1220 |
| 1215 // Duplicate the switch value. | 1221 // Duplicate the switch value. |
| 1216 frame_->Dup(); | 1222 frame_->Dup(); |
| 1217 | 1223 |
| 1218 // Compile the label expression. | 1224 // Compile the label expression. |
| 1219 Load(clause->label()); | 1225 Load(clause->label()); |
| 1220 | 1226 |
| 1221 // Compare and branch to the body if true or the next test if | 1227 // Compare and branch to the body if true or the next test if |
| 1222 // false. Prefer the next test as a fall through. | 1228 // false. Prefer the next test as a fall through. |
| 1223 ControlDestination dest(clause->body_target(), &next_test, false); | 1229 ControlDestination dest(clause->body_target(), &next_test, false); |
| 1224 Comparison(equal, true, &dest); | 1230 Comparison(node, equal, true, &dest); |
| 1225 | 1231 |
| 1226 // If the comparison fell through to the true target, jump to the | 1232 // If the comparison fell through to the true target, jump to the |
| 1227 // actual body. | 1233 // actual body. |
| 1228 if (dest.true_was_fall_through()) { | 1234 if (dest.true_was_fall_through()) { |
| 1229 clause->body_target()->Unuse(); | 1235 clause->body_target()->Unuse(); |
| 1230 clause->body_target()->Jump(); | 1236 clause->body_target()->Jump(); |
| 1231 } | 1237 } |
| 1232 } | 1238 } |
| 1233 | 1239 |
| 1234 // If there was control flow to a next test from the last one | 1240 // If there was control flow to a next test from the last one |
| (...skipping 976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2211 | 2217 |
| 2212 | 2218 |
| 2213 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 2219 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
| 2214 ASSERT(!in_spilled_code()); | 2220 ASSERT(!in_spilled_code()); |
| 2215 Comment cmnt(masm_, "[ DebuggerStatement"); | 2221 Comment cmnt(masm_, "[ DebuggerStatement"); |
| 2216 CodeForStatementPosition(node); | 2222 CodeForStatementPosition(node); |
| 2217 #ifdef ENABLE_DEBUGGER_SUPPORT | 2223 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 2218 // Spill everything, even constants, to the frame. | 2224 // Spill everything, even constants, to the frame. |
| 2219 frame_->SpillAll(); | 2225 frame_->SpillAll(); |
| 2220 | 2226 |
| 2221 DebuggerStatementStub ces; | 2227 frame_->DebugBreak(); |
| 2222 frame_->CallStub(&ces, 0); | |
| 2223 // Ignore the return value. | 2228 // Ignore the return value. |
| 2224 #endif | 2229 #endif |
| 2225 } | 2230 } |
| 2226 | 2231 |
| 2227 | 2232 |
| 2228 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 2233 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 2229 ASSERT(boilerplate->IsBoilerplate()); | 2234 ASSERT(boilerplate->IsBoilerplate()); |
| 2230 | 2235 |
| 2231 // The inevitable call will sync frame elements to memory anyway, so | 2236 // The inevitable call will sync frame elements to memory anyway, so |
| 2232 // we do it eagerly to allow us to push the arguments directly into | 2237 // we do it eagerly to allow us to push the arguments directly into |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2489 // Load a writable copy of the function of this activation in a | 2494 // Load a writable copy of the function of this activation in a |
| 2490 // register. | 2495 // register. |
| 2491 frame_->PushFunction(); | 2496 frame_->PushFunction(); |
| 2492 Result literals = frame_->Pop(); | 2497 Result literals = frame_->Pop(); |
| 2493 literals.ToRegister(); | 2498 literals.ToRegister(); |
| 2494 frame_->Spill(literals.reg()); | 2499 frame_->Spill(literals.reg()); |
| 2495 | 2500 |
| 2496 // Load the literals array of the function. | 2501 // Load the literals array of the function. |
| 2497 __ movq(literals.reg(), | 2502 __ movq(literals.reg(), |
| 2498 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); | 2503 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); |
| 2499 // Literal array. | 2504 |
| 2500 frame_->Push(&literals); | 2505 frame_->Push(&literals); |
| 2501 // Literal index. | |
| 2502 frame_->Push(Smi::FromInt(node->literal_index())); | 2506 frame_->Push(Smi::FromInt(node->literal_index())); |
| 2503 // Constant elements. | |
| 2504 frame_->Push(node->constant_elements()); | 2507 frame_->Push(node->constant_elements()); |
| 2508 int length = node->values()->length(); |
| 2505 Result clone; | 2509 Result clone; |
| 2506 if (node->depth() > 1) { | 2510 if (node->depth() > 1) { |
| 2507 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3); | 2511 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3); |
| 2512 } else if (length > FastCloneShallowArrayStub::kMaximumLength) { |
| 2513 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); |
| 2508 } else { | 2514 } else { |
| 2509 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); | 2515 FastCloneShallowArrayStub stub(length); |
| 2516 clone = frame_->CallStub(&stub, 3); |
| 2510 } | 2517 } |
| 2511 frame_->Push(&clone); | 2518 frame_->Push(&clone); |
| 2512 | 2519 |
| 2513 // Generate code to set the elements in the array that are not | 2520 // Generate code to set the elements in the array that are not |
| 2514 // literals. | 2521 // literals. |
| 2515 for (int i = 0; i < node->values()->length(); i++) { | 2522 for (int i = 0; i < node->values()->length(); i++) { |
| 2516 Expression* value = node->values()->at(i); | 2523 Expression* value = node->values()->at(i); |
| 2517 | 2524 |
| 2518 // If value is a literal the property value is already set in the | 2525 // If value is a literal the property value is already set in the |
| 2519 // boilerplate object. | 2526 // boilerplate object. |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2749 // Restore the context and overwrite the function on the stack with | 2756 // Restore the context and overwrite the function on the stack with |
| 2750 // the result. | 2757 // the result. |
| 2751 frame_->RestoreContextRegister(); | 2758 frame_->RestoreContextRegister(); |
| 2752 frame_->SetElementAt(0, &result); | 2759 frame_->SetElementAt(0, &result); |
| 2753 | 2760 |
| 2754 } else if (var != NULL && !var->is_this() && var->is_global()) { | 2761 } else if (var != NULL && !var->is_this() && var->is_global()) { |
| 2755 // ---------------------------------- | 2762 // ---------------------------------- |
| 2756 // JavaScript example: 'foo(1, 2, 3)' // foo is global | 2763 // JavaScript example: 'foo(1, 2, 3)' // foo is global |
| 2757 // ---------------------------------- | 2764 // ---------------------------------- |
| 2758 | 2765 |
| 2759 // Push the name of the function and the receiver onto the stack. | |
| 2760 frame_->Push(var->name()); | |
| 2761 | |
| 2762 // Pass the global object as the receiver and let the IC stub | 2766 // Pass the global object as the receiver and let the IC stub |
| 2763 // patch the stack to use the global proxy as 'this' in the | 2767 // patch the stack to use the global proxy as 'this' in the |
| 2764 // invoked function. | 2768 // invoked function. |
| 2765 LoadGlobal(); | 2769 LoadGlobal(); |
| 2766 | 2770 |
| 2767 // Load the arguments. | 2771 // Load the arguments. |
| 2768 int arg_count = args->length(); | 2772 int arg_count = args->length(); |
| 2769 for (int i = 0; i < arg_count; i++) { | 2773 for (int i = 0; i < arg_count; i++) { |
| 2770 Load(args->at(i)); | 2774 Load(args->at(i)); |
| 2771 } | 2775 } |
| 2772 | 2776 |
| 2777 // Push the name of the function on the frame. |
| 2778 frame_->Push(var->name()); |
| 2779 |
| 2773 // Call the IC initialization code. | 2780 // Call the IC initialization code. |
| 2774 CodeForSourcePosition(node->position()); | 2781 CodeForSourcePosition(node->position()); |
| 2775 Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT, | 2782 Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT, |
| 2776 arg_count, | 2783 arg_count, |
| 2777 loop_nesting()); | 2784 loop_nesting()); |
| 2778 frame_->RestoreContextRegister(); | 2785 frame_->RestoreContextRegister(); |
| 2779 // Replace the function on the stack with the result. | 2786 // Replace the function on the stack with the result. |
| 2780 frame_->SetElementAt(0, &result); | 2787 frame_->Push(&result); |
| 2781 | 2788 |
| 2782 } else if (var != NULL && var->slot() != NULL && | 2789 } else if (var != NULL && var->slot() != NULL && |
| 2783 var->slot()->type() == Slot::LOOKUP) { | 2790 var->slot()->type() == Slot::LOOKUP) { |
| 2784 // ---------------------------------- | 2791 // ---------------------------------- |
| 2785 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj | 2792 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj |
| 2786 // ---------------------------------- | 2793 // ---------------------------------- |
| 2787 | 2794 |
| 2788 // Load the function from the context. Sync the frame so we can | 2795 // Load the function from the context. Sync the frame so we can |
| 2789 // push the arguments directly into place. | 2796 // push the arguments directly into place. |
| 2790 frame_->SyncRange(0, frame_->element_count() - 1); | 2797 frame_->SyncRange(0, frame_->element_count() - 1); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2823 args->at(1)->AsVariableProxy() != NULL && | 2830 args->at(1)->AsVariableProxy() != NULL && |
| 2824 args->at(1)->AsVariableProxy()->IsArguments()) { | 2831 args->at(1)->AsVariableProxy()->IsArguments()) { |
| 2825 // Use the optimized Function.prototype.apply that avoids | 2832 // Use the optimized Function.prototype.apply that avoids |
| 2826 // allocating lazily allocated arguments objects. | 2833 // allocating lazily allocated arguments objects. |
| 2827 CallApplyLazy(property->obj(), | 2834 CallApplyLazy(property->obj(), |
| 2828 args->at(0), | 2835 args->at(0), |
| 2829 args->at(1)->AsVariableProxy(), | 2836 args->at(1)->AsVariableProxy(), |
| 2830 node->position()); | 2837 node->position()); |
| 2831 | 2838 |
| 2832 } else { | 2839 } else { |
| 2833 // Push the name of the function and the receiver onto the stack. | 2840 // Push the receiver onto the frame. |
| 2834 frame_->Push(name); | |
| 2835 Load(property->obj()); | 2841 Load(property->obj()); |
| 2836 | 2842 |
| 2837 // Load the arguments. | 2843 // Load the arguments. |
| 2838 int arg_count = args->length(); | 2844 int arg_count = args->length(); |
| 2839 for (int i = 0; i < arg_count; i++) { | 2845 for (int i = 0; i < arg_count; i++) { |
| 2840 Load(args->at(i)); | 2846 Load(args->at(i)); |
| 2841 } | 2847 } |
| 2842 | 2848 |
| 2849 // Push the name of the function onto the frame. |
| 2850 frame_->Push(name); |
| 2851 |
| 2843 // Call the IC initialization code. | 2852 // Call the IC initialization code. |
| 2844 CodeForSourcePosition(node->position()); | 2853 CodeForSourcePosition(node->position()); |
| 2845 Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET, | 2854 Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET, |
| 2846 arg_count, | 2855 arg_count, |
| 2847 loop_nesting()); | 2856 loop_nesting()); |
| 2848 frame_->RestoreContextRegister(); | 2857 frame_->RestoreContextRegister(); |
| 2849 // Replace the function on the stack with the result. | 2858 frame_->Push(&result); |
| 2850 frame_->SetElementAt(0, &result); | |
| 2851 } | 2859 } |
| 2852 | 2860 |
| 2853 } else { | 2861 } else { |
| 2854 // ------------------------------------------- | 2862 // ------------------------------------------- |
| 2855 // JavaScript example: 'array[index](1, 2, 3)' | 2863 // JavaScript example: 'array[index](1, 2, 3)' |
| 2856 // ------------------------------------------- | 2864 // ------------------------------------------- |
| 2857 | 2865 |
| 2858 // Load the function to call from the property through a reference. | 2866 // Load the function to call from the property through a reference. |
| 2859 if (property->is_synthetic()) { | 2867 if (property->is_synthetic()) { |
| 2860 Reference ref(this, property, false); | 2868 Reference ref(this, property, false); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2931 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 2939 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 2932 if (CheckForInlineRuntimeCall(node)) { | 2940 if (CheckForInlineRuntimeCall(node)) { |
| 2933 return; | 2941 return; |
| 2934 } | 2942 } |
| 2935 | 2943 |
| 2936 ZoneList<Expression*>* args = node->arguments(); | 2944 ZoneList<Expression*>* args = node->arguments(); |
| 2937 Comment cmnt(masm_, "[ CallRuntime"); | 2945 Comment cmnt(masm_, "[ CallRuntime"); |
| 2938 Runtime::Function* function = node->function(); | 2946 Runtime::Function* function = node->function(); |
| 2939 | 2947 |
| 2940 if (function == NULL) { | 2948 if (function == NULL) { |
| 2941 // Prepare stack for calling JS runtime function. | |
| 2942 frame_->Push(node->name()); | |
| 2943 // Push the builtins object found in the current global object. | 2949 // Push the builtins object found in the current global object. |
| 2944 Result temp = allocator()->Allocate(); | 2950 Result temp = allocator()->Allocate(); |
| 2945 ASSERT(temp.is_valid()); | 2951 ASSERT(temp.is_valid()); |
| 2946 __ movq(temp.reg(), GlobalObject()); | 2952 __ movq(temp.reg(), GlobalObject()); |
| 2947 __ movq(temp.reg(), | 2953 __ movq(temp.reg(), |
| 2948 FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset)); | 2954 FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset)); |
| 2949 frame_->Push(&temp); | 2955 frame_->Push(&temp); |
| 2950 } | 2956 } |
| 2951 | 2957 |
| 2952 // Push the arguments ("left-to-right"). | 2958 // Push the arguments ("left-to-right"). |
| 2953 int arg_count = args->length(); | 2959 int arg_count = args->length(); |
| 2954 for (int i = 0; i < arg_count; i++) { | 2960 for (int i = 0; i < arg_count; i++) { |
| 2955 Load(args->at(i)); | 2961 Load(args->at(i)); |
| 2956 } | 2962 } |
| 2957 | 2963 |
| 2958 if (function == NULL) { | 2964 if (function == NULL) { |
| 2959 // Call the JS runtime function. | 2965 // Call the JS runtime function. |
| 2966 frame_->Push(node->name()); |
| 2960 Result answer = frame_->CallCallIC(RelocInfo::CODE_TARGET, | 2967 Result answer = frame_->CallCallIC(RelocInfo::CODE_TARGET, |
| 2961 arg_count, | 2968 arg_count, |
| 2962 loop_nesting_); | 2969 loop_nesting_); |
| 2963 frame_->RestoreContextRegister(); | 2970 frame_->RestoreContextRegister(); |
| 2964 frame_->SetElementAt(0, &answer); | 2971 frame_->Push(&answer); |
| 2965 } else { | 2972 } else { |
| 2966 // Call the C runtime function. | 2973 // Call the C runtime function. |
| 2967 Result answer = frame_->CallRuntime(function, arg_count); | 2974 Result answer = frame_->CallRuntime(function, arg_count); |
| 2968 frame_->Push(&answer); | 2975 frame_->Push(&answer); |
| 2969 } | 2976 } |
| 2970 } | 2977 } |
| 2971 | 2978 |
| 2972 | 2979 |
| 2973 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 2980 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| 2974 Comment cmnt(masm_, "[ UnaryOperation"); | 2981 Comment cmnt(masm_, "[ UnaryOperation"); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3063 Load(node->expression()); | 3070 Load(node->expression()); |
| 3064 switch (op) { | 3071 switch (op) { |
| 3065 case Token::NOT: | 3072 case Token::NOT: |
| 3066 case Token::DELETE: | 3073 case Token::DELETE: |
| 3067 case Token::TYPEOF: | 3074 case Token::TYPEOF: |
| 3068 UNREACHABLE(); // handled above | 3075 UNREACHABLE(); // handled above |
| 3069 break; | 3076 break; |
| 3070 | 3077 |
| 3071 case Token::SUB: { | 3078 case Token::SUB: { |
| 3072 GenericUnaryOpStub stub(Token::SUB, overwrite); | 3079 GenericUnaryOpStub stub(Token::SUB, overwrite); |
| 3073 // TODO(1222589): remove dependency of TOS being cached inside stub | |
| 3074 Result operand = frame_->Pop(); | 3080 Result operand = frame_->Pop(); |
| 3075 Result answer = frame_->CallStub(&stub, &operand); | 3081 Result answer = frame_->CallStub(&stub, &operand); |
| 3076 frame_->Push(&answer); | 3082 frame_->Push(&answer); |
| 3077 break; | 3083 break; |
| 3078 } | 3084 } |
| 3079 | 3085 |
| 3080 case Token::BIT_NOT: { | 3086 case Token::BIT_NOT: { |
| 3081 // Smi check. | 3087 // Smi check. |
| 3082 JumpTarget smi_label; | 3088 JumpTarget smi_label; |
| 3083 JumpTarget continue_label; | 3089 JumpTarget continue_label; |
| (...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3579 __ testq(answer.reg(), answer.reg()); | 3585 __ testq(answer.reg(), answer.reg()); |
| 3580 answer.Unuse(); | 3586 answer.Unuse(); |
| 3581 destination()->Split(zero); | 3587 destination()->Split(zero); |
| 3582 return; | 3588 return; |
| 3583 } | 3589 } |
| 3584 default: | 3590 default: |
| 3585 UNREACHABLE(); | 3591 UNREACHABLE(); |
| 3586 } | 3592 } |
| 3587 Load(left); | 3593 Load(left); |
| 3588 Load(right); | 3594 Load(right); |
| 3589 Comparison(cc, strict, destination()); | 3595 Comparison(node, cc, strict, destination()); |
| 3590 } | 3596 } |
| 3591 | 3597 |
| 3592 | 3598 |
| 3593 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 3599 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 3594 frame_->PushFunction(); | 3600 frame_->PushFunction(); |
| 3595 } | 3601 } |
| 3596 | 3602 |
| 3597 | 3603 |
| 3598 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 3604 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
| 3599 ASSERT(args->length() == 1); | 3605 ASSERT(args->length() == 1); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 3620 Condition is_smi = masm_->CheckSmi(value.reg()); | 3626 Condition is_smi = masm_->CheckSmi(value.reg()); |
| 3621 destination()->false_target()->Branch(is_smi); | 3627 destination()->false_target()->Branch(is_smi); |
| 3622 // It is a heap object - get map. | 3628 // It is a heap object - get map. |
| 3623 // Check if the object is a JS array or not. | 3629 // Check if the object is a JS array or not. |
| 3624 __ CmpObjectType(value.reg(), JS_ARRAY_TYPE, kScratchRegister); | 3630 __ CmpObjectType(value.reg(), JS_ARRAY_TYPE, kScratchRegister); |
| 3625 value.Unuse(); | 3631 value.Unuse(); |
| 3626 destination()->Split(equal); | 3632 destination()->Split(equal); |
| 3627 } | 3633 } |
| 3628 | 3634 |
| 3629 | 3635 |
| 3636 void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) { |
| 3637 ASSERT(args->length() == 1); |
| 3638 Load(args->at(0)); |
| 3639 Result value = frame_->Pop(); |
| 3640 value.ToRegister(); |
| 3641 ASSERT(value.is_valid()); |
| 3642 Condition is_smi = masm_->CheckSmi(value.reg()); |
| 3643 destination()->false_target()->Branch(is_smi); |
| 3644 // It is a heap object - get map. |
| 3645 // Check if the object is a regexp. |
| 3646 __ CmpObjectType(value.reg(), JS_REGEXP_TYPE, kScratchRegister); |
| 3647 value.Unuse(); |
| 3648 destination()->Split(equal); |
| 3649 } |
| 3650 |
| 3651 |
| 3630 void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { | 3652 void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { |
| 3631 // This generates a fast version of: | 3653 // This generates a fast version of: |
| 3632 // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') | 3654 // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') |
| 3633 ASSERT(args->length() == 1); | 3655 ASSERT(args->length() == 1); |
| 3634 Load(args->at(0)); | 3656 Load(args->at(0)); |
| 3635 Result obj = frame_->Pop(); | 3657 Result obj = frame_->Pop(); |
| 3636 obj.ToRegister(); | 3658 obj.ToRegister(); |
| 3637 Condition is_smi = masm_->CheckSmi(obj.reg()); | 3659 Condition is_smi = masm_->CheckSmi(obj.reg()); |
| 3638 destination()->false_target()->Branch(is_smi); | 3660 destination()->false_target()->Branch(is_smi); |
| 3639 | 3661 |
| (...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3964 Load(args->at(0)); | 3986 Load(args->at(0)); |
| 3965 Load(args->at(1)); | 3987 Load(args->at(1)); |
| 3966 Load(args->at(2)); | 3988 Load(args->at(2)); |
| 3967 Load(args->at(3)); | 3989 Load(args->at(3)); |
| 3968 RegExpExecStub stub; | 3990 RegExpExecStub stub; |
| 3969 Result result = frame_->CallStub(&stub, 4); | 3991 Result result = frame_->CallStub(&stub, 4); |
| 3970 frame_->Push(&result); | 3992 frame_->Push(&result); |
| 3971 } | 3993 } |
| 3972 | 3994 |
| 3973 | 3995 |
| 3996 void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) { |
| 3997 ASSERT_EQ(args->length(), 1); |
| 3998 |
| 3999 // Load the argument on the stack and jump to the runtime. |
| 4000 Load(args->at(0)); |
| 4001 |
| 4002 Result answer = frame_->CallRuntime(Runtime::kNumberToString, 1); |
| 4003 frame_->Push(&answer); |
| 4004 } |
| 4005 |
| 4006 |
| 4007 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { |
| 4008 ASSERT_EQ(args->length(), 1); |
| 4009 // Load the argument on the stack and jump to the runtime. |
| 4010 Load(args->at(0)); |
| 4011 Result answer = frame_->CallRuntime(Runtime::kMath_sin, 1); |
| 4012 frame_->Push(&answer); |
| 4013 } |
| 4014 |
| 4015 |
| 4016 void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { |
| 4017 ASSERT_EQ(args->length(), 1); |
| 4018 // Load the argument on the stack and jump to the runtime. |
| 4019 Load(args->at(0)); |
| 4020 Result answer = frame_->CallRuntime(Runtime::kMath_cos, 1); |
| 4021 frame_->Push(&answer); |
| 4022 } |
| 4023 |
| 4024 |
| 3974 void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { | 4025 void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { |
| 3975 ASSERT_EQ(2, args->length()); | 4026 ASSERT_EQ(2, args->length()); |
| 3976 | 4027 |
| 3977 Load(args->at(0)); | 4028 Load(args->at(0)); |
| 3978 Load(args->at(1)); | 4029 Load(args->at(1)); |
| 3979 | 4030 |
| 3980 StringAddStub stub(NO_STRING_ADD_FLAGS); | 4031 StringAddStub stub(NO_STRING_ADD_FLAGS); |
| 3981 Result answer = frame_->CallStub(&stub, 2); | 4032 Result answer = frame_->CallStub(&stub, 2); |
| 3982 frame_->Push(&answer); | 4033 frame_->Push(&answer); |
| 3983 } | 4034 } |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4253 | 4304 |
| 4254 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and | 4305 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and |
| 4255 // convert it to a boolean in the condition code register or jump to | 4306 // convert it to a boolean in the condition code register or jump to |
| 4256 // 'false_target'/'true_target' as appropriate. | 4307 // 'false_target'/'true_target' as appropriate. |
| 4257 void CodeGenerator::ToBoolean(ControlDestination* dest) { | 4308 void CodeGenerator::ToBoolean(ControlDestination* dest) { |
| 4258 Comment cmnt(masm_, "[ ToBoolean"); | 4309 Comment cmnt(masm_, "[ ToBoolean"); |
| 4259 | 4310 |
| 4260 // The value to convert should be popped from the frame. | 4311 // The value to convert should be popped from the frame. |
| 4261 Result value = frame_->Pop(); | 4312 Result value = frame_->Pop(); |
| 4262 value.ToRegister(); | 4313 value.ToRegister(); |
| 4263 // Fast case checks. | |
| 4264 | 4314 |
| 4265 // 'false' => false. | 4315 if (value.is_number()) { |
| 4266 __ CompareRoot(value.reg(), Heap::kFalseValueRootIndex); | 4316 Comment cmnt(masm_, "ONLY_NUMBER"); |
| 4267 dest->false_target()->Branch(equal); | 4317 // Fast case if NumberInfo indicates only numbers. |
| 4318 if (FLAG_debug_code) { |
| 4319 __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); |
| 4320 } |
| 4321 // Smi => false iff zero. |
| 4322 __ SmiCompare(value.reg(), Smi::FromInt(0)); |
| 4323 dest->false_target()->Branch(equal); |
| 4324 Condition is_smi = masm_->CheckSmi(value.reg()); |
| 4325 dest->true_target()->Branch(is_smi); |
| 4326 __ fldz(); |
| 4327 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); |
| 4328 __ FCmp(); |
| 4329 value.Unuse(); |
| 4330 dest->Split(not_zero); |
| 4331 } else { |
| 4332 // Fast case checks. |
| 4333 // 'false' => false. |
| 4334 __ CompareRoot(value.reg(), Heap::kFalseValueRootIndex); |
| 4335 dest->false_target()->Branch(equal); |
| 4268 | 4336 |
| 4269 // 'true' => true. | 4337 // 'true' => true. |
| 4270 __ CompareRoot(value.reg(), Heap::kTrueValueRootIndex); | 4338 __ CompareRoot(value.reg(), Heap::kTrueValueRootIndex); |
| 4271 dest->true_target()->Branch(equal); | 4339 dest->true_target()->Branch(equal); |
| 4272 | 4340 |
| 4273 // 'undefined' => false. | 4341 // 'undefined' => false. |
| 4274 __ CompareRoot(value.reg(), Heap::kUndefinedValueRootIndex); | 4342 __ CompareRoot(value.reg(), Heap::kUndefinedValueRootIndex); |
| 4275 dest->false_target()->Branch(equal); | 4343 dest->false_target()->Branch(equal); |
| 4276 | 4344 |
| 4277 // Smi => false iff zero. | 4345 // Smi => false iff zero. |
| 4278 __ SmiCompare(value.reg(), Smi::FromInt(0)); | 4346 __ SmiCompare(value.reg(), Smi::FromInt(0)); |
| 4279 dest->false_target()->Branch(equal); | 4347 dest->false_target()->Branch(equal); |
| 4280 Condition is_smi = masm_->CheckSmi(value.reg()); | 4348 Condition is_smi = masm_->CheckSmi(value.reg()); |
| 4281 dest->true_target()->Branch(is_smi); | 4349 dest->true_target()->Branch(is_smi); |
| 4282 | 4350 |
| 4283 // Call the stub for all other cases. | 4351 // Call the stub for all other cases. |
| 4284 frame_->Push(&value); // Undo the Pop() from above. | 4352 frame_->Push(&value); // Undo the Pop() from above. |
| 4285 ToBooleanStub stub; | 4353 ToBooleanStub stub; |
| 4286 Result temp = frame_->CallStub(&stub, 1); | 4354 Result temp = frame_->CallStub(&stub, 1); |
| 4287 // Convert the result to a condition code. | 4355 // Convert the result to a condition code. |
| 4288 __ testq(temp.reg(), temp.reg()); | 4356 __ testq(temp.reg(), temp.reg()); |
| 4289 temp.Unuse(); | 4357 temp.Unuse(); |
| 4290 dest->Split(not_equal); | 4358 dest->Split(not_equal); |
| 4359 } |
| 4291 } | 4360 } |
| 4292 | 4361 |
| 4293 | 4362 |
| 4294 void CodeGenerator::LoadUnsafeSmi(Register target, Handle<Object> value) { | 4363 void CodeGenerator::LoadUnsafeSmi(Register target, Handle<Object> value) { |
| 4295 UNIMPLEMENTED(); | 4364 UNIMPLEMENTED(); |
| 4296 // TODO(X64): Implement security policy for loads of smis. | 4365 // TODO(X64): Implement security policy for loads of smis. |
| 4297 } | 4366 } |
| 4298 | 4367 |
| 4299 | 4368 |
| 4300 bool CodeGenerator::IsUnsafeSmi(Handle<Object> value) { | 4369 bool CodeGenerator::IsUnsafeSmi(Handle<Object> value) { |
| (...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4861 // For a variable that rewrites to a slot, we signal it is the immediate | 4930 // For a variable that rewrites to a slot, we signal it is the immediate |
| 4862 // subexpression of a typeof. | 4931 // subexpression of a typeof. |
| 4863 LoadFromSlotCheckForArguments(variable->slot(), INSIDE_TYPEOF); | 4932 LoadFromSlotCheckForArguments(variable->slot(), INSIDE_TYPEOF); |
| 4864 } else { | 4933 } else { |
| 4865 // Anything else can be handled normally. | 4934 // Anything else can be handled normally. |
| 4866 Load(expr); | 4935 Load(expr); |
| 4867 } | 4936 } |
| 4868 } | 4937 } |
| 4869 | 4938 |
| 4870 | 4939 |
| 4871 void CodeGenerator::Comparison(Condition cc, | 4940 void CodeGenerator::Comparison(AstNode* node, |
| 4941 Condition cc, |
| 4872 bool strict, | 4942 bool strict, |
| 4873 ControlDestination* dest) { | 4943 ControlDestination* dest) { |
| 4874 // Strict only makes sense for equality comparisons. | 4944 // Strict only makes sense for equality comparisons. |
| 4875 ASSERT(!strict || cc == equal); | 4945 ASSERT(!strict || cc == equal); |
| 4876 | 4946 |
| 4877 Result left_side; | 4947 Result left_side; |
| 4878 Result right_side; | 4948 Result right_side; |
| 4879 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 4949 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| 4880 if (cc == greater || cc == less_equal) { | 4950 if (cc == greater || cc == less_equal) { |
| 4881 cc = ReverseCondition(cc); | 4951 cc = ReverseCondition(cc); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 4908 break; | 4978 break; |
| 4909 case equal: | 4979 case equal: |
| 4910 dest->Goto(left_value == right_value); | 4980 dest->Goto(left_value == right_value); |
| 4911 break; | 4981 break; |
| 4912 case greater_equal: | 4982 case greater_equal: |
| 4913 dest->Goto(left_value >= right_value); | 4983 dest->Goto(left_value >= right_value); |
| 4914 break; | 4984 break; |
| 4915 default: | 4985 default: |
| 4916 UNREACHABLE(); | 4986 UNREACHABLE(); |
| 4917 } | 4987 } |
| 4918 } else { // Only one side is a constant Smi. | 4988 } else { |
| 4989 // Only one side is a constant Smi. |
| 4919 // If left side is a constant Smi, reverse the operands. | 4990 // If left side is a constant Smi, reverse the operands. |
| 4920 // Since one side is a constant Smi, conversion order does not matter. | 4991 // Since one side is a constant Smi, conversion order does not matter. |
| 4921 if (left_side_constant_smi) { | 4992 if (left_side_constant_smi) { |
| 4922 Result temp = left_side; | 4993 Result temp = left_side; |
| 4923 left_side = right_side; | 4994 left_side = right_side; |
| 4924 right_side = temp; | 4995 right_side = temp; |
| 4925 cc = ReverseCondition(cc); | 4996 cc = ReverseCondition(cc); |
| 4926 // This may reintroduce greater or less_equal as the value of cc. | 4997 // This may reintroduce greater or less_equal as the value of cc. |
| 4927 // CompareStub and the inline code both support all values of cc. | 4998 // CompareStub and the inline code both support all values of cc. |
| 4928 } | 4999 } |
| 4929 // Implement comparison against a constant Smi, inlining the case | 5000 // Implement comparison against a constant Smi, inlining the case |
| 4930 // where both sides are Smis. | 5001 // where both sides are Smis. |
| 4931 left_side.ToRegister(); | 5002 left_side.ToRegister(); |
| 5003 Register left_reg = left_side.reg(); |
| 5004 Handle<Object> right_val = right_side.handle(); |
| 4932 | 5005 |
| 4933 // Here we split control flow to the stub call and inlined cases | 5006 // Here we split control flow to the stub call and inlined cases |
| 4934 // before finally splitting it to the control destination. We use | 5007 // before finally splitting it to the control destination. We use |
| 4935 // a jump target and branching to duplicate the virtual frame at | 5008 // a jump target and branching to duplicate the virtual frame at |
| 4936 // the first split. We manually handle the off-frame references | 5009 // the first split. We manually handle the off-frame references |
| 4937 // by reconstituting them on the non-fall-through path. | 5010 // by reconstituting them on the non-fall-through path. |
| 4938 JumpTarget is_smi; | 5011 JumpTarget is_smi; |
| 4939 Register left_reg = left_side.reg(); | |
| 4940 Handle<Object> right_val = right_side.handle(); | |
| 4941 | 5012 |
| 4942 Condition left_is_smi = masm_->CheckSmi(left_side.reg()); | 5013 Condition left_is_smi = masm_->CheckSmi(left_side.reg()); |
| 4943 is_smi.Branch(left_is_smi); | 5014 is_smi.Branch(left_is_smi); |
| 4944 | 5015 |
| 5016 bool is_for_loop_compare = (node->AsCompareOperation() != NULL) |
| 5017 && node->AsCompareOperation()->is_for_loop_condition(); |
| 5018 if (!is_for_loop_compare && right_val->IsSmi()) { |
| 5019 // Right side is a constant smi and left side has been checked |
| 5020 // not to be a smi. |
| 5021 JumpTarget not_number; |
| 5022 __ Cmp(FieldOperand(left_reg, HeapObject::kMapOffset), |
| 5023 Factory::heap_number_map()); |
| 5024 not_number.Branch(not_equal, &left_side); |
| 5025 __ movsd(xmm1, |
| 5026 FieldOperand(left_reg, HeapNumber::kValueOffset)); |
| 5027 int value = Smi::cast(*right_val)->value(); |
| 5028 if (value == 0) { |
| 5029 __ xorpd(xmm0, xmm0); |
| 5030 } else { |
| 5031 Result temp = allocator()->Allocate(); |
| 5032 __ movl(temp.reg(), Immediate(value)); |
| 5033 __ cvtlsi2sd(xmm0, temp.reg()); |
| 5034 temp.Unuse(); |
| 5035 } |
| 5036 __ ucomisd(xmm1, xmm0); |
| 5037 // Jump to builtin for NaN. |
| 5038 not_number.Branch(parity_even, &left_side); |
| 5039 left_side.Unuse(); |
| 5040 Condition double_cc = cc; |
| 5041 switch (cc) { |
| 5042 case less: double_cc = below; break; |
| 5043 case equal: double_cc = equal; break; |
| 5044 case less_equal: double_cc = below_equal; break; |
| 5045 case greater: double_cc = above; break; |
| 5046 case greater_equal: double_cc = above_equal; break; |
| 5047 default: UNREACHABLE(); |
| 5048 } |
| 5049 dest->true_target()->Branch(double_cc); |
| 5050 dest->false_target()->Jump(); |
| 5051 not_number.Bind(&left_side); |
| 5052 } |
| 5053 |
| 4945 // Setup and call the compare stub. | 5054 // Setup and call the compare stub. |
| 4946 CompareStub stub(cc, strict); | 5055 CompareStub stub(cc, strict); |
| 4947 Result result = frame_->CallStub(&stub, &left_side, &right_side); | 5056 Result result = frame_->CallStub(&stub, &left_side, &right_side); |
| 4948 result.ToRegister(); | 5057 result.ToRegister(); |
| 4949 __ testq(result.reg(), result.reg()); | 5058 __ testq(result.reg(), result.reg()); |
| 4950 result.Unuse(); | 5059 result.Unuse(); |
| 4951 dest->true_target()->Branch(cc); | 5060 dest->true_target()->Branch(cc); |
| 4952 dest->false_target()->Jump(); | 5061 dest->false_target()->Jump(); |
| 4953 | 5062 |
| 4954 is_smi.Bind(); | 5063 is_smi.Bind(); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5107 } else if (right_is_string) { | 5216 } else if (right_is_string) { |
| 5108 answer = | 5217 answer = |
| 5109 frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2); | 5218 frame_->InvokeBuiltin(Builtins::STRING_ADD_RIGHT, CALL_FUNCTION, 2); |
| 5110 } | 5219 } |
| 5111 frame_->Push(&answer); | 5220 frame_->Push(&answer); |
| 5112 return; | 5221 return; |
| 5113 } | 5222 } |
| 5114 // Neither operand is known to be a string. | 5223 // Neither operand is known to be a string. |
| 5115 } | 5224 } |
| 5116 | 5225 |
| 5117 bool left_is_smi = left.is_constant() && left.handle()->IsSmi(); | 5226 bool left_is_smi_constant = left.is_constant() && left.handle()->IsSmi(); |
| 5118 bool left_is_non_smi = left.is_constant() && !left.handle()->IsSmi(); | 5227 bool left_is_non_smi_constant = left.is_constant() && !left.handle()->IsSmi(); |
| 5119 bool right_is_smi = right.is_constant() && right.handle()->IsSmi(); | 5228 bool right_is_smi_constant = right.is_constant() && right.handle()->IsSmi(); |
| 5120 bool right_is_non_smi = right.is_constant() && !right.handle()->IsSmi(); | 5229 bool right_is_non_smi_constant = |
| 5230 right.is_constant() && !right.handle()->IsSmi(); |
| 5121 | 5231 |
| 5122 if (left_is_smi && right_is_smi) { | 5232 if (left_is_smi_constant && right_is_smi_constant) { |
| 5123 // Compute the constant result at compile time, and leave it on the frame. | 5233 // Compute the constant result at compile time, and leave it on the frame. |
| 5124 int left_int = Smi::cast(*left.handle())->value(); | 5234 int left_int = Smi::cast(*left.handle())->value(); |
| 5125 int right_int = Smi::cast(*right.handle())->value(); | 5235 int right_int = Smi::cast(*right.handle())->value(); |
| 5126 if (FoldConstantSmis(op, left_int, right_int)) return; | 5236 if (FoldConstantSmis(op, left_int, right_int)) return; |
| 5127 } | 5237 } |
| 5128 | 5238 |
| 5239 // Get number type of left and right sub-expressions. |
| 5240 NumberInfo::Type operands_type = |
| 5241 NumberInfo::Combine(left.number_info(), right.number_info()); |
| 5242 |
| 5129 Result answer; | 5243 Result answer; |
| 5130 if (left_is_non_smi || right_is_non_smi) { | 5244 if (left_is_non_smi_constant || right_is_non_smi_constant) { |
| 5131 GenericBinaryOpStub stub(op, overwrite_mode, NO_SMI_CODE_IN_STUB); | 5245 GenericBinaryOpStub stub(op, |
| 5246 overwrite_mode, |
| 5247 NO_SMI_CODE_IN_STUB, |
| 5248 operands_type); |
| 5132 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 5249 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
| 5133 } else if (right_is_smi) { | 5250 } else if (right_is_smi_constant) { |
| 5134 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), | 5251 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), |
| 5135 type, false, overwrite_mode); | 5252 type, false, overwrite_mode); |
| 5136 } else if (left_is_smi) { | 5253 } else if (left_is_smi_constant) { |
| 5137 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), | 5254 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), |
| 5138 type, true, overwrite_mode); | 5255 type, true, overwrite_mode); |
| 5139 } else { | 5256 } else { |
| 5140 // Set the flags based on the operation, type and loop nesting level. | 5257 // Set the flags based on the operation, type and loop nesting level. |
| 5141 // Bit operations always assume they likely operate on Smis. Still only | 5258 // Bit operations always assume they likely operate on Smis. Still only |
| 5142 // generate the inline Smi check code if this operation is part of a loop. | 5259 // generate the inline Smi check code if this operation is part of a loop. |
| 5143 // For all other operations only inline the Smi check code for likely smis | 5260 // For all other operations only inline the Smi check code for likely smis |
| 5144 // if the operation is part of a loop. | 5261 // if the operation is part of a loop. |
| 5145 if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) { | 5262 if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) { |
| 5146 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); | 5263 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); |
| 5147 } else { | 5264 } else { |
| 5148 GenericBinaryOpStub stub(op, overwrite_mode, NO_GENERIC_BINARY_FLAGS); | 5265 GenericBinaryOpStub stub(op, |
| 5266 overwrite_mode, |
| 5267 NO_GENERIC_BINARY_FLAGS, |
| 5268 operands_type); |
| 5149 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 5269 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
| 5150 } | 5270 } |
| 5151 } | 5271 } |
| 5272 |
| 5273 // Set NumberInfo of result according to the operation performed. |
| 5274 // We rely on the fact that smis have a 32 bit payload on x64. |
| 5275 ASSERT(kSmiValueSize == 32); |
| 5276 NumberInfo::Type result_type = NumberInfo::kUnknown; |
| 5277 switch (op) { |
| 5278 case Token::COMMA: |
| 5279 result_type = right.number_info(); |
| 5280 break; |
| 5281 case Token::OR: |
| 5282 case Token::AND: |
| 5283 // Result type can be either of the two input types. |
| 5284 result_type = operands_type; |
| 5285 break; |
| 5286 case Token::BIT_OR: |
| 5287 case Token::BIT_XOR: |
| 5288 case Token::BIT_AND: |
| 5289 // Result is always a smi. |
| 5290 result_type = NumberInfo::kSmi; |
| 5291 break; |
| 5292 case Token::SAR: |
| 5293 case Token::SHL: |
| 5294 // Result is always a smi. |
| 5295 result_type = NumberInfo::kSmi; |
| 5296 break; |
| 5297 case Token::SHR: |
| 5298 // Result of x >>> y is always a smi if y >= 1, otherwise a number. |
| 5299 result_type = (right.is_constant() && right.handle()->IsSmi() |
| 5300 && Smi::cast(*right.handle())->value() >= 1) |
| 5301 ? NumberInfo::kSmi |
| 5302 : NumberInfo::kNumber; |
| 5303 break; |
| 5304 case Token::ADD: |
| 5305 // Result could be a string or a number. Check types of inputs. |
| 5306 result_type = NumberInfo::IsNumber(operands_type) |
| 5307 ? NumberInfo::kNumber |
| 5308 : NumberInfo::kUnknown; |
| 5309 break; |
| 5310 case Token::SUB: |
| 5311 case Token::MUL: |
| 5312 case Token::DIV: |
| 5313 case Token::MOD: |
| 5314 // Result is always a number. |
| 5315 result_type = NumberInfo::kNumber; |
| 5316 break; |
| 5317 default: |
| 5318 UNREACHABLE(); |
| 5319 } |
| 5320 answer.set_number_info(result_type); |
| 5152 frame_->Push(&answer); | 5321 frame_->Push(&answer); |
| 5153 } | 5322 } |
| 5154 | 5323 |
| 5155 | 5324 |
| 5156 // Emit a LoadIC call to get the value from receiver and leave it in | 5325 // Emit a LoadIC call to get the value from receiver and leave it in |
| 5157 // dst. The receiver register is restored after the call. | 5326 // dst. The receiver register is restored after the call. |
| 5158 class DeferredReferenceGetNamedValue: public DeferredCode { | 5327 class DeferredReferenceGetNamedValue: public DeferredCode { |
| 5159 public: | 5328 public: |
| 5160 DeferredReferenceGetNamedValue(Register dst, | 5329 DeferredReferenceGetNamedValue(Register dst, |
| 5161 Register receiver, | 5330 Register receiver, |
| (...skipping 1052 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6214 // Return and remove the on-stack parameter. | 6383 // Return and remove the on-stack parameter. |
| 6215 __ movq(rsi, rax); | 6384 __ movq(rsi, rax); |
| 6216 __ ret(1 * kPointerSize); | 6385 __ ret(1 * kPointerSize); |
| 6217 | 6386 |
| 6218 // Need to collect. Call into runtime system. | 6387 // Need to collect. Call into runtime system. |
| 6219 __ bind(&gc); | 6388 __ bind(&gc); |
| 6220 __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1); | 6389 __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1); |
| 6221 } | 6390 } |
| 6222 | 6391 |
| 6223 | 6392 |
| 6393 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
| 6394 // Stack layout on entry: |
| 6395 // |
| 6396 // [rsp + kPointerSize]: constant elements. |
| 6397 // [rsp + (2 * kPointerSize)]: literal index. |
| 6398 // [rsp + (3 * kPointerSize)]: literals array. |
| 6399 |
| 6400 // All sizes here are multiples of kPointerSize. |
| 6401 int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; |
| 6402 int size = JSArray::kSize + elements_size; |
| 6403 |
| 6404 // Load boilerplate object into rcx and check if we need to create a |
| 6405 // boilerplate. |
| 6406 Label slow_case; |
| 6407 __ movq(rcx, Operand(rsp, 3 * kPointerSize)); |
| 6408 __ movq(rax, Operand(rsp, 2 * kPointerSize)); |
| 6409 SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2); |
| 6410 __ movq(rcx, |
| 6411 FieldOperand(rcx, index.reg, index.scale, FixedArray::kHeaderSize)); |
| 6412 __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex); |
| 6413 __ j(equal, &slow_case); |
| 6414 |
| 6415 // Allocate both the JS array and the elements array in one big |
| 6416 // allocation. This avoids multiple limit checks. |
| 6417 __ AllocateInNewSpace(size, rax, rbx, rdx, &slow_case, TAG_OBJECT); |
| 6418 |
| 6419 // Copy the JS array part. |
| 6420 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { |
| 6421 if ((i != JSArray::kElementsOffset) || (length_ == 0)) { |
| 6422 __ movq(rbx, FieldOperand(rcx, i)); |
| 6423 __ movq(FieldOperand(rax, i), rbx); |
| 6424 } |
| 6425 } |
| 6426 |
| 6427 if (length_ > 0) { |
| 6428 // Get hold of the elements array of the boilerplate and setup the |
| 6429 // elements pointer in the resulting object. |
| 6430 __ movq(rcx, FieldOperand(rcx, JSArray::kElementsOffset)); |
| 6431 __ lea(rdx, Operand(rax, JSArray::kSize)); |
| 6432 __ movq(FieldOperand(rax, JSArray::kElementsOffset), rdx); |
| 6433 |
| 6434 // Copy the elements array. |
| 6435 for (int i = 0; i < elements_size; i += kPointerSize) { |
| 6436 __ movq(rbx, FieldOperand(rcx, i)); |
| 6437 __ movq(FieldOperand(rdx, i), rbx); |
| 6438 } |
| 6439 } |
| 6440 |
| 6441 // Return and remove the on-stack parameters. |
| 6442 __ ret(3 * kPointerSize); |
| 6443 |
| 6444 __ bind(&slow_case); |
| 6445 ExternalReference runtime(Runtime::kCreateArrayLiteralShallow); |
| 6446 __ TailCallRuntime(runtime, 3, 1); |
| 6447 } |
| 6448 |
| 6449 |
| 6224 void ToBooleanStub::Generate(MacroAssembler* masm) { | 6450 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 6225 Label false_result, true_result, not_string; | 6451 Label false_result, true_result, not_string; |
| 6226 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | 6452 __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
| 6227 | 6453 |
| 6228 // 'null' => false. | 6454 // 'null' => false. |
| 6229 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 6455 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 6230 __ j(equal, &false_result); | 6456 __ j(equal, &false_result); |
| 6231 | 6457 |
| 6232 // Get the map and type of the heap object. | 6458 // Get the map and type of the heap object. |
| 6233 // We don't use CmpObjectType because we manipulate the type field. | 6459 // We don't use CmpObjectType because we manipulate the type field. |
| (...skipping 993 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7227 __ movl(rax, Immediate(1)); | 7453 __ movl(rax, Immediate(1)); |
| 7228 __ ret(2 * kPointerSize); | 7454 __ ret(2 * kPointerSize); |
| 7229 | 7455 |
| 7230 // Slow-case: Go through the JavaScript implementation. | 7456 // Slow-case: Go through the JavaScript implementation. |
| 7231 __ bind(&slow); | 7457 __ bind(&slow); |
| 7232 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 7458 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 7233 } | 7459 } |
| 7234 | 7460 |
| 7235 | 7461 |
| 7236 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { | 7462 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { |
| 7463 // rsp[0] : return address |
| 7464 // rsp[8] : number of parameters |
| 7465 // rsp[16] : receiver displacement |
| 7466 // rsp[24] : function |
| 7467 |
| 7237 // The displacement is used for skipping the return address and the | 7468 // The displacement is used for skipping the return address and the |
| 7238 // frame pointer on the stack. It is the offset of the last | 7469 // frame pointer on the stack. It is the offset of the last |
| 7239 // parameter (if any) relative to the frame pointer. | 7470 // parameter (if any) relative to the frame pointer. |
| 7240 static const int kDisplacement = 2 * kPointerSize; | 7471 static const int kDisplacement = 2 * kPointerSize; |
| 7241 | 7472 |
| 7242 // Check if the calling frame is an arguments adaptor frame. | 7473 // Check if the calling frame is an arguments adaptor frame. |
| 7243 Label runtime; | 7474 Label adaptor_frame, try_allocate, runtime; |
| 7244 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 7475 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 7245 __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), | 7476 __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), |
| 7246 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 7477 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 7247 __ j(not_equal, &runtime); | 7478 __ j(equal, &adaptor_frame); |
| 7248 // Value in rcx is Smi encoded. | 7479 |
| 7480 // Get the length from the frame. |
| 7481 __ movq(rcx, Operand(rsp, 1 * kPointerSize)); |
| 7482 __ jmp(&try_allocate); |
| 7249 | 7483 |
| 7250 // Patch the arguments.length and the parameters pointer. | 7484 // Patch the arguments.length and the parameters pointer. |
| 7485 __ bind(&adaptor_frame); |
| 7251 __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 7486 __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 7252 __ movq(Operand(rsp, 1 * kPointerSize), rcx); | 7487 __ movq(Operand(rsp, 1 * kPointerSize), rcx); |
| 7253 SmiIndex index = masm->SmiToIndex(rcx, rcx, kPointerSizeLog2); | 7488 // Do not clobber the length index for the indexing operation since |
| 7489 // it is used compute the size for allocation later. |
| 7490 SmiIndex index = masm->SmiToIndex(rbx, rcx, kPointerSizeLog2); |
| 7254 __ lea(rdx, Operand(rdx, index.reg, index.scale, kDisplacement)); | 7491 __ lea(rdx, Operand(rdx, index.reg, index.scale, kDisplacement)); |
| 7255 __ movq(Operand(rsp, 2 * kPointerSize), rdx); | 7492 __ movq(Operand(rsp, 2 * kPointerSize), rdx); |
| 7256 | 7493 |
| 7494 // Try the new space allocation. Start out with computing the size of |
| 7495 // the arguments object and the elements array. |
| 7496 Label add_arguments_object; |
| 7497 __ bind(&try_allocate); |
| 7498 __ testq(rcx, rcx); |
| 7499 __ j(zero, &add_arguments_object); |
| 7500 index = masm->SmiToIndex(rcx, rcx, kPointerSizeLog2); |
| 7501 __ lea(rcx, Operand(index.reg, index.scale, FixedArray::kHeaderSize)); |
| 7502 __ bind(&add_arguments_object); |
| 7503 __ addq(rcx, Immediate(Heap::kArgumentsObjectSize)); |
| 7504 |
| 7505 // Do the allocation of both objects in one go. |
| 7506 __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT); |
| 7507 |
| 7508 // Get the arguments boilerplate from the current (global) context. |
| 7509 int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX); |
| 7510 __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 7511 __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset)); |
| 7512 __ movq(rdi, Operand(rdi, offset)); |
| 7513 |
| 7514 // Copy the JS object part. |
| 7515 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
| 7516 __ movq(kScratchRegister, FieldOperand(rdi, i)); |
| 7517 __ movq(FieldOperand(rax, i), kScratchRegister); |
| 7518 } |
| 7519 |
| 7520 // Setup the callee in-object property. |
| 7521 ASSERT(Heap::arguments_callee_index == 0); |
| 7522 __ movq(kScratchRegister, Operand(rsp, 3 * kPointerSize)); |
| 7523 __ movq(FieldOperand(rax, JSObject::kHeaderSize), kScratchRegister); |
| 7524 |
| 7525 // Get the length (smi tagged) and set that as an in-object property too. |
| 7526 ASSERT(Heap::arguments_length_index == 1); |
| 7527 __ movq(rcx, Operand(rsp, 1 * kPointerSize)); |
| 7528 __ movq(FieldOperand(rax, JSObject::kHeaderSize + kPointerSize), rcx); |
| 7529 |
| 7530 // If there are no actual arguments, we're done. |
| 7531 Label done; |
| 7532 __ testq(rcx, rcx); |
| 7533 __ j(zero, &done); |
| 7534 |
| 7535 // Get the parameters pointer from the stack and untag the length. |
| 7536 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); |
| 7537 __ SmiToInteger32(rcx, rcx); |
| 7538 |
| 7539 // Setup the elements pointer in the allocated arguments object and |
| 7540 // initialize the header in the elements fixed array. |
| 7541 __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize)); |
| 7542 __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi); |
| 7543 __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex); |
| 7544 __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); |
| 7545 __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); |
| 7546 |
| 7547 // Copy the fixed array slots. |
| 7548 Label loop; |
| 7549 __ bind(&loop); |
| 7550 __ movq(kScratchRegister, Operand(rdx, -1 * kPointerSize)); // Skip receiver. |
| 7551 __ movq(FieldOperand(rdi, FixedArray::kHeaderSize), kScratchRegister); |
| 7552 __ addq(rdi, Immediate(kPointerSize)); |
| 7553 __ subq(rdx, Immediate(kPointerSize)); |
| 7554 __ decq(rcx); |
| 7555 __ j(not_zero, &loop); |
| 7556 |
| 7557 // Return and remove the on-stack parameters. |
| 7558 __ bind(&done); |
| 7559 __ ret(3 * kPointerSize); |
| 7560 |
| 7257 // Do the runtime call to allocate the arguments object. | 7561 // Do the runtime call to allocate the arguments object. |
| 7258 __ bind(&runtime); | 7562 __ bind(&runtime); |
| 7259 Runtime::Function* f = Runtime::FunctionForId(Runtime::kNewArgumentsFast); | 7563 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1); |
| 7260 __ TailCallRuntime(ExternalReference(f), 3, f->result_size); | |
| 7261 } | 7564 } |
| 7262 | 7565 |
| 7263 | 7566 |
| 7264 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { | 7567 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { |
| 7265 // The key is in rdx and the parameter count is in rax. | 7568 // The key is in rdx and the parameter count is in rax. |
| 7266 | 7569 |
| 7267 // The displacement is used for skipping the frame pointer on the | 7570 // The displacement is used for skipping the frame pointer on the |
| 7268 // stack. It is the offset of the last parameter (if any) relative | 7571 // stack. It is the offset of the last parameter (if any) relative |
| 7269 // to the frame pointer. | 7572 // to the frame pointer. |
| 7270 static const int kDisplacement = 1 * kPointerSize; | 7573 static const int kDisplacement = 1 * kPointerSize; |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7585 // Goto slow case if we do not have a function. | 7888 // Goto slow case if we do not have a function. |
| 7586 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | 7889 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
| 7587 __ j(not_equal, &slow); | 7890 __ j(not_equal, &slow); |
| 7588 | 7891 |
| 7589 // Fast-case: Just invoke the function. | 7892 // Fast-case: Just invoke the function. |
| 7590 ParameterCount actual(argc_); | 7893 ParameterCount actual(argc_); |
| 7591 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | 7894 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); |
| 7592 | 7895 |
| 7593 // Slow-case: Non-function called. | 7896 // Slow-case: Non-function called. |
| 7594 __ bind(&slow); | 7897 __ bind(&slow); |
| 7898 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead |
| 7899 // of the original receiver from the call site). |
| 7900 __ movq(Operand(rsp, (argc_ + 1) * kPointerSize), rdi); |
| 7595 __ Set(rax, argc_); | 7901 __ Set(rax, argc_); |
| 7596 __ Set(rbx, 0); | 7902 __ Set(rbx, 0); |
| 7597 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); | 7903 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); |
| 7598 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); | 7904 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); |
| 7599 __ Jump(adaptor, RelocInfo::CODE_TARGET); | 7905 __ Jump(adaptor, RelocInfo::CODE_TARGET); |
| 7600 } | 7906 } |
| 7601 | 7907 |
| 7602 | 7908 |
| 7603 void CEntryStub::Generate(MacroAssembler* masm) { | 7909 void CEntryStub::Generate(MacroAssembler* masm) { |
| 7604 // rax: number of arguments including receiver | 7910 // rax: number of arguments including receiver |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7973 const char* op_name = Token::Name(op_); | 8279 const char* op_name = Token::Name(op_); |
| 7974 const char* overwrite_name; | 8280 const char* overwrite_name; |
| 7975 switch (mode_) { | 8281 switch (mode_) { |
| 7976 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 8282 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 7977 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 8283 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
| 7978 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 8284 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
| 7979 default: overwrite_name = "UnknownOverwrite"; break; | 8285 default: overwrite_name = "UnknownOverwrite"; break; |
| 7980 } | 8286 } |
| 7981 | 8287 |
| 7982 OS::SNPrintF(Vector<char>(name_, len), | 8288 OS::SNPrintF(Vector<char>(name_, len), |
| 7983 "GenericBinaryOpStub_%s_%s%s_%s%s_%s", | 8289 "GenericBinaryOpStub_%s_%s%s_%s%s_%s%s", |
| 7984 op_name, | 8290 op_name, |
| 7985 overwrite_name, | 8291 overwrite_name, |
| 7986 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", | 8292 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", |
| 7987 args_in_registers_ ? "RegArgs" : "StackArgs", | 8293 args_in_registers_ ? "RegArgs" : "StackArgs", |
| 7988 args_reversed_ ? "_R" : "", | 8294 args_reversed_ ? "_R" : "", |
| 7989 use_sse3_ ? "SSE3" : "SSE2"); | 8295 use_sse3_ ? "SSE3" : "SSE2", |
| 8296 NumberInfo::ToString(operands_type_)); |
| 7990 return name_; | 8297 return name_; |
| 7991 } | 8298 } |
| 7992 | 8299 |
| 7993 | 8300 |
| 7994 void GenericBinaryOpStub::GenerateCall( | 8301 void GenericBinaryOpStub::GenerateCall( |
| 7995 MacroAssembler* masm, | 8302 MacroAssembler* masm, |
| 7996 Register left, | 8303 Register left, |
| 7997 Register right) { | 8304 Register right) { |
| 7998 if (!ArgsInRegistersSupported()) { | 8305 if (!ArgsInRegistersSupported()) { |
| 7999 // Pass arguments on the stack. | 8306 // Pass arguments on the stack. |
| 8000 __ push(left); | 8307 __ push(left); |
| 8001 __ push(right); | 8308 __ push(right); |
| 8002 } else { | 8309 } else { |
| 8003 // The calling convention with registers is left in rdx and right in rax. | 8310 // The calling convention with registers is left in rdx and right in rax. |
| 8004 Register left_arg = rdx; | 8311 Register left_arg = rdx; |
| 8005 Register right_arg = rax; | 8312 Register right_arg = rax; |
| 8006 if (!(left.is(left_arg) && right.is(right_arg))) { | 8313 if (!(left.is(left_arg) && right.is(right_arg))) { |
| 8007 if (left.is(right_arg) && right.is(left_arg)) { | 8314 if (left.is(right_arg) && right.is(left_arg)) { |
| 8008 if (IsOperationCommutative()) { | 8315 if (IsOperationCommutative()) { |
| 8009 SetArgsReversed(); | 8316 SetArgsReversed(); |
| 8010 } else { | 8317 } else { |
| 8011 __ xchg(left, right); | 8318 __ xchg(left, right); |
| 8012 } | 8319 } |
| 8013 } else if (left.is(left_arg)) { | 8320 } else if (left.is(left_arg)) { |
| 8014 __ movq(right_arg, right); | 8321 __ movq(right_arg, right); |
| 8322 } else if (right.is(right_arg)) { |
| 8323 __ movq(left_arg, left); |
| 8015 } else if (left.is(right_arg)) { | 8324 } else if (left.is(right_arg)) { |
| 8016 if (IsOperationCommutative()) { | 8325 if (IsOperationCommutative()) { |
| 8017 __ movq(left_arg, right); | 8326 __ movq(left_arg, right); |
| 8018 SetArgsReversed(); | 8327 SetArgsReversed(); |
| 8019 } else { | 8328 } else { |
| 8020 // Order of moves important to avoid destroying left argument. | 8329 // Order of moves important to avoid destroying left argument. |
| 8021 __ movq(left_arg, left); | 8330 __ movq(left_arg, left); |
| 8022 __ movq(right_arg, right); | 8331 __ movq(right_arg, right); |
| 8023 } | 8332 } |
| 8024 } else if (right.is(left_arg)) { | 8333 } else if (right.is(left_arg)) { |
| 8025 if (IsOperationCommutative()) { | 8334 if (IsOperationCommutative()) { |
| 8026 __ movq(right_arg, left); | 8335 __ movq(right_arg, left); |
| 8027 SetArgsReversed(); | 8336 SetArgsReversed(); |
| 8028 } else { | 8337 } else { |
| 8029 // Order of moves important to avoid destroying right argument. | 8338 // Order of moves important to avoid destroying right argument. |
| 8030 __ movq(right_arg, right); | 8339 __ movq(right_arg, right); |
| 8031 __ movq(left_arg, left); | 8340 __ movq(left_arg, left); |
| 8032 } | 8341 } |
| 8033 } else if (right.is(right_arg)) { | |
| 8034 __ movq(left_arg, left); | |
| 8035 } else { | 8342 } else { |
| 8036 // Order of moves is not important. | 8343 // Order of moves is not important. |
| 8037 __ movq(left_arg, left); | 8344 __ movq(left_arg, left); |
| 8038 __ movq(right_arg, right); | 8345 __ movq(right_arg, right); |
| 8039 } | 8346 } |
| 8040 } | 8347 } |
| 8041 | 8348 |
| 8042 // Update flags to indicate that arguments are in registers. | 8349 // Update flags to indicate that arguments are in registers. |
| 8043 SetArgsInRegisters(); | 8350 SetArgsInRegisters(); |
| 8044 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 8351 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 8060 } else { | 8367 } else { |
| 8061 // The calling convention with registers is left in rdx and right in rax. | 8368 // The calling convention with registers is left in rdx and right in rax. |
| 8062 Register left_arg = rdx; | 8369 Register left_arg = rdx; |
| 8063 Register right_arg = rax; | 8370 Register right_arg = rax; |
| 8064 if (left.is(left_arg)) { | 8371 if (left.is(left_arg)) { |
| 8065 __ Move(right_arg, right); | 8372 __ Move(right_arg, right); |
| 8066 } else if (left.is(right_arg) && IsOperationCommutative()) { | 8373 } else if (left.is(right_arg) && IsOperationCommutative()) { |
| 8067 __ Move(left_arg, right); | 8374 __ Move(left_arg, right); |
| 8068 SetArgsReversed(); | 8375 SetArgsReversed(); |
| 8069 } else { | 8376 } else { |
| 8377 // For non-commutative operations, left and right_arg might be |
| 8378 // the same register. Therefore, the order of the moves is |
| 8379 // important here in order to not overwrite left before moving |
| 8380 // it to left_arg. |
| 8070 __ movq(left_arg, left); | 8381 __ movq(left_arg, left); |
| 8071 __ Move(right_arg, right); | 8382 __ Move(right_arg, right); |
| 8072 } | 8383 } |
| 8073 | 8384 |
| 8074 // Update flags to indicate that arguments are in registers. | 8385 // Update flags to indicate that arguments are in registers. |
| 8075 SetArgsInRegisters(); | 8386 SetArgsInRegisters(); |
| 8076 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 8387 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); |
| 8077 } | 8388 } |
| 8078 | 8389 |
| 8079 // Call the stub. | 8390 // Call the stub. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 8092 } else { | 8403 } else { |
| 8093 // The calling convention with registers is left in rdx and right in rax. | 8404 // The calling convention with registers is left in rdx and right in rax. |
| 8094 Register left_arg = rdx; | 8405 Register left_arg = rdx; |
| 8095 Register right_arg = rax; | 8406 Register right_arg = rax; |
| 8096 if (right.is(right_arg)) { | 8407 if (right.is(right_arg)) { |
| 8097 __ Move(left_arg, left); | 8408 __ Move(left_arg, left); |
| 8098 } else if (right.is(left_arg) && IsOperationCommutative()) { | 8409 } else if (right.is(left_arg) && IsOperationCommutative()) { |
| 8099 __ Move(right_arg, left); | 8410 __ Move(right_arg, left); |
| 8100 SetArgsReversed(); | 8411 SetArgsReversed(); |
| 8101 } else { | 8412 } else { |
| 8413 // For non-commutative operations, right and left_arg might be |
| 8414 // the same register. Therefore, the order of the moves is |
| 8415 // important here in order to not overwrite right before moving |
| 8416 // it to right_arg. |
| 8417 __ movq(right_arg, right); |
| 8102 __ Move(left_arg, left); | 8418 __ Move(left_arg, left); |
| 8103 __ movq(right_arg, right); | |
| 8104 } | 8419 } |
| 8105 // Update flags to indicate that arguments are in registers. | 8420 // Update flags to indicate that arguments are in registers. |
| 8106 SetArgsInRegisters(); | 8421 SetArgsInRegisters(); |
| 8107 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 8422 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); |
| 8108 } | 8423 } |
| 8109 | 8424 |
| 8110 // Call the stub. | 8425 // Call the stub. |
| 8111 __ CallStub(this); | 8426 __ CallStub(this); |
| 8112 } | 8427 } |
| 8113 | 8428 |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8295 GenerateLoadArguments(masm); | 8610 GenerateLoadArguments(masm); |
| 8296 } | 8611 } |
| 8297 // Floating point case. | 8612 // Floating point case. |
| 8298 switch (op_) { | 8613 switch (op_) { |
| 8299 case Token::ADD: | 8614 case Token::ADD: |
| 8300 case Token::SUB: | 8615 case Token::SUB: |
| 8301 case Token::MUL: | 8616 case Token::MUL: |
| 8302 case Token::DIV: { | 8617 case Token::DIV: { |
| 8303 // rax: y | 8618 // rax: y |
| 8304 // rdx: x | 8619 // rdx: x |
| 8305 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); | 8620 if (NumberInfo::IsNumber(operands_type_)) { |
| 8621 if (FLAG_debug_code) { |
| 8622 // Assert at runtime that inputs are only numbers. |
| 8623 __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number."); |
| 8624 __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number."); |
| 8625 } |
| 8626 } else { |
| 8627 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); |
| 8628 } |
| 8306 // Fast-case: Both operands are numbers. | 8629 // Fast-case: Both operands are numbers. |
| 8307 // xmm4 and xmm5 are volatile XMM registers. | 8630 // xmm4 and xmm5 are volatile XMM registers. |
| 8308 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); | 8631 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); |
| 8309 | 8632 |
| 8310 switch (op_) { | 8633 switch (op_) { |
| 8311 case Token::ADD: __ addsd(xmm4, xmm5); break; | 8634 case Token::ADD: __ addsd(xmm4, xmm5); break; |
| 8312 case Token::SUB: __ subsd(xmm4, xmm5); break; | 8635 case Token::SUB: __ subsd(xmm4, xmm5); break; |
| 8313 case Token::MUL: __ mulsd(xmm4, xmm5); break; | 8636 case Token::MUL: __ mulsd(xmm4, xmm5); break; |
| 8314 case Token::DIV: __ divsd(xmm4, xmm5); break; | 8637 case Token::DIV: __ divsd(xmm4, xmm5); break; |
| 8315 default: UNREACHABLE(); | 8638 default: UNREACHABLE(); |
| (...skipping 875 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9191 // Call the function from C++. | 9514 // Call the function from C++. |
| 9192 return FUNCTION_CAST<ModuloFunction>(buffer); | 9515 return FUNCTION_CAST<ModuloFunction>(buffer); |
| 9193 } | 9516 } |
| 9194 | 9517 |
| 9195 #endif | 9518 #endif |
| 9196 | 9519 |
| 9197 | 9520 |
| 9198 #undef __ | 9521 #undef __ |
| 9199 | 9522 |
| 9200 } } // namespace v8::internal | 9523 } } // namespace v8::internal |
| OLD | NEW |