// 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 generates 'TNode<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<uintptr>(BitcastTaggedToWord(o)) >>> kSmiTagSize) < kFrameTypeCount); return %RawDownCast<FrameType>(o); } type FrameBase extends RawPtr generates 'TNode<RawPtrT>' constexpr 'void*'; type StandardFrame extends FrameBase generates 'TNode<RawPtrT>' constexpr 'void*'; type ArgumentsAdaptorFrame extends FrameBase generates 'TNode<RawPtrT>' constexpr 'void*'; type StubFrame extends FrameBase generates 'TNode<RawPtrT>' constexpr 'void*'; type Frame = ArgumentsAdaptorFrame | StandardFrame | 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); } 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); } 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 WordEqual(f1, f2); } macro Cast<A: type>(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. macro LoadTargetFromFrame(): JSFunction { return LoadFramePointer().function; }