| Index: src/builtins.cc | 
| diff --git a/src/builtins.cc b/src/builtins.cc | 
| index 90e11e3d6cccbc10323287f2250452ea74889cf0..bda1c0d2355ac8675ddeea325293674e0a72ae21 100644 | 
| --- a/src/builtins.cc | 
| +++ b/src/builtins.cc | 
| @@ -4165,6 +4165,199 @@ BUILTIN(ObjectProtoToString) { | 
| return *result; | 
| } | 
|  | 
| +// ----------------------------------------------------------------------------- | 
| +// ES6 section 21.1 String Objects | 
| + | 
| +// ES6 section 21.1.3.1 String.prototype.charAt ( pos ) | 
| +void Builtins::Generate_StringPrototypeCharAt( | 
| +    compiler::CodeStubAssembler* assembler) { | 
| +  typedef compiler::CodeStubAssembler::Label Label; | 
| +  typedef compiler::Node Node; | 
| +  typedef compiler::CodeStubAssembler::Variable Variable; | 
| + | 
| +  Node* receiver = assembler->Parameter(0); | 
| +  Node* position = assembler->Parameter(1); | 
| +  Node* context = assembler->Parameter(4); | 
| + | 
| +  // Check that {receiver} is coercible to Object and convert it to a String. | 
| +  receiver = | 
| +      assembler->ToThisString(context, receiver, "String.prototype.charAt"); | 
| + | 
| +  // Convert the {position} to a Smi and check that it's in bounds of the | 
| +  // {receiver}. | 
| +  // TODO(bmeurer): Find an abstraction for this! | 
| +  { | 
| +    // Check if the {position} is already a Smi. | 
| +    Variable var_position(assembler, MachineRepresentation::kTagged); | 
| +    var_position.Bind(position); | 
| +    Label if_positionissmi(assembler), | 
| +        if_positionisnotsmi(assembler, Label::kDeferred); | 
| +    assembler->Branch(assembler->WordIsSmi(position), &if_positionissmi, | 
| +                      &if_positionisnotsmi); | 
| +    assembler->Bind(&if_positionisnotsmi); | 
| +    { | 
| +      // Convert the {position} to an Integer via the ToIntegerStub. | 
| +      Callable callable = CodeFactory::ToInteger(assembler->isolate()); | 
| +      Node* index = assembler->CallStub(callable, context, position); | 
| + | 
| +      // Check if the resulting {index} is now a Smi. | 
| +      Label if_indexissmi(assembler, Label::kDeferred), | 
| +          if_indexisnotsmi(assembler, Label::kDeferred); | 
| +      assembler->Branch(assembler->WordIsSmi(index), &if_indexissmi, | 
| +                        &if_indexisnotsmi); | 
| + | 
| +      assembler->Bind(&if_indexissmi); | 
| +      { | 
| +        var_position.Bind(index); | 
| +        assembler->Goto(&if_positionissmi); | 
| +      } | 
| + | 
| +      assembler->Bind(&if_indexisnotsmi); | 
| +      { | 
| +        // The ToIntegerStub canonicalizes everything in Smi range to Smi | 
| +        // representation, so any HeapNumber returned is not in Smi range. | 
| +        // The only exception here is -0.0, which we treat as 0. | 
| +        Node* index_value = assembler->LoadHeapNumberValue(index); | 
| +        Label if_indexiszero(assembler, Label::kDeferred), | 
| +            if_indexisnotzero(assembler, Label::kDeferred); | 
| +        assembler->Branch(assembler->Float64Equal( | 
| +                              index_value, assembler->Float64Constant(0.0)), | 
| +                          &if_indexiszero, &if_indexisnotzero); | 
| + | 
| +        assembler->Bind(&if_indexiszero); | 
| +        { | 
| +          var_position.Bind(assembler->SmiConstant(Smi::FromInt(0))); | 
| +          assembler->Goto(&if_positionissmi); | 
| +        } | 
| + | 
| +        assembler->Bind(&if_indexisnotzero); | 
| +        { | 
| +          // The {index} is some other integral Number, that is definitely | 
| +          // neither -0.0 nor in Smi range. | 
| +          assembler->Return(assembler->EmptyStringConstant()); | 
| +        } | 
| +      } | 
| +    } | 
| +    assembler->Bind(&if_positionissmi); | 
| +    position = var_position.value(); | 
| + | 
| +    // Determine the actual length of the {receiver} String. | 
| +    Node* receiver_length = | 
| +        assembler->LoadObjectField(receiver, String::kLengthOffset); | 
| + | 
| +    // Return "" if the Smi {position} is outside the bounds of the {receiver}. | 
| +    Label if_positioninbounds(assembler), | 
| +        if_positionnotinbounds(assembler, Label::kDeferred); | 
| +    assembler->Branch(assembler->SmiAboveOrEqual(position, receiver_length), | 
| +                      &if_positionnotinbounds, &if_positioninbounds); | 
| +    assembler->Bind(&if_positionnotinbounds); | 
| +    assembler->Return(assembler->EmptyStringConstant()); | 
| +    assembler->Bind(&if_positioninbounds); | 
| +  } | 
| + | 
| +  // Load the character code at the {position} from the {receiver}. | 
| +  Node* code = assembler->StringCharCodeAt(receiver, position); | 
| + | 
| +  // And return the single character string with only that {code}. | 
| +  Node* result = assembler->StringFromCharCode(code); | 
| +  assembler->Return(result); | 
| +} | 
| + | 
| +// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) | 
| +void Builtins::Generate_StringPrototypeCharCodeAt( | 
| +    compiler::CodeStubAssembler* assembler) { | 
| +  typedef compiler::CodeStubAssembler::Label Label; | 
| +  typedef compiler::Node Node; | 
| +  typedef compiler::CodeStubAssembler::Variable Variable; | 
| + | 
| +  Node* receiver = assembler->Parameter(0); | 
| +  Node* position = assembler->Parameter(1); | 
| +  Node* context = assembler->Parameter(4); | 
| + | 
| +  // Check that {receiver} is coercible to Object and convert it to a String. | 
| +  receiver = | 
| +      assembler->ToThisString(context, receiver, "String.prototype.charCodeAt"); | 
| + | 
| +  // Convert the {position} to a Smi and check that it's in bounds of the | 
| +  // {receiver}. | 
| +  // TODO(bmeurer): Find an abstraction for this! | 
| +  { | 
| +    // Check if the {position} is already a Smi. | 
| +    Variable var_position(assembler, MachineRepresentation::kTagged); | 
| +    var_position.Bind(position); | 
| +    Label if_positionissmi(assembler), | 
| +        if_positionisnotsmi(assembler, Label::kDeferred); | 
| +    assembler->Branch(assembler->WordIsSmi(position), &if_positionissmi, | 
| +                      &if_positionisnotsmi); | 
| +    assembler->Bind(&if_positionisnotsmi); | 
| +    { | 
| +      // Convert the {position} to an Integer via the ToIntegerStub. | 
| +      Callable callable = CodeFactory::ToInteger(assembler->isolate()); | 
| +      Node* index = assembler->CallStub(callable, context, position); | 
| + | 
| +      // Check if the resulting {index} is now a Smi. | 
| +      Label if_indexissmi(assembler, Label::kDeferred), | 
| +          if_indexisnotsmi(assembler, Label::kDeferred); | 
| +      assembler->Branch(assembler->WordIsSmi(index), &if_indexissmi, | 
| +                        &if_indexisnotsmi); | 
| + | 
| +      assembler->Bind(&if_indexissmi); | 
| +      { | 
| +        var_position.Bind(index); | 
| +        assembler->Goto(&if_positionissmi); | 
| +      } | 
| + | 
| +      assembler->Bind(&if_indexisnotsmi); | 
| +      { | 
| +        // The ToIntegerStub canonicalizes everything in Smi range to Smi | 
| +        // representation, so any HeapNumber returned is not in Smi range. | 
| +        // The only exception here is -0.0, which we treat as 0. | 
| +        Node* index_value = assembler->LoadHeapNumberValue(index); | 
| +        Label if_indexiszero(assembler, Label::kDeferred), | 
| +            if_indexisnotzero(assembler, Label::kDeferred); | 
| +        assembler->Branch(assembler->Float64Equal( | 
| +                              index_value, assembler->Float64Constant(0.0)), | 
| +                          &if_indexiszero, &if_indexisnotzero); | 
| + | 
| +        assembler->Bind(&if_indexiszero); | 
| +        { | 
| +          var_position.Bind(assembler->SmiConstant(Smi::FromInt(0))); | 
| +          assembler->Goto(&if_positionissmi); | 
| +        } | 
| + | 
| +        assembler->Bind(&if_indexisnotzero); | 
| +        { | 
| +          // The {index} is some other integral Number, that is definitely | 
| +          // neither -0.0 nor in Smi range. | 
| +          assembler->Return(assembler->NaNConstant()); | 
| +        } | 
| +      } | 
| +    } | 
| +    assembler->Bind(&if_positionissmi); | 
| +    position = var_position.value(); | 
| + | 
| +    // Determine the actual length of the {receiver} String. | 
| +    Node* receiver_length = | 
| +        assembler->LoadObjectField(receiver, String::kLengthOffset); | 
| + | 
| +    // Return NaN if the Smi {position} is outside the bounds of the {receiver}. | 
| +    Label if_positioninbounds(assembler), | 
| +        if_positionnotinbounds(assembler, Label::kDeferred); | 
| +    assembler->Branch(assembler->SmiAboveOrEqual(position, receiver_length), | 
| +                      &if_positionnotinbounds, &if_positioninbounds); | 
| +    assembler->Bind(&if_positionnotinbounds); | 
| +    assembler->Return(assembler->NaNConstant()); | 
| +    assembler->Bind(&if_positioninbounds); | 
| +  } | 
| + | 
| +  // Load the character at the {position} from the {receiver}. | 
| +  Node* value = assembler->StringCharCodeAt(receiver, position); | 
| +  Node* result = assembler->SmiFromWord32(value); | 
| +  assembler->Return(result); | 
| +} | 
| + | 
| +// ----------------------------------------------------------------------------- | 
| +// ES6 section 21.1 ArrayBuffer Objects | 
|  | 
| // ES6 section 24.1.2.1 ArrayBuffer ( length ) for the [[Call]] case. | 
| BUILTIN(ArrayBufferConstructor) { | 
|  |