| OLD | NEW |
| (Empty) |
| 1 // Copyright 2017 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-arguments.h" | |
| 6 #include "src/builtins/builtins-utils.h" | |
| 7 #include "src/builtins/builtins.h" | |
| 8 #include "src/code-factory.h" | |
| 9 #include "src/code-stub-assembler.h" | |
| 10 #include "src/interface-descriptors.h" | |
| 11 #include "src/objects-inl.h" | |
| 12 | |
| 13 namespace v8 { | |
| 14 namespace internal { | |
| 15 | |
| 16 typedef compiler::Node Node; | |
| 17 | |
| 18 std::tuple<Node*, Node*, Node*> | |
| 19 ArgumentsBuiltinsAssembler::GetArgumentsFrameAndCount(Node* function, | |
| 20 ParameterMode mode) { | |
| 21 CSA_ASSERT(this, HasInstanceType(function, JS_FUNCTION_TYPE)); | |
| 22 | |
| 23 Variable frame_ptr(this, MachineType::PointerRepresentation()); | |
| 24 frame_ptr.Bind(LoadParentFramePointer()); | |
| 25 CSA_ASSERT(this, | |
| 26 WordEqual(function, | |
| 27 LoadBufferObject(frame_ptr.value(), | |
| 28 StandardFrameConstants::kFunctionOffset, | |
| 29 MachineType::Pointer()))); | |
| 30 Variable argument_count(this, ParameterRepresentation(mode)); | |
| 31 VariableList list({&frame_ptr, &argument_count}, zone()); | |
| 32 Label done_argument_count(this, list); | |
| 33 | |
| 34 // Determine the number of passed parameters, which is either the count stored | |
| 35 // in an arguments adapter frame or fetched from the shared function info. | |
| 36 Node* frame_ptr_above = LoadBufferObject( | |
| 37 frame_ptr.value(), StandardFrameConstants::kCallerFPOffset, | |
| 38 MachineType::Pointer()); | |
| 39 Node* shared = | |
| 40 LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset); | |
| 41 Node* formal_parameter_count = LoadSharedFunctionInfoSpecialField( | |
| 42 shared, SharedFunctionInfo::kFormalParameterCountOffset, mode); | |
| 43 argument_count.Bind(formal_parameter_count); | |
| 44 Node* marker_or_function = LoadBufferObject( | |
| 45 frame_ptr_above, CommonFrameConstants::kContextOrFrameTypeOffset); | |
| 46 GotoIf( | |
| 47 MarkerIsNotFrameType(marker_or_function, StackFrame::ARGUMENTS_ADAPTOR), | |
| 48 &done_argument_count); | |
| 49 Node* adapted_parameter_count = LoadBufferObject( | |
| 50 frame_ptr_above, ArgumentsAdaptorFrameConstants::kLengthOffset); | |
| 51 frame_ptr.Bind(frame_ptr_above); | |
| 52 argument_count.Bind(TaggedToParameter(adapted_parameter_count, mode)); | |
| 53 Goto(&done_argument_count); | |
| 54 | |
| 55 Bind(&done_argument_count); | |
| 56 return std::tuple<Node*, Node*, Node*>( | |
| 57 frame_ptr.value(), argument_count.value(), formal_parameter_count); | |
| 58 } | |
| 59 | |
| 60 std::tuple<Node*, Node*, Node*> | |
| 61 ArgumentsBuiltinsAssembler::AllocateArgumentsObject(Node* map, | |
| 62 Node* arguments_count, | |
| 63 Node* parameter_map_count, | |
| 64 ParameterMode mode, | |
| 65 int base_size) { | |
| 66 // Allocate the parameter object (either a Rest parameter object, a strict | |
| 67 // argument object or a sloppy arguments object) and the elements/mapped | |
| 68 // arguments together. | |
| 69 int elements_offset = base_size; | |
| 70 Node* element_count = arguments_count; | |
| 71 if (parameter_map_count != nullptr) { | |
| 72 base_size += FixedArray::kHeaderSize; | |
| 73 element_count = IntPtrOrSmiAdd(element_count, parameter_map_count, mode); | |
| 74 } | |
| 75 bool empty = IsIntPtrOrSmiConstantZero(arguments_count); | |
| 76 DCHECK_IMPLIES(empty, parameter_map_count == nullptr); | |
| 77 Node* size = | |
| 78 empty ? IntPtrConstant(base_size) | |
| 79 : ElementOffsetFromIndex(element_count, FAST_ELEMENTS, mode, | |
| 80 base_size + FixedArray::kHeaderSize); | |
| 81 Node* result = Allocate(size); | |
| 82 Comment("Initialize arguments object"); | |
| 83 StoreMapNoWriteBarrier(result, map); | |
| 84 Node* empty_fixed_array = LoadRoot(Heap::kEmptyFixedArrayRootIndex); | |
| 85 StoreObjectField(result, JSArray::kPropertiesOffset, empty_fixed_array); | |
| 86 Node* smi_arguments_count = ParameterToTagged(arguments_count, mode); | |
| 87 StoreObjectFieldNoWriteBarrier(result, JSArray::kLengthOffset, | |
| 88 smi_arguments_count); | |
| 89 Node* arguments = nullptr; | |
| 90 if (!empty) { | |
| 91 arguments = InnerAllocate(result, elements_offset); | |
| 92 StoreObjectFieldNoWriteBarrier(arguments, FixedArray::kLengthOffset, | |
| 93 smi_arguments_count); | |
| 94 Node* fixed_array_map = LoadRoot(Heap::kFixedArrayMapRootIndex); | |
| 95 StoreMapNoWriteBarrier(arguments, fixed_array_map); | |
| 96 } | |
| 97 Node* parameter_map = nullptr; | |
| 98 if (parameter_map_count != nullptr) { | |
| 99 Node* parameter_map_offset = ElementOffsetFromIndex( | |
| 100 arguments_count, FAST_ELEMENTS, mode, FixedArray::kHeaderSize); | |
| 101 parameter_map = InnerAllocate(arguments, parameter_map_offset); | |
| 102 StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset, | |
| 103 parameter_map); | |
| 104 Node* sloppy_elements_map = | |
| 105 LoadRoot(Heap::kSloppyArgumentsElementsMapRootIndex); | |
| 106 StoreMapNoWriteBarrier(parameter_map, sloppy_elements_map); | |
| 107 parameter_map_count = ParameterToTagged(parameter_map_count, mode); | |
| 108 StoreObjectFieldNoWriteBarrier(parameter_map, FixedArray::kLengthOffset, | |
| 109 parameter_map_count); | |
| 110 } else { | |
| 111 if (empty) { | |
| 112 StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset, | |
| 113 empty_fixed_array); | |
| 114 } else { | |
| 115 StoreObjectFieldNoWriteBarrier(result, JSArray::kElementsOffset, | |
| 116 arguments); | |
| 117 } | |
| 118 } | |
| 119 return std::tuple<Node*, Node*, Node*>(result, arguments, parameter_map); | |
| 120 } | |
| 121 | |
| 122 Node* ArgumentsBuiltinsAssembler::ConstructParametersObjectFromArgs( | |
| 123 Node* map, Node* frame_ptr, Node* arg_count, Node* first_arg, | |
| 124 Node* rest_count, ParameterMode param_mode, int base_size) { | |
| 125 // Allocate the parameter object (either a Rest parameter object, a strict | |
| 126 // argument object or a sloppy arguments object) and the elements together and | |
| 127 // fill in the contents with the arguments above |formal_parameter_count|. | |
| 128 Node* result; | |
| 129 Node* elements; | |
| 130 Node* unused; | |
| 131 std::tie(result, elements, unused) = | |
| 132 AllocateArgumentsObject(map, rest_count, nullptr, param_mode, base_size); | |
| 133 DCHECK(unused == nullptr); | |
| 134 CodeStubArguments arguments(this, arg_count, frame_ptr, param_mode); | |
| 135 Variable offset(this, MachineType::PointerRepresentation()); | |
| 136 offset.Bind(IntPtrConstant(FixedArrayBase::kHeaderSize - kHeapObjectTag)); | |
| 137 VariableList list({&offset}, zone()); | |
| 138 arguments.ForEach(list, | |
| 139 [this, elements, &offset](Node* arg) { | |
| 140 StoreNoWriteBarrier(MachineRepresentation::kTagged, | |
| 141 elements, offset.value(), arg); | |
| 142 Increment(offset, kPointerSize); | |
| 143 }, | |
| 144 first_arg, nullptr, param_mode); | |
| 145 return result; | |
| 146 } | |
| 147 | |
| 148 Node* ArgumentsBuiltinsAssembler::EmitFastNewRestParameter(Node* context, | |
| 149 Node* function) { | |
| 150 Node* frame_ptr; | |
| 151 Node* argument_count; | |
| 152 Node* formal_parameter_count; | |
| 153 | |
| 154 ParameterMode mode = OptimalParameterMode(); | |
| 155 Node* zero = IntPtrOrSmiConstant(0, mode); | |
| 156 | |
| 157 std::tie(frame_ptr, argument_count, formal_parameter_count) = | |
| 158 GetArgumentsFrameAndCount(function, mode); | |
| 159 | |
| 160 Variable result(this, MachineRepresentation::kTagged); | |
| 161 Label no_rest_parameters(this), runtime(this, Label::kDeferred), | |
| 162 done(this, &result); | |
| 163 | |
| 164 Node* rest_count = | |
| 165 IntPtrOrSmiSub(argument_count, formal_parameter_count, mode); | |
| 166 Node* const native_context = LoadNativeContext(context); | |
| 167 Node* const array_map = LoadJSArrayElementsMap(FAST_ELEMENTS, native_context); | |
| 168 GotoIf(IntPtrOrSmiLessThanOrEqual(rest_count, zero, mode), | |
| 169 &no_rest_parameters); | |
| 170 | |
| 171 GotoIfFixedArraySizeDoesntFitInNewSpace( | |
| 172 rest_count, &runtime, JSArray::kSize + FixedArray::kHeaderSize, mode); | |
| 173 | |
| 174 // Allocate the Rest JSArray and the elements together and fill in the | |
| 175 // contents with the arguments above |formal_parameter_count|. | |
| 176 result.Bind(ConstructParametersObjectFromArgs( | |
| 177 array_map, frame_ptr, argument_count, formal_parameter_count, rest_count, | |
| 178 mode, JSArray::kSize)); | |
| 179 Goto(&done); | |
| 180 | |
| 181 Bind(&no_rest_parameters); | |
| 182 { | |
| 183 Node* arguments; | |
| 184 Node* elements; | |
| 185 Node* unused; | |
| 186 std::tie(arguments, elements, unused) = | |
| 187 AllocateArgumentsObject(array_map, zero, nullptr, mode, JSArray::kSize); | |
| 188 result.Bind(arguments); | |
| 189 Goto(&done); | |
| 190 } | |
| 191 | |
| 192 Bind(&runtime); | |
| 193 { | |
| 194 result.Bind(CallRuntime(Runtime::kNewRestParameter, context, function)); | |
| 195 Goto(&done); | |
| 196 } | |
| 197 | |
| 198 Bind(&done); | |
| 199 return result.value(); | |
| 200 } | |
| 201 | |
| 202 TF_BUILTIN(FastNewRestParameter, ArgumentsBuiltinsAssembler) { | |
| 203 Node* function = Parameter(FastNewArgumentsDescriptor::kFunction); | |
| 204 Node* context = Parameter(FastNewArgumentsDescriptor::kContext); | |
| 205 Return(EmitFastNewRestParameter(context, function)); | |
| 206 } | |
| 207 | |
| 208 Node* ArgumentsBuiltinsAssembler::EmitFastNewStrictArguments(Node* context, | |
| 209 Node* function) { | |
| 210 Variable result(this, MachineRepresentation::kTagged); | |
| 211 Label done(this, &result), empty(this), runtime(this, Label::kDeferred); | |
| 212 | |
| 213 Node* frame_ptr; | |
| 214 Node* argument_count; | |
| 215 Node* formal_parameter_count; | |
| 216 | |
| 217 ParameterMode mode = OptimalParameterMode(); | |
| 218 Node* zero = IntPtrOrSmiConstant(0, mode); | |
| 219 | |
| 220 std::tie(frame_ptr, argument_count, formal_parameter_count) = | |
| 221 GetArgumentsFrameAndCount(function, mode); | |
| 222 | |
| 223 GotoIfFixedArraySizeDoesntFitInNewSpace( | |
| 224 argument_count, &runtime, | |
| 225 JSStrictArgumentsObject::kSize + FixedArray::kHeaderSize, mode); | |
| 226 | |
| 227 Node* const native_context = LoadNativeContext(context); | |
| 228 Node* const map = | |
| 229 LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX); | |
| 230 GotoIf(WordEqual(argument_count, zero), &empty); | |
| 231 | |
| 232 result.Bind(ConstructParametersObjectFromArgs( | |
| 233 map, frame_ptr, argument_count, zero, argument_count, mode, | |
| 234 JSStrictArgumentsObject::kSize)); | |
| 235 Goto(&done); | |
| 236 | |
| 237 Bind(&empty); | |
| 238 { | |
| 239 Node* arguments; | |
| 240 Node* elements; | |
| 241 Node* unused; | |
| 242 std::tie(arguments, elements, unused) = AllocateArgumentsObject( | |
| 243 map, zero, nullptr, mode, JSStrictArgumentsObject::kSize); | |
| 244 result.Bind(arguments); | |
| 245 Goto(&done); | |
| 246 } | |
| 247 | |
| 248 Bind(&runtime); | |
| 249 { | |
| 250 result.Bind(CallRuntime(Runtime::kNewStrictArguments, context, function)); | |
| 251 Goto(&done); | |
| 252 } | |
| 253 | |
| 254 Bind(&done); | |
| 255 return result.value(); | |
| 256 } | |
| 257 | |
| 258 TF_BUILTIN(FastNewStrictArguments, ArgumentsBuiltinsAssembler) { | |
| 259 Node* function = Parameter(FastNewArgumentsDescriptor::kFunction); | |
| 260 Node* context = Parameter(FastNewArgumentsDescriptor::kContext); | |
| 261 Return(EmitFastNewStrictArguments(context, function)); | |
| 262 } | |
| 263 | |
| 264 Node* ArgumentsBuiltinsAssembler::EmitFastNewSloppyArguments(Node* context, | |
| 265 Node* function) { | |
| 266 Node* frame_ptr; | |
| 267 Node* argument_count; | |
| 268 Node* formal_parameter_count; | |
| 269 Variable result(this, MachineRepresentation::kTagged); | |
| 270 | |
| 271 ParameterMode mode = OptimalParameterMode(); | |
| 272 Node* zero = IntPtrOrSmiConstant(0, mode); | |
| 273 | |
| 274 Label done(this, &result), empty(this), no_parameters(this), | |
| 275 runtime(this, Label::kDeferred); | |
| 276 | |
| 277 std::tie(frame_ptr, argument_count, formal_parameter_count) = | |
| 278 GetArgumentsFrameAndCount(function, mode); | |
| 279 | |
| 280 GotoIf(WordEqual(argument_count, zero), &empty); | |
| 281 | |
| 282 GotoIf(WordEqual(formal_parameter_count, zero), &no_parameters); | |
| 283 | |
| 284 { | |
| 285 Comment("Mapped parameter JSSloppyArgumentsObject"); | |
| 286 | |
| 287 Node* mapped_count = | |
| 288 IntPtrOrSmiMin(argument_count, formal_parameter_count, mode); | |
| 289 | |
| 290 Node* parameter_map_size = | |
| 291 IntPtrOrSmiAdd(mapped_count, IntPtrOrSmiConstant(2, mode), mode); | |
| 292 | |
| 293 // Verify that the overall allocation will fit in new space. | |
| 294 Node* elements_allocated = | |
| 295 IntPtrOrSmiAdd(argument_count, parameter_map_size, mode); | |
| 296 GotoIfFixedArraySizeDoesntFitInNewSpace( | |
| 297 elements_allocated, &runtime, | |
| 298 JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize * 2, mode); | |
| 299 | |
| 300 Node* const native_context = LoadNativeContext(context); | |
| 301 Node* const map = LoadContextElement( | |
| 302 native_context, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX); | |
| 303 Node* argument_object; | |
| 304 Node* elements; | |
| 305 Node* map_array; | |
| 306 std::tie(argument_object, elements, map_array) = | |
| 307 AllocateArgumentsObject(map, argument_count, parameter_map_size, mode, | |
| 308 JSSloppyArgumentsObject::kSize); | |
| 309 StoreObjectFieldNoWriteBarrier( | |
| 310 argument_object, JSSloppyArgumentsObject::kCalleeOffset, function); | |
| 311 StoreFixedArrayElement(map_array, 0, context, SKIP_WRITE_BARRIER); | |
| 312 StoreFixedArrayElement(map_array, 1, elements, SKIP_WRITE_BARRIER); | |
| 313 | |
| 314 Comment("Fill in non-mapped parameters"); | |
| 315 Node* argument_offset = | |
| 316 ElementOffsetFromIndex(argument_count, FAST_ELEMENTS, mode, | |
| 317 FixedArray::kHeaderSize - kHeapObjectTag); | |
| 318 Node* mapped_offset = | |
| 319 ElementOffsetFromIndex(mapped_count, FAST_ELEMENTS, mode, | |
| 320 FixedArray::kHeaderSize - kHeapObjectTag); | |
| 321 CodeStubArguments arguments(this, argument_count, frame_ptr, mode); | |
| 322 Variable current_argument(this, MachineType::PointerRepresentation()); | |
| 323 current_argument.Bind(arguments.AtIndexPtr(argument_count, mode)); | |
| 324 VariableList var_list1({¤t_argument}, zone()); | |
| 325 mapped_offset = BuildFastLoop( | |
| 326 var_list1, argument_offset, mapped_offset, | |
| 327 [this, elements, ¤t_argument](Node* offset) { | |
| 328 Increment(current_argument, kPointerSize); | |
| 329 Node* arg = LoadBufferObject(current_argument.value(), 0); | |
| 330 StoreNoWriteBarrier(MachineRepresentation::kTagged, elements, offset, | |
| 331 arg); | |
| 332 }, | |
| 333 -kPointerSize, INTPTR_PARAMETERS); | |
| 334 | |
| 335 // Copy the parameter slots and the holes in the arguments. | |
| 336 // We need to fill in mapped_count slots. They index the context, | |
| 337 // where parameters are stored in reverse order, at | |
| 338 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+argument_count-1 | |
| 339 // The mapped parameter thus need to get indices | |
| 340 // MIN_CONTEXT_SLOTS+parameter_count-1 .. | |
| 341 // MIN_CONTEXT_SLOTS+argument_count-mapped_count | |
| 342 // We loop from right to left. | |
| 343 Comment("Fill in mapped parameters"); | |
| 344 Variable context_index(this, OptimalParameterRepresentation()); | |
| 345 context_index.Bind(IntPtrOrSmiSub( | |
| 346 IntPtrOrSmiAdd(IntPtrOrSmiConstant(Context::MIN_CONTEXT_SLOTS, mode), | |
| 347 formal_parameter_count, mode), | |
| 348 mapped_count, mode)); | |
| 349 Node* the_hole = TheHoleConstant(); | |
| 350 VariableList var_list2({&context_index}, zone()); | |
| 351 const int kParameterMapHeaderSize = | |
| 352 FixedArray::kHeaderSize + 2 * kPointerSize; | |
| 353 Node* adjusted_map_array = IntPtrAdd( | |
| 354 BitcastTaggedToWord(map_array), | |
| 355 IntPtrConstant(kParameterMapHeaderSize - FixedArray::kHeaderSize)); | |
| 356 Node* zero_offset = ElementOffsetFromIndex( | |
| 357 zero, FAST_ELEMENTS, mode, FixedArray::kHeaderSize - kHeapObjectTag); | |
| 358 BuildFastLoop(var_list2, mapped_offset, zero_offset, | |
| 359 [this, the_hole, elements, adjusted_map_array, &context_index, | |
| 360 mode](Node* offset) { | |
| 361 StoreNoWriteBarrier(MachineRepresentation::kTagged, | |
| 362 elements, offset, the_hole); | |
| 363 StoreNoWriteBarrier( | |
| 364 MachineRepresentation::kTagged, adjusted_map_array, | |
| 365 offset, ParameterToTagged(context_index.value(), mode)); | |
| 366 Increment(context_index, 1, mode); | |
| 367 }, | |
| 368 -kPointerSize, INTPTR_PARAMETERS); | |
| 369 | |
| 370 result.Bind(argument_object); | |
| 371 Goto(&done); | |
| 372 } | |
| 373 | |
| 374 Bind(&no_parameters); | |
| 375 { | |
| 376 Comment("No parameters JSSloppyArgumentsObject"); | |
| 377 GotoIfFixedArraySizeDoesntFitInNewSpace( | |
| 378 argument_count, &runtime, | |
| 379 JSSloppyArgumentsObject::kSize + FixedArray::kHeaderSize, mode); | |
| 380 Node* const native_context = LoadNativeContext(context); | |
| 381 Node* const map = | |
| 382 LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX); | |
| 383 result.Bind(ConstructParametersObjectFromArgs( | |
| 384 map, frame_ptr, argument_count, zero, argument_count, mode, | |
| 385 JSSloppyArgumentsObject::kSize)); | |
| 386 StoreObjectFieldNoWriteBarrier( | |
| 387 result.value(), JSSloppyArgumentsObject::kCalleeOffset, function); | |
| 388 Goto(&done); | |
| 389 } | |
| 390 | |
| 391 Bind(&empty); | |
| 392 { | |
| 393 Comment("Empty JSSloppyArgumentsObject"); | |
| 394 Node* const native_context = LoadNativeContext(context); | |
| 395 Node* const map = | |
| 396 LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX); | |
| 397 Node* arguments; | |
| 398 Node* elements; | |
| 399 Node* unused; | |
| 400 std::tie(arguments, elements, unused) = AllocateArgumentsObject( | |
| 401 map, zero, nullptr, mode, JSSloppyArgumentsObject::kSize); | |
| 402 result.Bind(arguments); | |
| 403 StoreObjectFieldNoWriteBarrier( | |
| 404 result.value(), JSSloppyArgumentsObject::kCalleeOffset, function); | |
| 405 Goto(&done); | |
| 406 } | |
| 407 | |
| 408 Bind(&runtime); | |
| 409 { | |
| 410 result.Bind(CallRuntime(Runtime::kNewSloppyArguments, context, function)); | |
| 411 Goto(&done); | |
| 412 } | |
| 413 | |
| 414 Bind(&done); | |
| 415 return result.value(); | |
| 416 } | |
| 417 | |
| 418 TF_BUILTIN(FastNewSloppyArguments, ArgumentsBuiltinsAssembler) { | |
| 419 Node* function = Parameter(FastNewArgumentsDescriptor::kFunction); | |
| 420 Node* context = Parameter(FastNewArgumentsDescriptor::kContext); | |
| 421 Return(EmitFastNewSloppyArguments(context, function)); | |
| 422 } | |
| 423 | |
| 424 } // namespace internal | |
| 425 } // namespace v8 | |
| OLD | NEW |