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.h"
6#include "src/builtins/builtins.h"
7#include "src/code-stub-assembler.h"
8#include "src/counters.h"
9#include "src/interface-descriptors.h"
10#include "src/macro-assembler.h"
11#include "src/objects-inl.h"
12
13namespace v8 {
14namespace internal {
15
16BUILTIN(Illegal) {
17  UNREACHABLE();
18  return isolate->heap()->undefined_value();  // Make compiler happy.
19}
20
21BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); }
22
23BUILTIN(UnsupportedThrower) {
24  HandleScope scope(isolate);
25  THROW_NEW_ERROR_RETURN_FAILURE(isolate,
26                                 NewError(MessageTemplate::kUnsupported));
27}
28
29// -----------------------------------------------------------------------------
30// Throwers for restricted function properties and strict arguments object
31// properties
32
33BUILTIN(RestrictedFunctionPropertiesThrower) {
34  HandleScope scope(isolate);
35  THROW_NEW_ERROR_RETURN_FAILURE(
36      isolate, NewTypeError(MessageTemplate::kRestrictedFunctionProperties));
37}
38
39BUILTIN(RestrictedStrictArgumentsPropertiesThrower) {
40  HandleScope scope(isolate);
41  THROW_NEW_ERROR_RETURN_FAILURE(
42      isolate, NewTypeError(MessageTemplate::kStrictPoisonPill));
43}
44
45// -----------------------------------------------------------------------------
46// Interrupt and stack checks.
47
48void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
49  masm->TailCallRuntime(Runtime::kInterrupt);
50}
51
52void Builtins::Generate_StackCheck(MacroAssembler* masm) {
53  masm->TailCallRuntime(Runtime::kStackGuard);
54}
55
56// -----------------------------------------------------------------------------
57// TurboFan support builtins.
58
59void Builtins::Generate_CopyFastSmiOrObjectElements(
60    compiler::CodeAssemblerState* state) {
61  typedef CodeStubAssembler::Label Label;
62  typedef compiler::Node Node;
63  typedef CopyFastSmiOrObjectElementsDescriptor Descriptor;
64  CodeStubAssembler assembler(state);
65
66  Node* object = assembler.Parameter(Descriptor::kObject);
67
68  // Load the {object}s elements.
69  Node* source = assembler.LoadObjectField(object, JSObject::kElementsOffset);
70
71  CodeStubAssembler::ParameterMode mode = assembler.OptimalParameterMode();
72  Node* length = assembler.TaggedToParameter(
73      assembler.LoadFixedArrayBaseLength(source), mode);
74
75  // Check if we can allocate in new space.
76  ElementsKind kind = FAST_ELEMENTS;
77  int max_elements = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind);
78  Label if_newspace(&assembler), if_oldspace(&assembler);
79  assembler.Branch(
80      assembler.UintPtrOrSmiLessThan(
81          length, assembler.IntPtrOrSmiConstant(max_elements, mode), mode),
82      &if_newspace, &if_oldspace);
83
84  assembler.Bind(&if_newspace);
85  {
86    Node* target = assembler.AllocateFixedArray(kind, length, mode);
87    assembler.CopyFixedArrayElements(kind, source, target, length,
88                                     SKIP_WRITE_BARRIER, mode);
89    assembler.StoreObjectField(object, JSObject::kElementsOffset, target);
90    assembler.Return(target);
91  }
92
93  assembler.Bind(&if_oldspace);
94  {
95    Node* target = assembler.AllocateFixedArray(kind, length, mode,
96                                                CodeStubAssembler::kPretenured);
97    assembler.CopyFixedArrayElements(kind, source, target, length,
98                                     UPDATE_WRITE_BARRIER, mode);
99    assembler.StoreObjectField(object, JSObject::kElementsOffset, target);
100    assembler.Return(target);
101  }
102}
103
104void Builtins::Generate_GrowFastDoubleElements(
105    compiler::CodeAssemblerState* state) {
106  typedef CodeStubAssembler::Label Label;
107  typedef compiler::Node Node;
108  typedef GrowArrayElementsDescriptor Descriptor;
109  CodeStubAssembler assembler(state);
110
111  Node* object = assembler.Parameter(Descriptor::kObject);
112  Node* key = assembler.Parameter(Descriptor::kKey);
113  Node* context = assembler.Parameter(Descriptor::kContext);
114
115  Label runtime(&assembler, CodeStubAssembler::Label::kDeferred);
116  Node* elements = assembler.LoadElements(object);
117  elements = assembler.TryGrowElementsCapacity(
118      object, elements, FAST_DOUBLE_ELEMENTS, key, &runtime);
119  assembler.Return(elements);
120
121  assembler.Bind(&runtime);
122  assembler.TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
123}
124
125void Builtins::Generate_GrowFastSmiOrObjectElements(
126    compiler::CodeAssemblerState* state) {
127  typedef CodeStubAssembler::Label Label;
128  typedef compiler::Node Node;
129  typedef GrowArrayElementsDescriptor Descriptor;
130  CodeStubAssembler assembler(state);
131
132  Node* object = assembler.Parameter(Descriptor::kObject);
133  Node* key = assembler.Parameter(Descriptor::kKey);
134  Node* context = assembler.Parameter(Descriptor::kContext);
135
136  Label runtime(&assembler, CodeStubAssembler::Label::kDeferred);
137  Node* elements = assembler.LoadElements(object);
138  elements = assembler.TryGrowElementsCapacity(object, elements, FAST_ELEMENTS,
139                                               key, &runtime);
140  assembler.Return(elements);
141
142  assembler.Bind(&runtime);
143  assembler.TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
144}
145
146namespace {
147
148void Generate_NewArgumentsElements(CodeStubAssembler* assembler,
149                                   compiler::Node* frame,
150                                   compiler::Node* length) {
151  typedef CodeStubAssembler::Label Label;
152  typedef CodeStubAssembler::Variable Variable;
153  typedef compiler::Node Node;
154
155  // Check if we can allocate in new space.
156  ElementsKind kind = FAST_ELEMENTS;
157  int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind);
158  Label if_newspace(assembler), if_oldspace(assembler, Label::kDeferred);
159  assembler->Branch(assembler->IntPtrLessThan(
160                        length, assembler->IntPtrConstant(max_elements)),
161                    &if_newspace, &if_oldspace);
162
163  assembler->Bind(&if_newspace);
164  {
165    // Prefer EmptyFixedArray in case of non-positive {length} (the {length}
166    // can be negative here for rest parameters).
167    Label if_empty(assembler), if_notempty(assembler);
168    assembler->Branch(
169        assembler->IntPtrLessThanOrEqual(length, assembler->IntPtrConstant(0)),
170        &if_empty, &if_notempty);
171
172    assembler->Bind(&if_empty);
173    assembler->Return(assembler->EmptyFixedArrayConstant());
174
175    assembler->Bind(&if_notempty);
176    {
177      // Allocate a FixedArray in new space.
178      Node* result = assembler->AllocateFixedArray(kind, length);
179
180      // Compute the effective {offset} into the {frame}.
181      Node* offset = assembler->IntPtrAdd(length, assembler->IntPtrConstant(1));
182
183      // Copy the parameters from {frame} (starting at {offset}) to {result}.
184      Variable var_index(assembler, MachineType::PointerRepresentation());
185      Label loop(assembler, &var_index), done_loop(assembler);
186      var_index.Bind(assembler->IntPtrConstant(0));
187      assembler->Goto(&loop);
188      assembler->Bind(&loop);
189      {
190        // Load the current {index}.
191        Node* index = var_index.value();
192
193        // Check if we are done.
194        assembler->GotoIf(assembler->WordEqual(index, length), &done_loop);
195
196        // Load the parameter at the given {index}.
197        Node* value = assembler->Load(
198            MachineType::AnyTagged(), frame,
199            assembler->WordShl(assembler->IntPtrSub(offset, index),
200                               assembler->IntPtrConstant(kPointerSizeLog2)));
201
202        // Store the {value} into the {result}.
203        assembler->StoreFixedArrayElement(result, index, value,
204                                          SKIP_WRITE_BARRIER);
205
206        // Continue with next {index}.
207        var_index.Bind(
208            assembler->IntPtrAdd(index, assembler->IntPtrConstant(1)));
209        assembler->Goto(&loop);
210      }
211
212      assembler->Bind(&done_loop);
213      assembler->Return(result);
214    }
215  }
216
217  assembler->Bind(&if_oldspace);
218  {
219    // Allocate in old space (or large object space).
220    assembler->TailCallRuntime(
221        Runtime::kNewArgumentsElements, assembler->NoContextConstant(),
222        assembler->BitcastWordToTagged(frame), assembler->SmiFromWord(length));
223  }
224}
225
226}  // namespace
227
228void Builtins::Generate_NewUnmappedArgumentsElements(
229    compiler::CodeAssemblerState* state) {
230  typedef CodeStubAssembler::Label Label;
231  typedef CodeStubAssembler::Variable Variable;
232  typedef compiler::Node Node;
233  typedef NewArgumentsElementsDescriptor Descriptor;
234  CodeStubAssembler assembler(state);
235
236  Node* formal_parameter_count =
237      assembler.Parameter(Descriptor::kFormalParameterCount);
238
239  // Determine the frame that holds the parameters.
240  Label done(&assembler);
241  Variable var_frame(&assembler, MachineType::PointerRepresentation()),
242      var_length(&assembler, MachineType::PointerRepresentation());
243  var_frame.Bind(assembler.LoadParentFramePointer());
244  var_length.Bind(formal_parameter_count);
245  Node* parent_frame = assembler.Load(
246      MachineType::Pointer(), var_frame.value(),
247      assembler.IntPtrConstant(StandardFrameConstants::kCallerFPOffset));
248  Node* parent_frame_type =
249      assembler.Load(MachineType::AnyTagged(), parent_frame,
250                     assembler.IntPtrConstant(
251                         CommonFrameConstants::kContextOrFrameTypeOffset));
252  assembler.GotoIfNot(assembler.MarkerIsFrameType(
253                          parent_frame_type, StackFrame::ARGUMENTS_ADAPTOR),
254                      &done);
255  {
256    // Determine the length from the ArgumentsAdaptorFrame.
257    Node* length = assembler.LoadAndUntagSmi(
258        parent_frame, ArgumentsAdaptorFrameConstants::kLengthOffset);
259
260    // Take the arguments from the ArgumentsAdaptorFrame.
261    var_frame.Bind(parent_frame);
262    var_length.Bind(length);
263  }
264  assembler.Goto(&done);
265
266  // Allocate the actual FixedArray for the elements.
267  assembler.Bind(&done);
268  Generate_NewArgumentsElements(&assembler, var_frame.value(),
269                                var_length.value());
270}
271
272void Builtins::Generate_NewRestParameterElements(
273    compiler::CodeAssemblerState* state) {
274  typedef CodeStubAssembler::Label Label;
275  typedef compiler::Node Node;
276  typedef NewArgumentsElementsDescriptor Descriptor;
277  CodeStubAssembler assembler(state);
278
279  Node* formal_parameter_count =
280      assembler.Parameter(Descriptor::kFormalParameterCount);
281
282  // Check if we have an ArgumentsAdaptorFrame, as we will only have rest
283  // parameters in that case.
284  Label if_empty(&assembler);
285  Node* frame = assembler.Load(
286      MachineType::Pointer(), assembler.LoadParentFramePointer(),
287      assembler.IntPtrConstant(StandardFrameConstants::kCallerFPOffset));
288  Node* frame_type =
289      assembler.Load(MachineType::AnyTagged(), frame,
290                     assembler.IntPtrConstant(
291                         CommonFrameConstants::kContextOrFrameTypeOffset));
292  assembler.GotoIfNot(
293      assembler.MarkerIsFrameType(frame_type, StackFrame::ARGUMENTS_ADAPTOR),
294      &if_empty);
295
296  // Determine the length from the ArgumentsAdaptorFrame.
297  Node* frame_length = assembler.LoadAndUntagSmi(
298      frame, ArgumentsAdaptorFrameConstants::kLengthOffset);
299
300  // Compute the actual rest parameter length (may be negative).
301  Node* length = assembler.IntPtrSub(frame_length, formal_parameter_count);
302
303  // Allocate the actual FixedArray for the elements.
304  Generate_NewArgumentsElements(&assembler, frame, length);
305
306  // No rest parameters, return an empty FixedArray.
307  assembler.Bind(&if_empty);
308  assembler.Return(assembler.EmptyFixedArrayConstant());
309}
310
311void Builtins::Generate_ReturnReceiver(compiler::CodeAssemblerState* state) {
312  CodeStubAssembler assembler(state);
313  assembler.Return(assembler.Parameter(0));
314}
315
316}  // namespace internal
317}  // namespace v8
318