// Copyright 2019 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @generateCppClass extern class JSArgumentsObject extends JSObject { } type JSArgumentsObjectWithLength = JSSloppyArgumentsObject|JSStrictArgumentsObject; @export macro IsJSArgumentsObjectWithLength(implicit context: Context)(o: Object): bool { return Is<JSArgumentsObjectWithLength>(o); } // Just a starting shape for JSObject; properties can move after initialization. extern shape JSSloppyArgumentsObject extends JSArgumentsObject { length: JSAny; callee: JSAny; } // Just a starting shape for JSObject; properties can move after initialization. extern shape JSStrictArgumentsObject extends JSArgumentsObject { length: JSAny; } type SloppyArgumentsElements extends FixedArray; @generateCppClass extern class AliasedArgumentsEntry extends Struct { aliased_context_slot: Smi; } // TODO(danno): This should be a namespace {} once supported namespace arguments { macro NewJSStrictArgumentsObject(implicit context: Context)( elements: FixedArray): JSStrictArgumentsObject { const map = GetStrictArgumentsMap(); return new JSStrictArgumentsObject{ map, properties_or_hash: kEmptyFixedArray, elements, length: elements.length }; } macro NewJSSloppyArgumentsObject(implicit context: Context)( elements: FixedArray, callee: JSFunction): JSSloppyArgumentsObject { const map = GetSloppyArgumentsMap(); return new JSSloppyArgumentsObject{ map, properties_or_hash: kEmptyFixedArray, elements, length: elements.length, callee }; } macro NewJSFastAliasedArgumentsObject(implicit context: Context)( elements: FixedArray, length: Smi, callee: JSFunction): JSSloppyArgumentsObject { // TODO(danno): FastAliasedArguments should really be a type for itself const map = GetFastAliasedArgumentsMap(); return new JSSloppyArgumentsObject{ map, properties_or_hash: kEmptyFixedArray, elements, length, callee }; } struct ParameterMapIterator { macro Next(): Object labels NoMore { const currentMapSlotCopy = this.currentMapSlot++; if (currentMapSlotCopy > 1) { if (this.currentIndex == this.endInterationIndex) goto NoMore; this.currentIndex--; return Convert<Smi>(this.currentIndex); } else if (currentMapSlotCopy == 0) { return this.context; } else { assert(currentMapSlotCopy == 1); return this.elements; } } const context: Context; const elements: FixedArray; currentIndex: intptr; const endInterationIndex: intptr; currentMapSlot: intptr; } macro NewParameterMapIterator( context: Context, elements: FixedArray, formalParameterCount: intptr, mappedCount: intptr): ParameterMapIterator { const flags = context.scope_info.flags; let contextHeaderSize: intptr = MIN_CONTEXT_SLOTS; if (flags.has_context_extension_slot) ++contextHeaderSize; // Copy the parameter slots and the holes in the arguments. // We need to fill in mapped_count slots. They index the context, // where parameters are stored in reverse order, at // context_header_size .. context_header_size+argument_count-1 // The mapped parameter thus need to get indices // context_header_size+parameter_count-1 .. // context_header_size+argument_count-mapped_count // We loop from right to left. const afterLastContextIndex = contextHeaderSize + formalParameterCount; const firstContextIndex = afterLastContextIndex - mappedCount; return ParameterMapIterator{ context, elements, currentIndex: afterLastContextIndex, endInterationIndex: firstContextIndex, currentMapSlot: 0 }; } struct ParameterValueIterator { macro Next(): Object labels NoMore() { if (this.mapped_count != 0) { this.mapped_count--; return TheHole; } if (this.current == this.arguments.length) goto NoMore; return this.arguments[this.current++]; } mapped_count: intptr; const arguments: Arguments; current: intptr; } macro NewParameterValueIterator(mappedCount: intptr, arguments: Arguments): ParameterValueIterator { return ParameterValueIterator{ mapped_count: mappedCount, arguments, current: mappedCount }; } macro NewAllArguments(implicit context: Context)( frame: FrameWithArguments, argumentCount: intptr): JSArray { const map = GetFastPackedElementsJSArrayMap(); const arguments = GetFrameArguments(frame, argumentCount); const it = ArgumentsIterator{arguments, current: 0}; const elements = NewFixedArray(argumentCount, it); return NewJSArray(map, elements); } macro NewRestArguments(implicit context: Context)(info: FrameWithArgumentsInfo): JSArray { const argumentCount = Convert<intptr>(info.argument_count); const formalParameterCount = Convert<intptr>(info.formal_parameter_count); const map = GetFastPackedElementsJSArrayMap(); const length = (formalParameterCount >= argumentCount) ? 0 : argumentCount - formalParameterCount; const arguments = GetFrameArguments(info.frame, argumentCount); const it = ArgumentsIterator{arguments, current: formalParameterCount}; const elements = NewFixedArray(length, it); return NewJSArray(map, elements); } macro NewStrictArguments(implicit context: Context)( info: FrameWithArgumentsInfo): JSStrictArgumentsObject { const argumentCount = Convert<intptr>(info.argument_count); const arguments = GetFrameArguments(info.frame, argumentCount); const it = ArgumentsIterator{arguments, current: 0}; const elements = NewFixedArray(argumentCount, it); return NewJSStrictArgumentsObject(elements); } macro NewSloppyArguments(implicit context: Context)( info: FrameWithArgumentsInfo, callee: JSFunction): JSSloppyArgumentsObject { const argumentCount = Convert<intptr>(info.argument_count); const arguments = GetFrameArguments(info.frame, argumentCount); const formalParameterCount = Convert<intptr>(info.formal_parameter_count); if (formalParameterCount == 0) { const it = ArgumentsIterator{arguments, current: 0}; const elements = NewFixedArray(argumentCount, it); return NewJSSloppyArgumentsObject(elements, callee); } const mappedCount = IntPtrMin(formalParameterCount, argumentCount); const it = NewParameterValueIterator(mappedCount, arguments); const parameterValues = NewFixedArray(argumentCount, it); let paramIter = NewParameterMapIterator( context, parameterValues, formalParameterCount, mappedCount); const elementsLength = Convert<Smi>(mappedCount + kSloppyArgumentsParameterMapStart); const map = kSloppyArgumentsElementsMap; const elements = new FixedArray{map, length: elementsLength, objects: ...paramIter}; const length = Convert<Smi>(argumentCount); return NewJSFastAliasedArgumentsObject(elements, length, callee); } } @export macro EmitFastNewAllArguments(implicit context: Context)( frame: FrameWithArguments, argc: intptr): JSArray { return arguments::NewAllArguments(frame, argc); } @export macro EmitFastNewRestArguments(implicit context: Context)(_f: JSFunction): JSArray { const info = GetFrameWithArgumentsInfo(); return arguments::NewRestArguments(info); } @export macro EmitFastNewStrictArguments(implicit context: Context)(_f: JSFunction): JSStrictArgumentsObject { const info = GetFrameWithArgumentsInfo(); return arguments::NewStrictArguments(info); } @export macro EmitFastNewSloppyArguments(implicit context: Context)(f: JSFunction): JSSloppyArgumentsObject { const info = GetFrameWithArgumentsInfo(); return arguments::NewSloppyArguments(info, f); }