| // Copyright 2018 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. |
| |
| type FrameType extends Smi constexpr 'StackFrame::Type'; |
| const ARGUMENTS_ADAPTOR_FRAME: constexpr FrameType |
| generates 'StackFrame::ARGUMENTS_ADAPTOR'; |
| const STUB_FRAME: constexpr FrameType |
| generates 'StackFrame::STUB'; |
| const kFrameTypeCount: |
| constexpr int31 generates 'StackFrame::NUMBER_OF_TYPES'; |
| |
| FromConstexpr<FrameType, constexpr FrameType>(t: constexpr FrameType): |
| FrameType { |
| // Note that althought FrameTypes sometimes masquerade as Smis (their |
| // LSB is a zero), they are not. For efficiency in storing them as a |
| // constant into a frame, they are simply the FrameType value shifted |
| // up by a single bit. |
| const i: constexpr uintptr = %RawConstexprCast<constexpr uintptr>(t) |
| << kSmiTagSize; |
| return %RawDownCast<FrameType>(BitcastWordToTaggedSigned(i)); |
| } |
| Cast<FrameType>(o: Object): FrameType |
| labels CastError { |
| if (TaggedIsNotSmi(o)) goto CastError; |
| assert( |
| Convert<int32>(BitcastTaggedToWordForTagAndSmiBits(o)) < |
| Convert<int32>(kFrameTypeCount << kSmiTagSize)); |
| return %RawDownCast<FrameType>(o); |
| } |
| |
| type FrameBase extends RawPtr constexpr 'void*'; |
| type StandardFrame extends FrameBase constexpr 'void*'; |
| type ArgumentsAdaptorFrame extends FrameBase constexpr 'void*'; |
| type StubFrame extends FrameBase constexpr 'void*'; |
| type FrameWithArguments = StandardFrame|ArgumentsAdaptorFrame; |
| type Frame = FrameWithArguments|StubFrame; |
| |
| extern macro LoadFramePointer(): Frame; |
| extern macro LoadParentFramePointer(): Frame; |
| |
| // Load values from a specified frame by given offset in bytes. |
| macro LoadObjectFromFrame(f: Frame, o: constexpr int32): Object { |
| return LoadBufferObject(f, o); |
| } |
| macro LoadPointerFromFrame(f: Frame, o: constexpr int32): RawPtr { |
| return LoadBufferPointer(f, o); |
| } |
| macro LoadSmiFromFrame(f: Frame, o: constexpr int32): Smi { |
| return LoadBufferSmi(f, o); |
| } |
| macro LoadIntptrFromFrame(f: Frame, o: constexpr int32): intptr { |
| return LoadBufferIntptr(f, o); |
| } |
| |
| const kStandardFrameFunctionOffset: constexpr int31 |
| generates 'StandardFrameConstants::kFunctionOffset'; |
| operator '.function' macro LoadFunctionFromFrame(f: Frame): JSFunction { |
| // TODO(danno): Use RawDownCast here in order to avoid passing the implicit |
| // context, since this accessor is used in legacy CSA code through |
| // LoadTargetFromFrame |
| const result: Object = LoadObjectFromFrame(f, kStandardFrameFunctionOffset); |
| return %RawDownCast<JSFunction>(result); |
| } |
| |
| const kStandardFrameCallerFPOffset: constexpr int31 |
| generates 'StandardFrameConstants::kCallerFPOffset'; |
| operator '.caller' macro LoadCallerFromFrame(f: Frame): Frame { |
| const result: RawPtr = LoadPointerFromFrame(f, kStandardFrameCallerFPOffset); |
| return %RawDownCast<Frame>(result); |
| } |
| |
| const kStandardFrameArgCOffset: constexpr int31 |
| generates 'StandardFrameConstants::kArgCOffset'; |
| operator '.argument_count' macro LoadArgCFromFrame(f: Frame): intptr { |
| return LoadIntptrFromFrame(f, kStandardFrameArgCOffset); |
| } |
| |
| type ContextOrFrameType = Context|FrameType; |
| Cast<ContextOrFrameType>(implicit context: Context)(o: Object): |
| ContextOrFrameType |
| labels CastError { |
| typeswitch (o) { |
| case (c: Context): { |
| return c; |
| } |
| case (t: FrameType): { |
| return t; |
| } |
| case (Object): { |
| goto CastError; |
| } |
| } |
| } |
| |
| const kStandardFrameContextOrFrameTypeOffset: constexpr int31 |
| generates 'StandardFrameConstants::kContextOrFrameTypeOffset'; |
| operator '.context_or_frame_type' |
| macro LoadContextOrFrameTypeFromFrame(implicit context: Context)(f: Frame): |
| ContextOrFrameType { |
| return UnsafeCast<ContextOrFrameType>( |
| LoadObjectFromFrame(f, kStandardFrameContextOrFrameTypeOffset)); |
| } |
| |
| const kArgumentsAdaptorFrameLengthOffset: constexpr int31 |
| generates 'ArgumentsAdaptorFrameConstants::kLengthOffset'; |
| operator '.length' |
| macro LoadLengthFromAdapterFrame(implicit context: Context)( |
| f: ArgumentsAdaptorFrame): Smi { |
| return LoadSmiFromFrame(f, kArgumentsAdaptorFrameLengthOffset); |
| } |
| |
| operator '==' macro FrameTypeEquals(f1: FrameType, f2: FrameType): bool { |
| return TaggedEqual(f1, f2); |
| } |
| |
| macro Cast<A : type extends Frame>(implicit context: Context)(o: Frame): |
| A labels CastError; |
| Cast<StandardFrame>(implicit context: Context)(f: Frame): |
| StandardFrame labels CastError { |
| const o: HeapObject = |
| Cast<HeapObject>(f.context_or_frame_type) otherwise CastError; |
| // StandardFrames (which include interpreted and JIT-compiled frames), |
| // unlike other frame types, don't have their own type marker stored in |
| // the frame, but rather have the function's context stored where the |
| // type marker is stored for other frame types. From Torque, it would |
| // be quite expensive to do the test required to distinguish interpreter |
| // frames from JITted ones (and other StandardFrame types), so |
| // StandardFrame is the level of granularity support when iterating the |
| // stack from generated code. |
| // See the descriptions and frame layouts in src/frame-constants.h. |
| if (IsContext(o)) { |
| return %RawDownCast<StandardFrame>(f); |
| } |
| goto CastError; |
| } |
| |
| Cast<ArgumentsAdaptorFrame>(implicit context: Context)(f: Frame): |
| ArgumentsAdaptorFrame labels CastError { |
| const t: FrameType = |
| Cast<FrameType>(f.context_or_frame_type) otherwise CastError; |
| if (t == ARGUMENTS_ADAPTOR_FRAME) { |
| return %RawDownCast<ArgumentsAdaptorFrame>(f); |
| } |
| goto CastError; |
| } |
| |
| // Load target function from the current JS frame. |
| // This is an alternative way of getting the target function in addition to |
| // Parameter(Descriptor::kJSTarget). The latter should be used near the |
| // beginning of builtin code while the target value is still in the register |
| // and the former should be used in slow paths in order to reduce register |
| // pressure on the fast path. |
| @export |
| macro LoadTargetFromFrame(): JSFunction { |
| return LoadFramePointer().function; |
| } |