LCOV - code coverage report
Current view: top level - src/builtins - builtins-conversion-gen.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 180 180 100.0 %
Date: 2017-04-26 Functions: 34 34 100.0 %

          Line data    Source code
       1             : // Copyright 2016 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/builtins/builtins-utils-gen.h"
       6             : #include "src/builtins/builtins.h"
       7             : #include "src/code-factory.h"
       8             : #include "src/code-stub-assembler.h"
       9             : #include "src/objects-inl.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14             : class ConversionBuiltinsAssembler : public CodeStubAssembler {
      15             :  public:
      16             :   explicit ConversionBuiltinsAssembler(compiler::CodeAssemblerState* state)
      17         215 :       : CodeStubAssembler(state) {}
      18             : 
      19             :  protected:
      20             :   void Generate_NonPrimitiveToPrimitive(Node* context, Node* input,
      21             :                                         ToPrimitiveHint hint);
      22             : 
      23             :   void Generate_OrdinaryToPrimitive(Node* context, Node* input,
      24             :                                     OrdinaryToPrimitiveHint hint);
      25             : };
      26             : 
      27             : // ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] )
      28         129 : void ConversionBuiltinsAssembler::Generate_NonPrimitiveToPrimitive(
      29             :     Node* context, Node* input, ToPrimitiveHint hint) {
      30             :   // Lookup the @@toPrimitive property on the {input}.
      31             :   Node* exotic_to_prim =
      32         258 :       GetProperty(context, input, factory()->to_primitive_symbol());
      33             : 
      34             :   // Check if {exotic_to_prim} is neither null nor undefined.
      35             :   Label ordinary_to_primitive(this);
      36         129 :   GotoIf(WordEqual(exotic_to_prim, NullConstant()), &ordinary_to_primitive);
      37             :   GotoIf(WordEqual(exotic_to_prim, UndefinedConstant()),
      38         129 :          &ordinary_to_primitive);
      39             :   {
      40             :     // Invoke the {exotic_to_prim} method on the {input} with a string
      41             :     // representation of the {hint}.
      42             :     Callable callable =
      43         129 :         CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined);
      44         258 :     Node* hint_string = HeapConstant(factory()->ToPrimitiveHintString(hint));
      45             :     Node* result =
      46         129 :         CallJS(callable, context, exotic_to_prim, input, hint_string);
      47             : 
      48             :     // Verify that the {result} is actually a primitive.
      49         129 :     Label if_resultisprimitive(this),
      50         129 :         if_resultisnotprimitive(this, Label::kDeferred);
      51         129 :     GotoIf(TaggedIsSmi(result), &if_resultisprimitive);
      52         129 :     Node* result_instance_type = LoadInstanceType(result);
      53             :     STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
      54             :     Branch(Int32LessThanOrEqual(result_instance_type,
      55             :                                 Int32Constant(LAST_PRIMITIVE_TYPE)),
      56         129 :            &if_resultisprimitive, &if_resultisnotprimitive);
      57             : 
      58         129 :     BIND(&if_resultisprimitive);
      59             :     {
      60             :       // Just return the {result}.
      61         129 :       Return(result);
      62             :     }
      63             : 
      64         129 :     BIND(&if_resultisnotprimitive);
      65             :     {
      66             :       // Somehow the @@toPrimitive method on {input} didn't yield a primitive.
      67         129 :       TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context);
      68             :     }
      69             :   }
      70             : 
      71             :   // Convert using the OrdinaryToPrimitive algorithm instead.
      72         129 :   BIND(&ordinary_to_primitive);
      73             :   {
      74             :     Callable callable = CodeFactory::OrdinaryToPrimitive(
      75             :         isolate(), (hint == ToPrimitiveHint::kString)
      76             :                        ? OrdinaryToPrimitiveHint::kString
      77         129 :                        : OrdinaryToPrimitiveHint::kNumber);
      78         129 :     TailCallStub(callable, context, input);
      79         129 :   }
      80         129 : }
      81             : 
      82         172 : TF_BUILTIN(NonPrimitiveToPrimitive_Default, ConversionBuiltinsAssembler) {
      83             :   Node* context = Parameter(Descriptor::kContext);
      84             :   Node* input = Parameter(Descriptor::kArgument);
      85             : 
      86          43 :   Generate_NonPrimitiveToPrimitive(context, input, ToPrimitiveHint::kDefault);
      87          43 : }
      88             : 
      89         172 : TF_BUILTIN(NonPrimitiveToPrimitive_Number, ConversionBuiltinsAssembler) {
      90             :   Node* context = Parameter(Descriptor::kContext);
      91             :   Node* input = Parameter(Descriptor::kArgument);
      92             : 
      93          43 :   Generate_NonPrimitiveToPrimitive(context, input, ToPrimitiveHint::kNumber);
      94          43 : }
      95             : 
      96         172 : TF_BUILTIN(NonPrimitiveToPrimitive_String, ConversionBuiltinsAssembler) {
      97             :   Node* context = Parameter(Descriptor::kContext);
      98             :   Node* input = Parameter(Descriptor::kArgument);
      99             : 
     100          43 :   Generate_NonPrimitiveToPrimitive(context, input, ToPrimitiveHint::kString);
     101          43 : }
     102             : 
     103         129 : TF_BUILTIN(StringToNumber, CodeStubAssembler) {
     104             :   Node* context = Parameter(Descriptor::kContext);
     105             :   Node* input = Parameter(Descriptor::kArgument);
     106             : 
     107          43 :   Return(StringToNumber(context, input));
     108          43 : }
     109             : 
     110         129 : TF_BUILTIN(ToName, CodeStubAssembler) {
     111             :   Node* context = Parameter(Descriptor::kContext);
     112             :   Node* input = Parameter(Descriptor::kArgument);
     113             : 
     114          43 :   Return(ToName(context, input));
     115          43 : }
     116             : 
     117         129 : TF_BUILTIN(NonNumberToNumber, CodeStubAssembler) {
     118             :   Node* context = Parameter(Descriptor::kContext);
     119             :   Node* input = Parameter(Descriptor::kArgument);
     120             : 
     121          43 :   Return(NonNumberToNumber(context, input));
     122          43 : }
     123             : 
     124             : // ES6 section 7.1.3 ToNumber ( argument )
     125         129 : TF_BUILTIN(ToNumber, CodeStubAssembler) {
     126             :   Node* context = Parameter(Descriptor::kContext);
     127             :   Node* input = Parameter(Descriptor::kArgument);
     128             : 
     129          43 :   Return(ToNumber(context, input));
     130          43 : }
     131             : 
     132         129 : TF_BUILTIN(ToString, CodeStubAssembler) {
     133             :   Node* context = Parameter(Descriptor::kContext);
     134             :   Node* input = Parameter(Descriptor::kArgument);
     135             : 
     136             :   Label is_number(this);
     137          43 :   Label runtime(this);
     138             : 
     139          43 :   GotoIf(TaggedIsSmi(input), &is_number);
     140             : 
     141          43 :   Node* input_map = LoadMap(input);
     142          43 :   Node* input_instance_type = LoadMapInstanceType(input_map);
     143             : 
     144          43 :   Label not_string(this);
     145          43 :   GotoIfNot(IsStringInstanceType(input_instance_type), &not_string);
     146          43 :   Return(input);
     147             : 
     148          43 :   Label not_heap_number(this);
     149             : 
     150          43 :   BIND(&not_string);
     151          43 :   { Branch(IsHeapNumberMap(input_map), &is_number, &not_heap_number); }
     152             : 
     153          43 :   BIND(&is_number);
     154          43 :   { Return(NumberToString(context, input)); }
     155             : 
     156          43 :   BIND(&not_heap_number);
     157             :   {
     158             :     GotoIf(Word32NotEqual(input_instance_type, Int32Constant(ODDBALL_TYPE)),
     159          43 :            &runtime);
     160          43 :     Return(LoadObjectField(input, Oddball::kToStringOffset));
     161             :   }
     162             : 
     163          43 :   BIND(&runtime);
     164          86 :   { Return(CallRuntime(Runtime::kToString, context, input)); }
     165          43 : }
     166             : 
     167             : // 7.1.1.1 OrdinaryToPrimitive ( O, hint )
     168          86 : void ConversionBuiltinsAssembler::Generate_OrdinaryToPrimitive(
     169             :     Node* context, Node* input, OrdinaryToPrimitiveHint hint) {
     170          86 :   VARIABLE(var_result, MachineRepresentation::kTagged);
     171          86 :   Label return_result(this, &var_result);
     172             : 
     173         258 :   Handle<String> method_names[2];
     174          86 :   switch (hint) {
     175             :     case OrdinaryToPrimitiveHint::kNumber:
     176          86 :       method_names[0] = factory()->valueOf_string();
     177          86 :       method_names[1] = factory()->toString_string();
     178          43 :       break;
     179             :     case OrdinaryToPrimitiveHint::kString:
     180          86 :       method_names[0] = factory()->toString_string();
     181          86 :       method_names[1] = factory()->valueOf_string();
     182          43 :       break;
     183             :   }
     184         344 :   for (Handle<String> name : method_names) {
     185             :     // Lookup the {name} on the {input}.
     186         172 :     Node* method = GetProperty(context, input, name);
     187             : 
     188             :     // Check if the {method} is callable.
     189             :     Label if_methodiscallable(this),
     190         172 :         if_methodisnotcallable(this, Label::kDeferred);
     191         172 :     GotoIf(TaggedIsSmi(method), &if_methodisnotcallable);
     192         172 :     Node* method_map = LoadMap(method);
     193             :     Branch(IsCallableMap(method_map), &if_methodiscallable,
     194         172 :            &if_methodisnotcallable);
     195             : 
     196         172 :     BIND(&if_methodiscallable);
     197             :     {
     198             :       // Call the {method} on the {input}.
     199             :       Callable callable = CodeFactory::Call(
     200         172 :           isolate(), ConvertReceiverMode::kNotNullOrUndefined);
     201         172 :       Node* result = CallJS(callable, context, method, input);
     202         172 :       var_result.Bind(result);
     203             : 
     204             :       // Return the {result} if it is a primitive.
     205         172 :       GotoIf(TaggedIsSmi(result), &return_result);
     206         172 :       Node* result_instance_type = LoadInstanceType(result);
     207             :       STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
     208             :       GotoIf(Int32LessThanOrEqual(result_instance_type,
     209             :                                   Int32Constant(LAST_PRIMITIVE_TYPE)),
     210         172 :              &return_result);
     211             :     }
     212             : 
     213             :     // Just continue with the next {name} if the {method} is not callable.
     214         172 :     Goto(&if_methodisnotcallable);
     215         172 :     BIND(&if_methodisnotcallable);
     216         172 :   }
     217             : 
     218          86 :   TailCallRuntime(Runtime::kThrowCannotConvertToPrimitive, context);
     219             : 
     220          86 :   BIND(&return_result);
     221         172 :   Return(var_result.value());
     222          86 : }
     223             : 
     224         172 : TF_BUILTIN(OrdinaryToPrimitive_Number, ConversionBuiltinsAssembler) {
     225             :   Node* context = Parameter(Descriptor::kContext);
     226             :   Node* input = Parameter(Descriptor::kArgument);
     227             :   Generate_OrdinaryToPrimitive(context, input,
     228          43 :                                OrdinaryToPrimitiveHint::kNumber);
     229          43 : }
     230             : 
     231         172 : TF_BUILTIN(OrdinaryToPrimitive_String, ConversionBuiltinsAssembler) {
     232             :   Node* context = Parameter(Descriptor::kContext);
     233             :   Node* input = Parameter(Descriptor::kArgument);
     234             :   Generate_OrdinaryToPrimitive(context, input,
     235          43 :                                OrdinaryToPrimitiveHint::kString);
     236          43 : }
     237             : 
     238             : // ES6 section 7.1.2 ToBoolean ( argument )
     239         129 : TF_BUILTIN(ToBoolean, CodeStubAssembler) {
     240             :   Node* value = Parameter(Descriptor::kArgument);
     241             : 
     242          43 :   Label return_true(this), return_false(this);
     243          43 :   BranchIfToBooleanIsTrue(value, &return_true, &return_false);
     244             : 
     245          43 :   BIND(&return_true);
     246          43 :   Return(BooleanConstant(true));
     247             : 
     248          43 :   BIND(&return_false);
     249          86 :   Return(BooleanConstant(false));
     250          43 : }
     251             : 
     252         129 : TF_BUILTIN(ToLength, CodeStubAssembler) {
     253             :   Node* context = Parameter(Descriptor::kContext);
     254             : 
     255             :   // We might need to loop once for ToNumber conversion.
     256          43 :   VARIABLE(var_len, MachineRepresentation::kTagged,
     257             :            Parameter(Descriptor::kArgument));
     258          43 :   Label loop(this, &var_len);
     259          43 :   Goto(&loop);
     260          43 :   BIND(&loop);
     261             :   {
     262             :     // Shared entry points.
     263          43 :     Label return_len(this), return_two53minus1(this, Label::kDeferred),
     264          43 :         return_zero(this, Label::kDeferred);
     265             : 
     266             :     // Load the current {len} value.
     267          43 :     Node* len = var_len.value();
     268             : 
     269             :     // Check if {len} is a positive Smi.
     270          43 :     GotoIf(TaggedIsPositiveSmi(len), &return_len);
     271             : 
     272             :     // Check if {len} is a (negative) Smi.
     273          43 :     GotoIf(TaggedIsSmi(len), &return_zero);
     274             : 
     275             :     // Check if {len} is a HeapNumber.
     276          43 :     Label if_lenisheapnumber(this),
     277          43 :         if_lenisnotheapnumber(this, Label::kDeferred);
     278             :     Branch(IsHeapNumberMap(LoadMap(len)), &if_lenisheapnumber,
     279          43 :            &if_lenisnotheapnumber);
     280             : 
     281          43 :     BIND(&if_lenisheapnumber);
     282             :     {
     283             :       // Load the floating-point value of {len}.
     284          43 :       Node* len_value = LoadHeapNumberValue(len);
     285             : 
     286             :       // Check if {len} is not greater than zero.
     287             :       GotoIfNot(Float64GreaterThan(len_value, Float64Constant(0.0)),
     288          43 :                 &return_zero);
     289             : 
     290             :       // Check if {len} is greater than or equal to 2^53-1.
     291             :       GotoIf(Float64GreaterThanOrEqual(len_value,
     292             :                                        Float64Constant(kMaxSafeInteger)),
     293          43 :              &return_two53minus1);
     294             : 
     295             :       // Round the {len} towards -Infinity.
     296          43 :       Node* value = Float64Floor(len_value);
     297          43 :       Node* result = ChangeFloat64ToTagged(value);
     298          43 :       Return(result);
     299             :     }
     300             : 
     301          43 :     BIND(&if_lenisnotheapnumber);
     302             :     {
     303             :       // Need to convert {len} to a Number first.
     304          43 :       Callable callable = CodeFactory::NonNumberToNumber(isolate());
     305          43 :       var_len.Bind(CallStub(callable, context, len));
     306          43 :       Goto(&loop);
     307             :     }
     308             : 
     309          43 :     BIND(&return_len);
     310          43 :     Return(var_len.value());
     311             : 
     312          43 :     BIND(&return_two53minus1);
     313          43 :     Return(NumberConstant(kMaxSafeInteger));
     314             : 
     315          43 :     BIND(&return_zero);
     316          86 :     Return(SmiConstant(Smi::kZero));
     317          43 :   }
     318          43 : }
     319             : 
     320         129 : TF_BUILTIN(ToInteger, CodeStubAssembler) {
     321             :   Node* context = Parameter(Descriptor::kContext);
     322             :   Node* input = Parameter(Descriptor::kArgument);
     323             : 
     324          43 :   Return(ToInteger(context, input));
     325          43 : }
     326             : 
     327             : // ES6 section 7.1.13 ToObject (argument)
     328         172 : TF_BUILTIN(ToObject, CodeStubAssembler) {
     329          86 :   Label if_number(this, Label::kDeferred), if_notsmi(this), if_jsreceiver(this),
     330          43 :       if_noconstructor(this, Label::kDeferred), if_wrapjsvalue(this);
     331             : 
     332             :   Node* context = Parameter(Descriptor::kContext);
     333             :   Node* object = Parameter(Descriptor::kArgument);
     334             : 
     335          86 :   VARIABLE(constructor_function_index_var,
     336             :            MachineType::PointerRepresentation());
     337             : 
     338          43 :   Branch(TaggedIsSmi(object), &if_number, &if_notsmi);
     339             : 
     340          43 :   BIND(&if_notsmi);
     341          43 :   Node* map = LoadMap(object);
     342             : 
     343          43 :   GotoIf(IsHeapNumberMap(map), &if_number);
     344             : 
     345          43 :   Node* instance_type = LoadMapInstanceType(map);
     346          43 :   GotoIf(IsJSReceiverInstanceType(instance_type), &if_jsreceiver);
     347             : 
     348          43 :   Node* constructor_function_index = LoadMapConstructorFunctionIndex(map);
     349             :   GotoIf(WordEqual(constructor_function_index,
     350             :                    IntPtrConstant(Map::kNoConstructorFunctionIndex)),
     351          43 :          &if_noconstructor);
     352          43 :   constructor_function_index_var.Bind(constructor_function_index);
     353          43 :   Goto(&if_wrapjsvalue);
     354             : 
     355          43 :   BIND(&if_number);
     356             :   constructor_function_index_var.Bind(
     357          43 :       IntPtrConstant(Context::NUMBER_FUNCTION_INDEX));
     358          43 :   Goto(&if_wrapjsvalue);
     359             : 
     360          43 :   BIND(&if_wrapjsvalue);
     361          43 :   Node* native_context = LoadNativeContext(context);
     362             :   Node* constructor = LoadFixedArrayElement(
     363          43 :       native_context, constructor_function_index_var.value());
     364             :   Node* initial_map =
     365          43 :       LoadObjectField(constructor, JSFunction::kPrototypeOrInitialMapOffset);
     366          43 :   Node* js_value = Allocate(JSValue::kSize);
     367          43 :   StoreMapNoWriteBarrier(js_value, initial_map);
     368             :   StoreObjectFieldRoot(js_value, JSValue::kPropertiesOffset,
     369          43 :                        Heap::kEmptyFixedArrayRootIndex);
     370             :   StoreObjectFieldRoot(js_value, JSObject::kElementsOffset,
     371          43 :                        Heap::kEmptyFixedArrayRootIndex);
     372          43 :   StoreObjectField(js_value, JSValue::kValueOffset, object);
     373          43 :   Return(js_value);
     374             : 
     375          43 :   BIND(&if_noconstructor);
     376             :   TailCallRuntime(
     377             :       Runtime::kThrowUndefinedOrNullToObject, context,
     378          86 :       HeapConstant(factory()->NewStringFromAsciiChecked("ToObject", TENURED)));
     379             : 
     380          43 :   BIND(&if_jsreceiver);
     381          86 :   Return(object);
     382          43 : }
     383             : 
     384             : // Deprecated ES5 [[Class]] internal property (used to implement %_ClassOf).
     385         129 : TF_BUILTIN(ClassOf, CodeStubAssembler) {
     386             :   Node* object = Parameter(TypeofDescriptor::kObject);
     387             : 
     388          43 :   Return(ClassOf(object));
     389          43 : }
     390             : 
     391             : // ES6 section 12.5.5 typeof operator
     392         129 : TF_BUILTIN(Typeof, CodeStubAssembler) {
     393             :   Node* object = Parameter(TypeofDescriptor::kObject);
     394             : 
     395          43 :   Return(Typeof(object));
     396          43 : }
     397             : 
     398             : }  // namespace internal
     399             : }  // namespace v8

Generated by: LCOV version 1.10