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