Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: src/x64/codegen-x64.cc

Issue 660095: Merge revision 3813 to 3930 from bleeding_edge to partial snapshots branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/partial_snapshots/
Patch Set: '' Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/codegen-x64.h ('k') | src/x64/disasm-x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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_ = &register_allocator; 288 allocator_ = &register_allocator;
289 ASSERT(frame_ == NULL); 289 ASSERT(frame_ == NULL);
290 frame_ = new VirtualFrame(); 290 frame_ = new VirtualFrame();
(...skipping 18 matching lines...) Expand all
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/x64/codegen-x64.h ('k') | src/x64/disasm-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698