| Index: src/ia32/builtins-ia32.cc
 | 
| ===================================================================
 | 
| --- src/ia32/builtins-ia32.cc	(revision 9531)
 | 
| +++ src/ia32/builtins-ia32.cc	(working copy)
 | 
| @@ -69,7 +69,7 @@
 | 
|  
 | 
|    // JumpToExternalReference expects eax to contain the number of arguments
 | 
|    // including the receiver and the extra arguments.
 | 
| -  __ add(Operand(eax), Immediate(num_extra_args + 1));
 | 
| +  __ add(eax, Immediate(num_extra_args + 1));
 | 
|    __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
 | 
|  }
 | 
|  
 | 
| @@ -80,25 +80,34 @@
 | 
|    //  -- edi: constructor function
 | 
|    // -----------------------------------
 | 
|  
 | 
| -  Label non_function_call;
 | 
| +  Label slow, non_function_call;
 | 
|    // Check that function is not a smi.
 | 
|    __ JumpIfSmi(edi, &non_function_call);
 | 
|    // Check that function is a JSFunction.
 | 
|    __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
 | 
| -  __ j(not_equal, &non_function_call);
 | 
| +  __ j(not_equal, &slow);
 | 
|  
 | 
|    // Jump to the function-specific construct stub.
 | 
|    __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
 | 
|    __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset));
 | 
|    __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize));
 | 
| -  __ jmp(Operand(ebx));
 | 
| +  __ jmp(ebx);
 | 
|  
 | 
|    // edi: called object
 | 
|    // eax: number of arguments
 | 
| +  // ecx: object map
 | 
| +  Label do_call;
 | 
| +  __ bind(&slow);
 | 
| +  __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE);
 | 
| +  __ j(not_equal, &non_function_call);
 | 
| +  __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
 | 
| +  __ jmp(&do_call);
 | 
| +
 | 
|    __ bind(&non_function_call);
 | 
| +  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
 | 
| +  __ bind(&do_call);
 | 
|    // Set expected number of arguments to zero (not changing eax).
 | 
|    __ Set(ebx, Immediate(0));
 | 
| -  __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
 | 
|    Handle<Code> arguments_adaptor =
 | 
|        masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
 | 
|    __ SetCallKind(ecx, CALL_AS_METHOD);
 | 
| @@ -113,265 +122,272 @@
 | 
|    ASSERT(!is_api_function || !count_constructions);
 | 
|  
 | 
|    // Enter a construct frame.
 | 
| -  __ EnterConstructFrame();
 | 
| +  {
 | 
| +    FrameScope scope(masm, StackFrame::CONSTRUCT);
 | 
|  
 | 
| -  // Store a smi-tagged arguments count on the stack.
 | 
| -  __ SmiTag(eax);
 | 
| -  __ push(eax);
 | 
| +    // Store a smi-tagged arguments count on the stack.
 | 
| +    __ SmiTag(eax);
 | 
| +    __ push(eax);
 | 
|  
 | 
| -  // Push the function to invoke on the stack.
 | 
| -  __ push(edi);
 | 
| +    // Push the function to invoke on the stack.
 | 
| +    __ push(edi);
 | 
|  
 | 
| -  // Try to allocate the object without transitioning into C code. If any of the
 | 
| -  // preconditions is not met, the code bails out to the runtime call.
 | 
| -  Label rt_call, allocated;
 | 
| -  if (FLAG_inline_new) {
 | 
| -    Label undo_allocation;
 | 
| +    // Try to allocate the object without transitioning into C code. If any of
 | 
| +    // the preconditions is not met, the code bails out to the runtime call.
 | 
| +    Label rt_call, allocated;
 | 
| +    if (FLAG_inline_new) {
 | 
| +      Label undo_allocation;
 | 
|  #ifdef ENABLE_DEBUGGER_SUPPORT
 | 
| -    ExternalReference debug_step_in_fp =
 | 
| -        ExternalReference::debug_step_in_fp_address(masm->isolate());
 | 
| -    __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
 | 
| -    __ j(not_equal, &rt_call);
 | 
| +      ExternalReference debug_step_in_fp =
 | 
| +          ExternalReference::debug_step_in_fp_address(masm->isolate());
 | 
| +      __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
 | 
| +      __ j(not_equal, &rt_call);
 | 
|  #endif
 | 
|  
 | 
| -    // Verified that the constructor is a JSFunction.
 | 
| -    // Load the initial map and verify that it is in fact a map.
 | 
| -    // edi: constructor
 | 
| -    __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
 | 
| -    // Will both indicate a NULL and a Smi
 | 
| -    __ JumpIfSmi(eax, &rt_call);
 | 
| -    // edi: constructor
 | 
| -    // eax: initial map (if proven valid below)
 | 
| -    __ CmpObjectType(eax, MAP_TYPE, ebx);
 | 
| -    __ j(not_equal, &rt_call);
 | 
| +      // Verified that the constructor is a JSFunction.
 | 
| +      // Load the initial map and verify that it is in fact a map.
 | 
| +      // edi: constructor
 | 
| +      __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
 | 
| +      // Will both indicate a NULL and a Smi
 | 
| +      __ JumpIfSmi(eax, &rt_call);
 | 
| +      // edi: constructor
 | 
| +      // eax: initial map (if proven valid below)
 | 
| +      __ CmpObjectType(eax, MAP_TYPE, ebx);
 | 
| +      __ j(not_equal, &rt_call);
 | 
|  
 | 
| -    // Check that the constructor is not constructing a JSFunction (see comments
 | 
| -    // in Runtime_NewObject in runtime.cc). In which case the initial map's
 | 
| -    // instance type would be JS_FUNCTION_TYPE.
 | 
| -    // edi: constructor
 | 
| -    // eax: initial map
 | 
| -    __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
 | 
| -    __ j(equal, &rt_call);
 | 
| +      // Check that the constructor is not constructing a JSFunction (see
 | 
| +      // comments in Runtime_NewObject in runtime.cc). In which case the
 | 
| +      // initial map's instance type would be JS_FUNCTION_TYPE.
 | 
| +      // edi: constructor
 | 
| +      // eax: initial map
 | 
| +      __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
 | 
| +      __ j(equal, &rt_call);
 | 
|  
 | 
| -    if (count_constructions) {
 | 
| -      Label allocate;
 | 
| -      // Decrease generous allocation count.
 | 
| -      __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
 | 
| -      __ dec_b(FieldOperand(ecx, SharedFunctionInfo::kConstructionCountOffset));
 | 
| -      __ j(not_zero, &allocate);
 | 
| +      if (count_constructions) {
 | 
| +        Label allocate;
 | 
| +        // Decrease generous allocation count.
 | 
| +        __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
 | 
| +        __ dec_b(FieldOperand(ecx,
 | 
| +                              SharedFunctionInfo::kConstructionCountOffset));
 | 
| +        __ j(not_zero, &allocate);
 | 
|  
 | 
| -      __ push(eax);
 | 
| -      __ push(edi);
 | 
| +        __ push(eax);
 | 
| +        __ push(edi);
 | 
|  
 | 
| -      __ push(edi);  // constructor
 | 
| -      // The call will replace the stub, so the countdown is only done once.
 | 
| -      __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
 | 
| +        __ push(edi);  // constructor
 | 
| +        // The call will replace the stub, so the countdown is only done once.
 | 
| +        __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
 | 
|  
 | 
| -      __ pop(edi);
 | 
| -      __ pop(eax);
 | 
| +        __ pop(edi);
 | 
| +        __ pop(eax);
 | 
|  
 | 
| -      __ bind(&allocate);
 | 
| -    }
 | 
| +        __ bind(&allocate);
 | 
| +      }
 | 
|  
 | 
| -    // Now allocate the JSObject on the heap.
 | 
| -    // edi: constructor
 | 
| -    // eax: initial map
 | 
| -    __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
 | 
| -    __ shl(edi, kPointerSizeLog2);
 | 
| -    __ AllocateInNewSpace(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
 | 
| -    // Allocated the JSObject, now initialize the fields.
 | 
| -    // eax: initial map
 | 
| -    // ebx: JSObject
 | 
| -    // edi: start of next object
 | 
| -    __ mov(Operand(ebx, JSObject::kMapOffset), eax);
 | 
| -    Factory* factory = masm->isolate()->factory();
 | 
| -    __ mov(ecx, factory->empty_fixed_array());
 | 
| -    __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
 | 
| -    __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
 | 
| -    // Set extra fields in the newly allocated object.
 | 
| -    // eax: initial map
 | 
| -    // ebx: JSObject
 | 
| -    // edi: start of next object
 | 
| -    { Label loop, entry;
 | 
| -      // To allow for truncation.
 | 
| +      // Now allocate the JSObject on the heap.
 | 
| +      // edi: constructor
 | 
| +      // eax: initial map
 | 
| +      __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
 | 
| +      __ shl(edi, kPointerSizeLog2);
 | 
| +      __ AllocateInNewSpace(
 | 
| +          edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
 | 
| +      // Allocated the JSObject, now initialize the fields.
 | 
| +      // eax: initial map
 | 
| +      // ebx: JSObject
 | 
| +      // edi: start of next object
 | 
| +      __ mov(Operand(ebx, JSObject::kMapOffset), eax);
 | 
| +      Factory* factory = masm->isolate()->factory();
 | 
| +      __ mov(ecx, factory->empty_fixed_array());
 | 
| +      __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
 | 
| +      __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
 | 
| +      // Set extra fields in the newly allocated object.
 | 
| +      // eax: initial map
 | 
| +      // ebx: JSObject
 | 
| +      // edi: start of next object
 | 
| +      __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
 | 
| +      __ mov(edx, factory->undefined_value());
 | 
|        if (count_constructions) {
 | 
| +        __ movzx_b(esi,
 | 
| +                   FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
 | 
| +        __ lea(esi,
 | 
| +               Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize));
 | 
| +        // esi: offset of first field after pre-allocated fields
 | 
| +        if (FLAG_debug_code) {
 | 
| +          __ cmp(esi, edi);
 | 
| +          __ Assert(less_equal,
 | 
| +                    "Unexpected number of pre-allocated property fields.");
 | 
| +        }
 | 
| +        __ InitializeFieldsWithFiller(ecx, esi, edx);
 | 
|          __ mov(edx, factory->one_pointer_filler_map());
 | 
| -      } else {
 | 
| -        __ mov(edx, factory->undefined_value());
 | 
|        }
 | 
| -      __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
 | 
| -      __ jmp(&entry);
 | 
| -      __ bind(&loop);
 | 
| -      __ mov(Operand(ecx, 0), edx);
 | 
| -      __ add(Operand(ecx), Immediate(kPointerSize));
 | 
| -      __ bind(&entry);
 | 
| -      __ cmp(ecx, Operand(edi));
 | 
| -      __ j(less, &loop);
 | 
| -    }
 | 
| +      __ InitializeFieldsWithFiller(ecx, edi, edx);
 | 
|  
 | 
| -    // Add the object tag to make the JSObject real, so that we can continue and
 | 
| -    // jump into the continuation code at any time from now on. Any failures
 | 
| -    // need to undo the allocation, so that the heap is in a consistent state
 | 
| -    // and verifiable.
 | 
| -    // eax: initial map
 | 
| -    // ebx: JSObject
 | 
| -    // edi: start of next object
 | 
| -    __ or_(Operand(ebx), Immediate(kHeapObjectTag));
 | 
| +      // Add the object tag to make the JSObject real, so that we can continue
 | 
| +      // and jump into the continuation code at any time from now on. Any
 | 
| +      // failures need to undo the allocation, so that the heap is in a
 | 
| +      // consistent state and verifiable.
 | 
| +      // eax: initial map
 | 
| +      // ebx: JSObject
 | 
| +      // edi: start of next object
 | 
| +      __ or_(ebx, Immediate(kHeapObjectTag));
 | 
|  
 | 
| -    // Check if a non-empty properties array is needed.
 | 
| -    // Allocate and initialize a FixedArray if it is.
 | 
| -    // eax: initial map
 | 
| -    // ebx: JSObject
 | 
| -    // edi: start of next object
 | 
| -    // Calculate the total number of properties described by the map.
 | 
| -    __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
 | 
| -    __ movzx_b(ecx, FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
 | 
| -    __ add(edx, Operand(ecx));
 | 
| -    // Calculate unused properties past the end of the in-object properties.
 | 
| -    __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
 | 
| -    __ sub(edx, Operand(ecx));
 | 
| -    // Done if no extra properties are to be allocated.
 | 
| -    __ j(zero, &allocated);
 | 
| -    __ Assert(positive, "Property allocation count failed.");
 | 
| +      // Check if a non-empty properties array is needed.
 | 
| +      // Allocate and initialize a FixedArray if it is.
 | 
| +      // eax: initial map
 | 
| +      // ebx: JSObject
 | 
| +      // edi: start of next object
 | 
| +      // Calculate the total number of properties described by the map.
 | 
| +      __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
 | 
| +      __ movzx_b(ecx,
 | 
| +                 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
 | 
| +      __ add(edx, ecx);
 | 
| +      // Calculate unused properties past the end of the in-object properties.
 | 
| +      __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
 | 
| +      __ sub(edx, ecx);
 | 
| +      // Done if no extra properties are to be allocated.
 | 
| +      __ j(zero, &allocated);
 | 
| +      __ Assert(positive, "Property allocation count failed.");
 | 
|  
 | 
| -    // Scale the number of elements by pointer size and add the header for
 | 
| -    // FixedArrays to the start of the next object calculation from above.
 | 
| -    // ebx: JSObject
 | 
| -    // edi: start of next object (will be start of FixedArray)
 | 
| -    // edx: number of elements in properties array
 | 
| -    __ AllocateInNewSpace(FixedArray::kHeaderSize,
 | 
| -                          times_pointer_size,
 | 
| -                          edx,
 | 
| -                          edi,
 | 
| -                          ecx,
 | 
| -                          no_reg,
 | 
| -                          &undo_allocation,
 | 
| -                          RESULT_CONTAINS_TOP);
 | 
| +      // Scale the number of elements by pointer size and add the header for
 | 
| +      // FixedArrays to the start of the next object calculation from above.
 | 
| +      // ebx: JSObject
 | 
| +      // edi: start of next object (will be start of FixedArray)
 | 
| +      // edx: number of elements in properties array
 | 
| +      __ AllocateInNewSpace(FixedArray::kHeaderSize,
 | 
| +                            times_pointer_size,
 | 
| +                            edx,
 | 
| +                            edi,
 | 
| +                            ecx,
 | 
| +                            no_reg,
 | 
| +                            &undo_allocation,
 | 
| +                            RESULT_CONTAINS_TOP);
 | 
|  
 | 
| -    // Initialize the FixedArray.
 | 
| -    // ebx: JSObject
 | 
| -    // edi: FixedArray
 | 
| -    // edx: number of elements
 | 
| -    // ecx: start of next object
 | 
| -    __ mov(eax, factory->fixed_array_map());
 | 
| -    __ mov(Operand(edi, FixedArray::kMapOffset), eax);  // setup the map
 | 
| -    __ SmiTag(edx);
 | 
| -    __ mov(Operand(edi, FixedArray::kLengthOffset), edx);  // and length
 | 
| +      // Initialize the FixedArray.
 | 
| +      // ebx: JSObject
 | 
| +      // edi: FixedArray
 | 
| +      // edx: number of elements
 | 
| +      // ecx: start of next object
 | 
| +      __ mov(eax, factory->fixed_array_map());
 | 
| +      __ mov(Operand(edi, FixedArray::kMapOffset), eax);  // setup the map
 | 
| +      __ SmiTag(edx);
 | 
| +      __ mov(Operand(edi, FixedArray::kLengthOffset), edx);  // and length
 | 
|  
 | 
| -    // Initialize the fields to undefined.
 | 
| -    // ebx: JSObject
 | 
| -    // edi: FixedArray
 | 
| -    // ecx: start of next object
 | 
| -    { Label loop, entry;
 | 
| -      __ mov(edx, factory->undefined_value());
 | 
| -      __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
 | 
| -      __ jmp(&entry);
 | 
| -      __ bind(&loop);
 | 
| -      __ mov(Operand(eax, 0), edx);
 | 
| -      __ add(Operand(eax), Immediate(kPointerSize));
 | 
| -      __ bind(&entry);
 | 
| -      __ cmp(eax, Operand(ecx));
 | 
| -      __ j(below, &loop);
 | 
| -    }
 | 
| +      // Initialize the fields to undefined.
 | 
| +      // ebx: JSObject
 | 
| +      // edi: FixedArray
 | 
| +      // ecx: start of next object
 | 
| +      { Label loop, entry;
 | 
| +        __ mov(edx, factory->undefined_value());
 | 
| +        __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
 | 
| +        __ jmp(&entry);
 | 
| +        __ bind(&loop);
 | 
| +        __ mov(Operand(eax, 0), edx);
 | 
| +        __ add(eax, Immediate(kPointerSize));
 | 
| +        __ bind(&entry);
 | 
| +        __ cmp(eax, ecx);
 | 
| +        __ j(below, &loop);
 | 
| +      }
 | 
|  
 | 
| -    // Store the initialized FixedArray into the properties field of
 | 
| -    // the JSObject
 | 
| -    // ebx: JSObject
 | 
| -    // edi: FixedArray
 | 
| -    __ or_(Operand(edi), Immediate(kHeapObjectTag));  // add the heap tag
 | 
| -    __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
 | 
| +      // Store the initialized FixedArray into the properties field of
 | 
| +      // the JSObject
 | 
| +      // ebx: JSObject
 | 
| +      // edi: FixedArray
 | 
| +      __ or_(edi, Immediate(kHeapObjectTag));  // add the heap tag
 | 
| +      __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
 | 
|  
 | 
|  
 | 
| -    // Continue with JSObject being successfully allocated
 | 
| -    // ebx: JSObject
 | 
| -    __ jmp(&allocated);
 | 
| +      // Continue with JSObject being successfully allocated
 | 
| +      // ebx: JSObject
 | 
| +      __ jmp(&allocated);
 | 
|  
 | 
| -    // Undo the setting of the new top so that the heap is verifiable. For
 | 
| -    // example, the map's unused properties potentially do not match the
 | 
| -    // allocated objects unused properties.
 | 
| -    // ebx: JSObject (previous new top)
 | 
| -    __ bind(&undo_allocation);
 | 
| -    __ UndoAllocationInNewSpace(ebx);
 | 
| -  }
 | 
| +      // Undo the setting of the new top so that the heap is verifiable. For
 | 
| +      // example, the map's unused properties potentially do not match the
 | 
| +      // allocated objects unused properties.
 | 
| +      // ebx: JSObject (previous new top)
 | 
| +      __ bind(&undo_allocation);
 | 
| +      __ UndoAllocationInNewSpace(ebx);
 | 
| +    }
 | 
|  
 | 
| -  // Allocate the new receiver object using the runtime call.
 | 
| -  __ bind(&rt_call);
 | 
| -  // Must restore edi (constructor) before calling runtime.
 | 
| -  __ mov(edi, Operand(esp, 0));
 | 
| -  // edi: function (constructor)
 | 
| -  __ push(edi);
 | 
| -  __ CallRuntime(Runtime::kNewObject, 1);
 | 
| -  __ mov(ebx, Operand(eax));  // store result in ebx
 | 
| +    // Allocate the new receiver object using the runtime call.
 | 
| +    __ bind(&rt_call);
 | 
| +    // Must restore edi (constructor) before calling runtime.
 | 
| +    __ mov(edi, Operand(esp, 0));
 | 
| +    // edi: function (constructor)
 | 
| +    __ push(edi);
 | 
| +    __ CallRuntime(Runtime::kNewObject, 1);
 | 
| +    __ mov(ebx, eax);  // store result in ebx
 | 
|  
 | 
| -  // New object allocated.
 | 
| -  // ebx: newly allocated object
 | 
| -  __ bind(&allocated);
 | 
| -  // Retrieve the function from the stack.
 | 
| -  __ pop(edi);
 | 
| +    // New object allocated.
 | 
| +    // ebx: newly allocated object
 | 
| +    __ bind(&allocated);
 | 
| +    // Retrieve the function from the stack.
 | 
| +    __ pop(edi);
 | 
|  
 | 
| -  // Retrieve smi-tagged arguments count from the stack.
 | 
| -  __ mov(eax, Operand(esp, 0));
 | 
| -  __ SmiUntag(eax);
 | 
| +    // Retrieve smi-tagged arguments count from the stack.
 | 
| +    __ mov(eax, Operand(esp, 0));
 | 
| +    __ SmiUntag(eax);
 | 
|  
 | 
| -  // Push the allocated receiver to the stack. We need two copies
 | 
| -  // because we may have to return the original one and the calling
 | 
| -  // conventions dictate that the called function pops the receiver.
 | 
| -  __ push(ebx);
 | 
| -  __ push(ebx);
 | 
| +    // Push the allocated receiver to the stack. We need two copies
 | 
| +    // because we may have to return the original one and the calling
 | 
| +    // conventions dictate that the called function pops the receiver.
 | 
| +    __ push(ebx);
 | 
| +    __ push(ebx);
 | 
|  
 | 
| -  // Setup pointer to last argument.
 | 
| -  __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
 | 
| +    // Setup pointer to last argument.
 | 
| +    __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
 | 
|  
 | 
| -  // Copy arguments and receiver to the expression stack.
 | 
| -  Label loop, entry;
 | 
| -  __ mov(ecx, Operand(eax));
 | 
| -  __ jmp(&entry);
 | 
| -  __ bind(&loop);
 | 
| -  __ push(Operand(ebx, ecx, times_4, 0));
 | 
| -  __ bind(&entry);
 | 
| -  __ dec(ecx);
 | 
| -  __ j(greater_equal, &loop);
 | 
| +    // Copy arguments and receiver to the expression stack.
 | 
| +    Label loop, entry;
 | 
| +    __ mov(ecx, eax);
 | 
| +    __ jmp(&entry);
 | 
| +    __ bind(&loop);
 | 
| +    __ push(Operand(ebx, ecx, times_4, 0));
 | 
| +    __ bind(&entry);
 | 
| +    __ dec(ecx);
 | 
| +    __ j(greater_equal, &loop);
 | 
|  
 | 
| -  // Call the function.
 | 
| -  if (is_api_function) {
 | 
| -    __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
 | 
| -    Handle<Code> code =
 | 
| -        masm->isolate()->builtins()->HandleApiCallConstruct();
 | 
| -    ParameterCount expected(0);
 | 
| -    __ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
 | 
| -                  CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
 | 
| -  } else {
 | 
| -    ParameterCount actual(eax);
 | 
| -    __ InvokeFunction(edi, actual, CALL_FUNCTION,
 | 
| -                      NullCallWrapper(), CALL_AS_METHOD);
 | 
| -  }
 | 
| +    // Call the function.
 | 
| +    if (is_api_function) {
 | 
| +      __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
 | 
| +      Handle<Code> code =
 | 
| +          masm->isolate()->builtins()->HandleApiCallConstruct();
 | 
| +      ParameterCount expected(0);
 | 
| +      __ InvokeCode(code, expected, expected, RelocInfo::CODE_TARGET,
 | 
| +                    CALL_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
 | 
| +    } else {
 | 
| +      ParameterCount actual(eax);
 | 
| +      __ InvokeFunction(edi, actual, CALL_FUNCTION,
 | 
| +                        NullCallWrapper(), CALL_AS_METHOD);
 | 
| +    }
 | 
|  
 | 
| -  // Restore context from the frame.
 | 
| -  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
 | 
| +    // Restore context from the frame.
 | 
| +    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
 | 
|  
 | 
| -  // If the result is an object (in the ECMA sense), we should get rid
 | 
| -  // of the receiver and use the result; see ECMA-262 section 13.2.2-7
 | 
| -  // on page 74.
 | 
| -  Label use_receiver, exit;
 | 
| +    // If the result is an object (in the ECMA sense), we should get rid
 | 
| +    // of the receiver and use the result; see ECMA-262 section 13.2.2-7
 | 
| +    // on page 74.
 | 
| +    Label use_receiver, exit;
 | 
|  
 | 
| -  // If the result is a smi, it is *not* an object in the ECMA sense.
 | 
| -  __ JumpIfSmi(eax, &use_receiver);
 | 
| +    // If the result is a smi, it is *not* an object in the ECMA sense.
 | 
| +    __ JumpIfSmi(eax, &use_receiver);
 | 
|  
 | 
| -  // If the type of the result (stored in its map) is less than
 | 
| -  // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
 | 
| -  __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
 | 
| -  __ j(above_equal, &exit);
 | 
| +    // If the type of the result (stored in its map) is less than
 | 
| +    // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
 | 
| +    __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
 | 
| +    __ j(above_equal, &exit);
 | 
|  
 | 
| -  // Throw away the result of the constructor invocation and use the
 | 
| -  // on-stack receiver as the result.
 | 
| -  __ bind(&use_receiver);
 | 
| -  __ mov(eax, Operand(esp, 0));
 | 
| +    // Throw away the result of the constructor invocation and use the
 | 
| +    // on-stack receiver as the result.
 | 
| +    __ bind(&use_receiver);
 | 
| +    __ mov(eax, Operand(esp, 0));
 | 
|  
 | 
| -  // Restore the arguments count and leave the construct frame.
 | 
| -  __ bind(&exit);
 | 
| -  __ mov(ebx, Operand(esp, kPointerSize));  // get arguments count
 | 
| -  __ LeaveConstructFrame();
 | 
| +    // Restore the arguments count and leave the construct frame.
 | 
| +    __ bind(&exit);
 | 
| +    __ mov(ebx, Operand(esp, kPointerSize));  // Get arguments count.
 | 
|  
 | 
| +    // Leave construct frame.
 | 
| +  }
 | 
| +
 | 
|    // Remove caller arguments from the stack and return.
 | 
|    STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
 | 
|    __ pop(ecx);
 | 
| @@ -399,57 +415,58 @@
 | 
|  
 | 
|  static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
 | 
|                                               bool is_construct) {
 | 
| -  // Clear the context before we push it when entering the JS frame.
 | 
| +  // Clear the context before we push it when entering the internal frame.
 | 
|    __ Set(esi, Immediate(0));
 | 
|  
 | 
| -  // Enter an internal frame.
 | 
| -  __ EnterInternalFrame();
 | 
| +  {
 | 
| +    FrameScope scope(masm, StackFrame::INTERNAL);
 | 
|  
 | 
| -  // Load the previous frame pointer (ebx) to access C arguments
 | 
| -  __ mov(ebx, Operand(ebp, 0));
 | 
| +    // Load the previous frame pointer (ebx) to access C arguments
 | 
| +    __ mov(ebx, Operand(ebp, 0));
 | 
|  
 | 
| -  // Get the function from the frame and setup the context.
 | 
| -  __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
 | 
| -  __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
 | 
| +    // Get the function from the frame and setup the context.
 | 
| +    __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset));
 | 
| +    __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset));
 | 
|  
 | 
| -  // Push the function and the receiver onto the stack.
 | 
| -  __ push(ecx);
 | 
| -  __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
 | 
| +    // Push the function and the receiver onto the stack.
 | 
| +    __ push(ecx);
 | 
| +    __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset));
 | 
|  
 | 
| -  // Load the number of arguments and setup pointer to the arguments.
 | 
| -  __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
 | 
| -  __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
 | 
| +    // Load the number of arguments and setup pointer to the arguments.
 | 
| +    __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset));
 | 
| +    __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset));
 | 
|  
 | 
| -  // Copy arguments to the stack in a loop.
 | 
| -  Label loop, entry;
 | 
| -  __ Set(ecx, Immediate(0));
 | 
| -  __ jmp(&entry);
 | 
| -  __ bind(&loop);
 | 
| -  __ mov(edx, Operand(ebx, ecx, times_4, 0));  // push parameter from argv
 | 
| -  __ push(Operand(edx, 0));  // dereference handle
 | 
| -  __ inc(Operand(ecx));
 | 
| -  __ bind(&entry);
 | 
| -  __ cmp(ecx, Operand(eax));
 | 
| -  __ j(not_equal, &loop);
 | 
| +    // Copy arguments to the stack in a loop.
 | 
| +    Label loop, entry;
 | 
| +    __ Set(ecx, Immediate(0));
 | 
| +    __ jmp(&entry);
 | 
| +    __ bind(&loop);
 | 
| +    __ mov(edx, Operand(ebx, ecx, times_4, 0));  // push parameter from argv
 | 
| +    __ push(Operand(edx, 0));  // dereference handle
 | 
| +    __ inc(ecx);
 | 
| +    __ bind(&entry);
 | 
| +    __ cmp(ecx, eax);
 | 
| +    __ j(not_equal, &loop);
 | 
|  
 | 
| -  // Get the function from the stack and call it.
 | 
| -  __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize));  // +1 ~ receiver
 | 
| +    // Get the function from the stack and call it.
 | 
| +    // kPointerSize for the receiver.
 | 
| +    __ mov(edi, Operand(esp, eax, times_4, kPointerSize));
 | 
|  
 | 
| -  // Invoke the code.
 | 
| -  if (is_construct) {
 | 
| -    __ call(masm->isolate()->builtins()->JSConstructCall(),
 | 
| -            RelocInfo::CODE_TARGET);
 | 
| -  } else {
 | 
| -    ParameterCount actual(eax);
 | 
| -    __ InvokeFunction(edi, actual, CALL_FUNCTION,
 | 
| -                      NullCallWrapper(), CALL_AS_METHOD);
 | 
| +    // Invoke the code.
 | 
| +    if (is_construct) {
 | 
| +      __ call(masm->isolate()->builtins()->JSConstructCall(),
 | 
| +              RelocInfo::CODE_TARGET);
 | 
| +    } else {
 | 
| +      ParameterCount actual(eax);
 | 
| +      __ InvokeFunction(edi, actual, CALL_FUNCTION,
 | 
| +                        NullCallWrapper(), CALL_AS_METHOD);
 | 
| +    }
 | 
| +
 | 
| +    // Exit the internal frame. Notice that this also removes the empty.
 | 
| +    // context and the function left on the stack by the code
 | 
| +    // invocation.
 | 
|    }
 | 
| -
 | 
| -  // Exit the JS frame. Notice that this also removes the empty
 | 
| -  // context and the function left on the stack by the code
 | 
| -  // invocation.
 | 
| -  __ LeaveInternalFrame();
 | 
| -  __ ret(1 * kPointerSize);  // remove receiver
 | 
| +  __ ret(kPointerSize);  // Remove receiver.
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -464,68 +481,68 @@
 | 
|  
 | 
|  
 | 
|  void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
 | 
| -  // Enter an internal frame.
 | 
| -  __ EnterInternalFrame();
 | 
| +  {
 | 
| +    FrameScope scope(masm, StackFrame::INTERNAL);
 | 
|  
 | 
| -  // Push a copy of the function.
 | 
| -  __ push(edi);
 | 
| -  // Push call kind information.
 | 
| -  __ push(ecx);
 | 
| +    // Push a copy of the function.
 | 
| +    __ push(edi);
 | 
| +    // Push call kind information.
 | 
| +    __ push(ecx);
 | 
|  
 | 
| -  __ push(edi);  // Function is also the parameter to the runtime call.
 | 
| -  __ CallRuntime(Runtime::kLazyCompile, 1);
 | 
| +    __ push(edi);  // Function is also the parameter to the runtime call.
 | 
| +    __ CallRuntime(Runtime::kLazyCompile, 1);
 | 
|  
 | 
| -  // Restore call kind information.
 | 
| -  __ pop(ecx);
 | 
| -  // Restore receiver.
 | 
| -  __ pop(edi);
 | 
| +    // Restore call kind information.
 | 
| +    __ pop(ecx);
 | 
| +    // Restore receiver.
 | 
| +    __ pop(edi);
 | 
|  
 | 
| -  // Tear down temporary frame.
 | 
| -  __ LeaveInternalFrame();
 | 
| +    // Tear down internal frame.
 | 
| +  }
 | 
|  
 | 
|    // Do a tail-call of the compiled function.
 | 
|    __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
 | 
| -  __ jmp(Operand(eax));
 | 
| +  __ jmp(eax);
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
 | 
| -  // Enter an internal frame.
 | 
| -  __ EnterInternalFrame();
 | 
| +  {
 | 
| +    FrameScope scope(masm, StackFrame::INTERNAL);
 | 
|  
 | 
| -  // Push a copy of the function onto the stack.
 | 
| -  __ push(edi);
 | 
| -  // Push call kind information.
 | 
| -  __ push(ecx);
 | 
| +    // Push a copy of the function onto the stack.
 | 
| +    __ push(edi);
 | 
| +    // Push call kind information.
 | 
| +    __ push(ecx);
 | 
|  
 | 
| -  __ push(edi);  // Function is also the parameter to the runtime call.
 | 
| -  __ CallRuntime(Runtime::kLazyRecompile, 1);
 | 
| +    __ push(edi);  // Function is also the parameter to the runtime call.
 | 
| +    __ CallRuntime(Runtime::kLazyRecompile, 1);
 | 
|  
 | 
| -  // Restore call kind information.
 | 
| -  __ pop(ecx);
 | 
| -  // Restore receiver.
 | 
| -  __ pop(edi);
 | 
| +    // Restore call kind information.
 | 
| +    __ pop(ecx);
 | 
| +    // Restore receiver.
 | 
| +    __ pop(edi);
 | 
|  
 | 
| -  // Tear down temporary frame.
 | 
| -  __ LeaveInternalFrame();
 | 
| +    // Tear down internal frame.
 | 
| +  }
 | 
|  
 | 
|    // Do a tail-call of the compiled function.
 | 
|    __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
 | 
| -  __ jmp(Operand(eax));
 | 
| +  __ jmp(eax);
 | 
|  }
 | 
|  
 | 
|  
 | 
|  static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
 | 
|                                               Deoptimizer::BailoutType type) {
 | 
| -  // Enter an internal frame.
 | 
| -  __ EnterInternalFrame();
 | 
| +  {
 | 
| +    FrameScope scope(masm, StackFrame::INTERNAL);
 | 
|  
 | 
| -  // Pass the function and deoptimization type to the runtime system.
 | 
| -  __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
 | 
| -  __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
 | 
| +    // Pass the function and deoptimization type to the runtime system.
 | 
| +    __ push(Immediate(Smi::FromInt(static_cast<int>(type))));
 | 
| +    __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
 | 
|  
 | 
| -  // Tear down temporary frame.
 | 
| -  __ LeaveInternalFrame();
 | 
| +    // Tear down internal frame.
 | 
| +  }
 | 
|  
 | 
|    // Get the full codegen state from the stack and untag it.
 | 
|    __ mov(ecx, Operand(esp, 1 * kPointerSize));
 | 
| @@ -566,9 +583,10 @@
 | 
|    // the registers without worrying about which of them contain
 | 
|    // pointers. This seems a bit fragile.
 | 
|    __ pushad();
 | 
| -  __ EnterInternalFrame();
 | 
| -  __ CallRuntime(Runtime::kNotifyOSR, 0);
 | 
| -  __ LeaveInternalFrame();
 | 
| +  {
 | 
| +    FrameScope scope(masm, StackFrame::INTERNAL);
 | 
| +    __ CallRuntime(Runtime::kNotifyOSR, 0);
 | 
| +  }
 | 
|    __ popad();
 | 
|    __ ret(0);
 | 
|  }
 | 
| @@ -579,7 +597,7 @@
 | 
|  
 | 
|    // 1. Make sure we have at least one argument.
 | 
|    { Label done;
 | 
| -    __ test(eax, Operand(eax));
 | 
| +    __ test(eax, eax);
 | 
|      __ j(not_zero, &done);
 | 
|      __ pop(ebx);
 | 
|      __ push(Immediate(factory->undefined_value()));
 | 
| @@ -631,18 +649,21 @@
 | 
|      __ j(above_equal, &shift_arguments);
 | 
|  
 | 
|      __ bind(&convert_to_object);
 | 
| -    __ EnterInternalFrame();  // In order to preserve argument count.
 | 
| -    __ SmiTag(eax);
 | 
| -    __ push(eax);
 | 
|  
 | 
| -    __ push(ebx);
 | 
| -    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
 | 
| -    __ mov(ebx, eax);
 | 
| -    __ Set(edx, Immediate(0));  // restore
 | 
| +    { // In order to preserve argument count.
 | 
| +      FrameScope scope(masm, StackFrame::INTERNAL);
 | 
| +      __ SmiTag(eax);
 | 
| +      __ push(eax);
 | 
|  
 | 
| -    __ pop(eax);
 | 
| -    __ SmiUntag(eax);
 | 
| -    __ LeaveInternalFrame();
 | 
| +      __ push(ebx);
 | 
| +      __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
 | 
| +      __ mov(ebx, eax);
 | 
| +      __ Set(edx, Immediate(0));  // restore
 | 
| +
 | 
| +      __ pop(eax);
 | 
| +      __ SmiUntag(eax);
 | 
| +    }
 | 
| +
 | 
|      // Restore the function to edi.
 | 
|      __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize));
 | 
|      __ jmp(&patch_receiver);
 | 
| @@ -695,11 +716,11 @@
 | 
|    // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
 | 
|    //     or a function proxy via CALL_FUNCTION_PROXY.
 | 
|    { Label function, non_proxy;
 | 
| -    __ test(edx, Operand(edx));
 | 
| +    __ test(edx, edx);
 | 
|      __ j(zero, &function);
 | 
|      __ Set(ebx, Immediate(0));
 | 
|      __ SetCallKind(ecx, CALL_AS_METHOD);
 | 
| -    __ cmp(Operand(edx), Immediate(1));
 | 
| +    __ cmp(edx, Immediate(1));
 | 
|      __ j(not_equal, &non_proxy);
 | 
|  
 | 
|      __ pop(edx);   // return address
 | 
| @@ -726,13 +747,13 @@
 | 
|    __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
 | 
|    __ SmiUntag(ebx);
 | 
|    __ SetCallKind(ecx, CALL_AS_METHOD);
 | 
| -  __ cmp(eax, Operand(ebx));
 | 
| +  __ cmp(eax, ebx);
 | 
|    __ j(not_equal,
 | 
|         masm->isolate()->builtins()->ArgumentsAdaptorTrampoline());
 | 
|  
 | 
|    ParameterCount expected(0);
 | 
| -  __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION,
 | 
| -                NullCallWrapper(), CALL_AS_METHOD);
 | 
| +  __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper(),
 | 
| +                CALL_AS_METHOD);
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -740,155 +761,156 @@
 | 
|    static const int kArgumentsOffset = 2 * kPointerSize;
 | 
|    static const int kReceiverOffset = 3 * kPointerSize;
 | 
|    static const int kFunctionOffset = 4 * kPointerSize;
 | 
| +  {
 | 
| +    FrameScope frame_scope(masm, StackFrame::INTERNAL);
 | 
|  
 | 
| -  __ EnterInternalFrame();
 | 
| +    __ push(Operand(ebp, kFunctionOffset));  // push this
 | 
| +    __ push(Operand(ebp, kArgumentsOffset));  // push arguments
 | 
| +    __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
 | 
|  
 | 
| -  __ push(Operand(ebp, kFunctionOffset));  // push this
 | 
| -  __ push(Operand(ebp, kArgumentsOffset));  // push arguments
 | 
| -  __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
 | 
| +    // Check the stack for overflow. We are not trying to catch
 | 
| +    // interruptions (e.g. debug break and preemption) here, so the "real stack
 | 
| +    // limit" is checked.
 | 
| +    Label okay;
 | 
| +    ExternalReference real_stack_limit =
 | 
| +        ExternalReference::address_of_real_stack_limit(masm->isolate());
 | 
| +    __ mov(edi, Operand::StaticVariable(real_stack_limit));
 | 
| +    // Make ecx the space we have left. The stack might already be overflowed
 | 
| +    // here which will cause ecx to become negative.
 | 
| +    __ mov(ecx, esp);
 | 
| +    __ sub(ecx, edi);
 | 
| +    // Make edx the space we need for the array when it is unrolled onto the
 | 
| +    // stack.
 | 
| +    __ mov(edx, eax);
 | 
| +    __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
 | 
| +    // Check if the arguments will overflow the stack.
 | 
| +    __ cmp(ecx, edx);
 | 
| +    __ j(greater, &okay);  // Signed comparison.
 | 
|  
 | 
| -  // Check the stack for overflow. We are not trying to catch
 | 
| -  // interruptions (e.g. debug break and preemption) here, so the "real stack
 | 
| -  // limit" is checked.
 | 
| -  Label okay;
 | 
| -  ExternalReference real_stack_limit =
 | 
| -      ExternalReference::address_of_real_stack_limit(masm->isolate());
 | 
| -  __ mov(edi, Operand::StaticVariable(real_stack_limit));
 | 
| -  // Make ecx the space we have left. The stack might already be overflowed
 | 
| -  // here which will cause ecx to become negative.
 | 
| -  __ mov(ecx, Operand(esp));
 | 
| -  __ sub(ecx, Operand(edi));
 | 
| -  // Make edx the space we need for the array when it is unrolled onto the
 | 
| -  // stack.
 | 
| -  __ mov(edx, Operand(eax));
 | 
| -  __ shl(edx, kPointerSizeLog2 - kSmiTagSize);
 | 
| -  // Check if the arguments will overflow the stack.
 | 
| -  __ cmp(ecx, Operand(edx));
 | 
| -  __ j(greater, &okay);  // Signed comparison.
 | 
| +    // Out of stack space.
 | 
| +    __ push(Operand(ebp, 4 * kPointerSize));  // push this
 | 
| +    __ push(eax);
 | 
| +    __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
 | 
| +    __ bind(&okay);
 | 
| +    // End of stack check.
 | 
|  
 | 
| -  // Out of stack space.
 | 
| -  __ push(Operand(ebp, 4 * kPointerSize));  // push this
 | 
| -  __ push(eax);
 | 
| -  __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION);
 | 
| -  __ bind(&okay);
 | 
| -  // End of stack check.
 | 
| +    // Push current index and limit.
 | 
| +    const int kLimitOffset =
 | 
| +        StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
 | 
| +    const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
 | 
| +    __ push(eax);  // limit
 | 
| +    __ push(Immediate(0));  // index
 | 
|  
 | 
| -  // Push current index and limit.
 | 
| -  const int kLimitOffset =
 | 
| -      StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize;
 | 
| -  const int kIndexOffset = kLimitOffset - 1 * kPointerSize;
 | 
| -  __ push(eax);  // limit
 | 
| -  __ push(Immediate(0));  // index
 | 
| +    // Get the receiver.
 | 
| +    __ mov(ebx, Operand(ebp, kReceiverOffset));
 | 
|  
 | 
| -  // Get the receiver.
 | 
| -  __ mov(ebx, Operand(ebp, kReceiverOffset));
 | 
| +    // Check that the function is a JS function (otherwise it must be a proxy).
 | 
| +    Label push_receiver;
 | 
| +    __ mov(edi, Operand(ebp, kFunctionOffset));
 | 
| +    __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
 | 
| +    __ j(not_equal, &push_receiver);
 | 
|  
 | 
| -  // Check that the function is a JS function (otherwise it must be a proxy).
 | 
| -  Label push_receiver;
 | 
| -  __ mov(edi, Operand(ebp, kFunctionOffset));
 | 
| -  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
 | 
| -  __ j(not_equal, &push_receiver);
 | 
| +    // Change context eagerly to get the right global object if necessary.
 | 
| +    __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
 | 
|  
 | 
| -  // Change context eagerly to get the right global object if necessary.
 | 
| -  __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
 | 
| +    // Compute the receiver.
 | 
| +    // Do not transform the receiver for strict mode functions.
 | 
| +    Label call_to_object, use_global_receiver;
 | 
| +    __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
 | 
| +    __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
 | 
| +              1 << SharedFunctionInfo::kStrictModeBitWithinByte);
 | 
| +    __ j(not_equal, &push_receiver);
 | 
|  
 | 
| -  // Compute the receiver.
 | 
| -  // Do not transform the receiver for strict mode functions.
 | 
| -  Label call_to_object, use_global_receiver;
 | 
| -  __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
 | 
| -  __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset),
 | 
| -            1 << SharedFunctionInfo::kStrictModeBitWithinByte);
 | 
| -  __ j(not_equal, &push_receiver);
 | 
| +    Factory* factory = masm->isolate()->factory();
 | 
|  
 | 
| -  Factory* factory = masm->isolate()->factory();
 | 
| +    // Do not transform the receiver for natives (shared already in ecx).
 | 
| +    __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
 | 
| +              1 << SharedFunctionInfo::kNativeBitWithinByte);
 | 
| +    __ j(not_equal, &push_receiver);
 | 
|  
 | 
| -  // Do not transform the receiver for natives (shared already in ecx).
 | 
| -  __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset),
 | 
| -            1 << SharedFunctionInfo::kNativeBitWithinByte);
 | 
| -  __ j(not_equal, &push_receiver);
 | 
| +    // Compute the receiver in non-strict mode.
 | 
| +    // Call ToObject on the receiver if it is not an object, or use the
 | 
| +    // global object if it is null or undefined.
 | 
| +    __ JumpIfSmi(ebx, &call_to_object);
 | 
| +    __ cmp(ebx, factory->null_value());
 | 
| +    __ j(equal, &use_global_receiver);
 | 
| +    __ cmp(ebx, factory->undefined_value());
 | 
| +    __ j(equal, &use_global_receiver);
 | 
| +    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
 | 
| +    __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
 | 
| +    __ j(above_equal, &push_receiver);
 | 
|  
 | 
| -  // Compute the receiver in non-strict mode.
 | 
| -  // Call ToObject on the receiver if it is not an object, or use the
 | 
| -  // global object if it is null or undefined.
 | 
| -  __ JumpIfSmi(ebx, &call_to_object);
 | 
| -  __ cmp(ebx, factory->null_value());
 | 
| -  __ j(equal, &use_global_receiver);
 | 
| -  __ cmp(ebx, factory->undefined_value());
 | 
| -  __ j(equal, &use_global_receiver);
 | 
| -  STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
 | 
| -  __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx);
 | 
| -  __ j(above_equal, &push_receiver);
 | 
| +    __ bind(&call_to_object);
 | 
| +    __ push(ebx);
 | 
| +    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
 | 
| +    __ mov(ebx, eax);
 | 
| +    __ jmp(&push_receiver);
 | 
|  
 | 
| -  __ bind(&call_to_object);
 | 
| -  __ push(ebx);
 | 
| -  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
 | 
| -  __ mov(ebx, Operand(eax));
 | 
| -  __ jmp(&push_receiver);
 | 
| +    // Use the current global receiver object as the receiver.
 | 
| +    __ bind(&use_global_receiver);
 | 
| +    const int kGlobalOffset =
 | 
| +        Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
 | 
| +    __ mov(ebx, FieldOperand(esi, kGlobalOffset));
 | 
| +    __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
 | 
| +    __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
 | 
| +    __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
 | 
|  
 | 
| -  // Use the current global receiver object as the receiver.
 | 
| -  __ bind(&use_global_receiver);
 | 
| -  const int kGlobalOffset =
 | 
| -      Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
 | 
| -  __ mov(ebx, FieldOperand(esi, kGlobalOffset));
 | 
| -  __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset));
 | 
| -  __ mov(ebx, FieldOperand(ebx, kGlobalOffset));
 | 
| -  __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
 | 
| +    // Push the receiver.
 | 
| +    __ bind(&push_receiver);
 | 
| +    __ push(ebx);
 | 
|  
 | 
| -  // Push the receiver.
 | 
| -  __ bind(&push_receiver);
 | 
| -  __ push(ebx);
 | 
| +    // Copy all arguments from the array to the stack.
 | 
| +    Label entry, loop;
 | 
| +    __ mov(eax, Operand(ebp, kIndexOffset));
 | 
| +    __ jmp(&entry);
 | 
| +    __ bind(&loop);
 | 
| +    __ mov(edx, Operand(ebp, kArgumentsOffset));  // load arguments
 | 
|  
 | 
| -  // Copy all arguments from the array to the stack.
 | 
| -  Label entry, loop;
 | 
| -  __ mov(eax, Operand(ebp, kIndexOffset));
 | 
| -  __ jmp(&entry);
 | 
| -  __ bind(&loop);
 | 
| -  __ mov(edx, Operand(ebp, kArgumentsOffset));  // load arguments
 | 
| +    // Use inline caching to speed up access to arguments.
 | 
| +    Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
 | 
| +    __ call(ic, RelocInfo::CODE_TARGET);
 | 
| +    // It is important that we do not have a test instruction after the
 | 
| +    // call.  A test instruction after the call is used to indicate that
 | 
| +    // we have generated an inline version of the keyed load.  In this
 | 
| +    // case, we know that we are not generating a test instruction next.
 | 
|  
 | 
| -  // Use inline caching to speed up access to arguments.
 | 
| -  Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Initialize();
 | 
| -  __ call(ic, RelocInfo::CODE_TARGET);
 | 
| -  // It is important that we do not have a test instruction after the
 | 
| -  // call.  A test instruction after the call is used to indicate that
 | 
| -  // we have generated an inline version of the keyed load.  In this
 | 
| -  // case, we know that we are not generating a test instruction next.
 | 
| +    // Push the nth argument.
 | 
| +    __ push(eax);
 | 
|  
 | 
| -  // Push the nth argument.
 | 
| -  __ push(eax);
 | 
| +    // Update the index on the stack and in register eax.
 | 
| +    __ mov(eax, Operand(ebp, kIndexOffset));
 | 
| +    __ add(eax, Immediate(1 << kSmiTagSize));
 | 
| +    __ mov(Operand(ebp, kIndexOffset), eax);
 | 
|  
 | 
| -  // Update the index on the stack and in register eax.
 | 
| -  __ mov(eax, Operand(ebp, kIndexOffset));
 | 
| -  __ add(Operand(eax), Immediate(1 << kSmiTagSize));
 | 
| -  __ mov(Operand(ebp, kIndexOffset), eax);
 | 
| +    __ bind(&entry);
 | 
| +    __ cmp(eax, Operand(ebp, kLimitOffset));
 | 
| +    __ j(not_equal, &loop);
 | 
|  
 | 
| -  __ bind(&entry);
 | 
| -  __ cmp(eax, Operand(ebp, kLimitOffset));
 | 
| -  __ j(not_equal, &loop);
 | 
| +    // Invoke the function.
 | 
| +    Label call_proxy;
 | 
| +    ParameterCount actual(eax);
 | 
| +    __ SmiUntag(eax);
 | 
| +    __ mov(edi, Operand(ebp, kFunctionOffset));
 | 
| +    __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
 | 
| +    __ j(not_equal, &call_proxy);
 | 
| +    __ InvokeFunction(edi, actual, CALL_FUNCTION,
 | 
| +                      NullCallWrapper(), CALL_AS_METHOD);
 | 
|  
 | 
| -  // Invoke the function.
 | 
| -  Label call_proxy;
 | 
| -  ParameterCount actual(eax);
 | 
| -  __ SmiUntag(eax);
 | 
| -  __ mov(edi, Operand(ebp, kFunctionOffset));
 | 
| -  __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
 | 
| -  __ j(not_equal, &call_proxy);
 | 
| -  __ InvokeFunction(edi, actual, CALL_FUNCTION,
 | 
| -                    NullCallWrapper(), CALL_AS_METHOD);
 | 
| +    frame_scope.GenerateLeaveFrame();
 | 
| +    __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
 | 
|  
 | 
| -  __ LeaveInternalFrame();
 | 
| -  __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
 | 
| +    // Invoke the function proxy.
 | 
| +    __ bind(&call_proxy);
 | 
| +    __ push(edi);  // add function proxy as last argument
 | 
| +    __ inc(eax);
 | 
| +    __ Set(ebx, Immediate(0));
 | 
| +    __ SetCallKind(ecx, CALL_AS_METHOD);
 | 
| +    __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
 | 
| +    __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
 | 
| +            RelocInfo::CODE_TARGET);
 | 
|  
 | 
| -  // Invoke the function proxy.
 | 
| -  __ bind(&call_proxy);
 | 
| -  __ push(edi);  // add function proxy as last argument
 | 
| -  __ inc(eax);
 | 
| -  __ Set(ebx, Immediate(0));
 | 
| -  __ SetCallKind(ecx, CALL_AS_METHOD);
 | 
| -  __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY);
 | 
| -  __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
 | 
| -          RelocInfo::CODE_TARGET);
 | 
| -
 | 
| -  __ LeaveInternalFrame();
 | 
| +    // Leave internal frame.
 | 
| +  }
 | 
|    __ ret(3 * kPointerSize);  // remove this, receiver, and arguments
 | 
|  }
 | 
|  
 | 
| @@ -983,9 +1005,9 @@
 | 
|      __ jmp(&entry);
 | 
|      __ bind(&loop);
 | 
|      __ mov(Operand(scratch1, 0), factory->the_hole_value());
 | 
| -    __ add(Operand(scratch1), Immediate(kPointerSize));
 | 
| +    __ add(scratch1, Immediate(kPointerSize));
 | 
|      __ bind(&entry);
 | 
| -    __ cmp(scratch1, Operand(scratch2));
 | 
| +    __ cmp(scratch1, scratch2);
 | 
|      __ j(below, &loop);
 | 
|    }
 | 
|  }
 | 
| @@ -1082,7 +1104,7 @@
 | 
|      __ bind(&loop);
 | 
|      __ stos();
 | 
|      __ bind(&entry);
 | 
| -    __ cmp(edi, Operand(elements_array_end));
 | 
| +    __ cmp(edi, elements_array_end);
 | 
|      __ j(below, &loop);
 | 
|      __ bind(&done);
 | 
|    }
 | 
| @@ -1120,7 +1142,7 @@
 | 
|    __ push(eax);
 | 
|  
 | 
|    // Check for array construction with zero arguments.
 | 
| -  __ test(eax, Operand(eax));
 | 
| +  __ test(eax, eax);
 | 
|    __ j(not_zero, &argc_one_or_more);
 | 
|  
 | 
|    __ bind(&empty_array);
 | 
| @@ -1147,7 +1169,7 @@
 | 
|    __ j(not_equal, &argc_two_or_more);
 | 
|    STATIC_ASSERT(kSmiTag == 0);
 | 
|    __ mov(ecx, Operand(esp, (push_count + 1) * kPointerSize));
 | 
| -  __ test(ecx, Operand(ecx));
 | 
| +  __ test(ecx, ecx);
 | 
|    __ j(not_zero, ¬_empty_array);
 | 
|  
 | 
|    // The single argument passed is zero, so we jump to the code above used to
 | 
| @@ -1160,7 +1182,7 @@
 | 
|      __ mov(eax, Operand(esp, i * kPointerSize));
 | 
|      __ mov(Operand(esp, (i + 1) * kPointerSize), eax);
 | 
|    }
 | 
| -  __ add(Operand(esp), Immediate(2 * kPointerSize));  // Drop two stack slots.
 | 
| +  __ add(esp, Immediate(2 * kPointerSize));  // Drop two stack slots.
 | 
|    __ push(Immediate(0));  // Treat this as a call with argc of zero.
 | 
|    __ jmp(&empty_array);
 | 
|  
 | 
| @@ -1250,7 +1272,7 @@
 | 
|    __ bind(&loop);
 | 
|    __ mov(eax, Operand(edi, ecx, times_pointer_size, 0));
 | 
|    __ mov(Operand(edx, 0), eax);
 | 
| -  __ add(Operand(edx), Immediate(kPointerSize));
 | 
| +  __ add(edx, Immediate(kPointerSize));
 | 
|    __ bind(&entry);
 | 
|    __ dec(ecx);
 | 
|    __ j(greater_equal, &loop);
 | 
| @@ -1356,14 +1378,14 @@
 | 
|  
 | 
|    if (FLAG_debug_code) {
 | 
|      __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx);
 | 
| -    __ cmp(edi, Operand(ecx));
 | 
| +    __ cmp(edi, ecx);
 | 
|      __ Assert(equal, "Unexpected String function");
 | 
|    }
 | 
|  
 | 
|    // Load the first argument into eax and get rid of the rest
 | 
|    // (including the receiver).
 | 
|    Label no_arguments;
 | 
| -  __ test(eax, Operand(eax));
 | 
| +  __ test(eax, eax);
 | 
|    __ j(zero, &no_arguments);
 | 
|    __ mov(ebx, Operand(esp, eax, times_pointer_size, 0));
 | 
|    __ pop(ecx);
 | 
| @@ -1439,12 +1461,13 @@
 | 
|    // Invoke the conversion builtin and put the result into ebx.
 | 
|    __ bind(&convert_argument);
 | 
|    __ IncrementCounter(counters->string_ctor_conversions(), 1);
 | 
| -  __ EnterInternalFrame();
 | 
| -  __ push(edi);  // Preserve the function.
 | 
| -  __ push(eax);
 | 
| -  __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
 | 
| -  __ pop(edi);
 | 
| -  __ LeaveInternalFrame();
 | 
| +  {
 | 
| +    FrameScope scope(masm, StackFrame::INTERNAL);
 | 
| +    __ push(edi);  // Preserve the function.
 | 
| +    __ push(eax);
 | 
| +    __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
 | 
| +    __ pop(edi);
 | 
| +  }
 | 
|    __ mov(ebx, eax);
 | 
|    __ jmp(&argument_is_string);
 | 
|  
 | 
| @@ -1461,17 +1484,18 @@
 | 
|    // create a string wrapper.
 | 
|    __ bind(&gc_required);
 | 
|    __ IncrementCounter(counters->string_ctor_gc_required(), 1);
 | 
| -  __ EnterInternalFrame();
 | 
| -  __ push(ebx);
 | 
| -  __ CallRuntime(Runtime::kNewStringWrapper, 1);
 | 
| -  __ LeaveInternalFrame();
 | 
| +  {
 | 
| +    FrameScope scope(masm, StackFrame::INTERNAL);
 | 
| +    __ push(ebx);
 | 
| +    __ CallRuntime(Runtime::kNewStringWrapper, 1);
 | 
| +  }
 | 
|    __ ret(0);
 | 
|  }
 | 
|  
 | 
|  
 | 
|  static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
 | 
|    __ push(ebp);
 | 
| -  __ mov(ebp, Operand(esp));
 | 
| +  __ mov(ebp, esp);
 | 
|  
 | 
|    // Store the arguments adaptor context sentinel.
 | 
|    __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
 | 
| @@ -1515,7 +1539,7 @@
 | 
|    __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1);
 | 
|  
 | 
|    Label enough, too_few;
 | 
| -  __ cmp(eax, Operand(ebx));
 | 
| +  __ cmp(eax, ebx);
 | 
|    __ j(less, &too_few);
 | 
|    __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
 | 
|    __ j(equal, &dont_adapt_arguments);
 | 
| @@ -1533,8 +1557,8 @@
 | 
|      __ bind(©);
 | 
|      __ inc(edi);
 | 
|      __ push(Operand(eax, 0));
 | 
| -    __ sub(Operand(eax), Immediate(kPointerSize));
 | 
| -    __ cmp(edi, Operand(ebx));
 | 
| +    __ sub(eax, Immediate(kPointerSize));
 | 
| +    __ cmp(edi, ebx);
 | 
|      __ j(less, ©);
 | 
|      __ jmp(&invoke);
 | 
|    }
 | 
| @@ -1547,17 +1571,17 @@
 | 
|      const int offset = StandardFrameConstants::kCallerSPOffset;
 | 
|      __ lea(edi, Operand(ebp, eax, times_4, offset));
 | 
|      // ebx = expected - actual.
 | 
| -    __ sub(ebx, Operand(eax));
 | 
| +    __ sub(ebx, eax);
 | 
|      // eax = -actual - 1
 | 
|      __ neg(eax);
 | 
| -    __ sub(Operand(eax), Immediate(1));
 | 
| +    __ sub(eax, Immediate(1));
 | 
|  
 | 
|      Label copy;
 | 
|      __ bind(©);
 | 
|      __ inc(eax);
 | 
|      __ push(Operand(edi, 0));
 | 
| -    __ sub(Operand(edi), Immediate(kPointerSize));
 | 
| -    __ test(eax, Operand(eax));
 | 
| +    __ sub(edi, Immediate(kPointerSize));
 | 
| +    __ test(eax, eax);
 | 
|      __ j(not_zero, ©);
 | 
|  
 | 
|      // Fill remaining expected arguments with undefined values.
 | 
| @@ -1565,7 +1589,7 @@
 | 
|      __ bind(&fill);
 | 
|      __ inc(eax);
 | 
|      __ push(Immediate(masm->isolate()->factory()->undefined_value()));
 | 
| -    __ cmp(eax, Operand(ebx));
 | 
| +    __ cmp(eax, ebx);
 | 
|      __ j(less, &fill);
 | 
|    }
 | 
|  
 | 
| @@ -1573,7 +1597,7 @@
 | 
|    __ bind(&invoke);
 | 
|    // Restore function pointer.
 | 
|    __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
 | 
| -  __ call(Operand(edx));
 | 
| +  __ call(edx);
 | 
|  
 | 
|    // Leave frame and return.
 | 
|    LeaveArgumentsAdaptorFrame(masm);
 | 
| @@ -1583,13 +1607,13 @@
 | 
|    // Dont adapt arguments.
 | 
|    // -------------------------------------------
 | 
|    __ bind(&dont_adapt_arguments);
 | 
| -  __ jmp(Operand(edx));
 | 
| +  __ jmp(edx);
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
 | 
|    CpuFeatures::TryForceFeatureScope scope(SSE2);
 | 
| -  if (!CpuFeatures::IsSupported(SSE2)) {
 | 
| +  if (!CpuFeatures::IsSupported(SSE2) && FLAG_debug_code) {
 | 
|      __ Abort("Unreachable code: Cannot optimize without SSE2 support.");
 | 
|      return;
 | 
|    }
 | 
| @@ -1616,15 +1640,16 @@
 | 
|  
 | 
|    // Pass the function to optimize as the argument to the on-stack
 | 
|    // replacement runtime function.
 | 
| -  __ EnterInternalFrame();
 | 
| -  __ push(eax);
 | 
| -  __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
 | 
| -  __ LeaveInternalFrame();
 | 
| +  {
 | 
| +    FrameScope scope(masm, StackFrame::INTERNAL);
 | 
| +    __ push(eax);
 | 
| +    __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
 | 
| +  }
 | 
|  
 | 
|    // If the result was -1 it means that we couldn't optimize the
 | 
|    // function. Just return and continue in the unoptimized version.
 | 
|    Label skip;
 | 
| -  __ cmp(Operand(eax), Immediate(Smi::FromInt(-1)));
 | 
| +  __ cmp(eax, Immediate(Smi::FromInt(-1)));
 | 
|    __ j(not_equal, &skip, Label::kNear);
 | 
|    __ ret(0);
 | 
|  
 | 
| @@ -1638,7 +1663,9 @@
 | 
|    __ j(above_equal, &ok, Label::kNear);
 | 
|    StackCheckStub stub;
 | 
|    __ TailCallStub(&stub);
 | 
| -  __ Abort("Unreachable code: returned from tail call.");
 | 
| +  if (FLAG_debug_code) {
 | 
| +    __ Abort("Unreachable code: returned from tail call.");
 | 
| +  }
 | 
|    __ bind(&ok);
 | 
|    __ ret(0);
 | 
|  
 | 
| 
 |