Commit 6b7493a4 authored by jgruber's avatar jgruber Committed by Commit bot

Revert of Use a custom Struct for stack trace storage (patchset #4 id:60001 of...

Revert of Use a custom Struct for stack trace storage (patchset #4 id:60001 of https://codereview.chromium.org/2230953002/ )

Reason for revert:
Performance regressions in Gameboy, Life, CodeLoad and others. See crbug.com/638210.

Original issue's description:
> Refactor data structures for simple stack traces
>
> Simple stack traces are captured through Isolate::CaptureSimpleStackTrace.
> Captured frames are stored in a FixedArray, which in turn is stored as a
> property (using a private symbol) on the error object itself. Actual formatting
> of the textual stack trace is done lazily when the user reads the stack
> property of the error object.
>
> This would involve many conversions back and forth between index-encoded raw
> data (receiver, function, offset and code), JS CallSite objects, and C++
> CallSite objects.
>
> This commit refactors the C++ CallSite class into a Struct class called
> StackTraceFrame, which is the new single point of truth frame information.
> Isolate::CaptureSimpleStackTrace stores an array of StackTraceFrames, and JS
> CallSite objects (now created only when the user specifies custom stack trace
> formatting through Error.prepareStackTrace) internally only store a reference
> to a StackTraceFrame.
>
> BUG=
>
> Committed: https://crrev.com/b4c1aefb9c369f1a33a6ca94a5de9b06ea4bf5c4
> Cr-Commit-Position: refs/heads/master@{#38645}

TBR=yangguo@chromium.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=

Review-Url: https://codereview.chromium.org/2252783007
Cr-Commit-Position: refs/heads/master@{#38700}
parent 4ba00696
......@@ -7623,8 +7623,8 @@ class Internals {
static const int kNodeIsPartiallyDependentShift = 4;
static const int kNodeIsActiveShift = 4;
static const int kJSObjectType = 0xb8;
static const int kJSApiObjectType = 0xb7;
static const int kJSObjectType = 0xb7;
static const int kJSApiObjectType = 0xb6;
static const int kFirstNonstringType = 0x80;
static const int kOddballType = 0x83;
static const int kForeignType = 0x87;
......
......@@ -11,22 +11,15 @@
namespace v8 {
namespace internal {
#define CHECK_CALLSITE(recv, method) \
CHECK_RECEIVER(JSObject, recv, method); \
Handle<StackTraceFrame> frame; \
{ \
Handle<Object> frame_obj; \
ASSIGN_RETURN_FAILURE_ON_EXCEPTION( \
isolate, frame_obj, \
JSObject::GetProperty(recv, \
isolate->factory()->call_site_frame_symbol())); \
if (!frame_obj->IsStackTraceFrame()) { \
THROW_NEW_ERROR_RETURN_FAILURE( \
isolate, NewTypeError(MessageTemplate::kCallSiteMethod, \
isolate->factory()->NewStringFromAsciiChecked( \
method))); \
} \
frame = Handle<StackTraceFrame>::cast(frame_obj); \
#define CHECK_CALLSITE(recv, method) \
CHECK_RECEIVER(JSObject, recv, method); \
if (!JSReceiver::HasOwnProperty( \
recv, isolate->factory()->call_site_position_symbol()) \
.FromMaybe(false)) { \
THROW_NEW_ERROR_RETURN_FAILURE( \
isolate, \
NewTypeError(MessageTemplate::kCallSiteMethod, \
isolate->factory()->NewStringFromAsciiChecked(method))); \
}
namespace {
......@@ -41,107 +34,167 @@ Object* PositiveNumberOrNull(int value, Isolate* isolate) {
BUILTIN(CallSitePrototypeGetColumnNumber) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getColumnNumber");
return PositiveNumberOrNull(frame->GetColumnNumber(), isolate);
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return PositiveNumberOrNull(call_site.GetColumnNumber(), isolate);
}
BUILTIN(CallSitePrototypeGetEvalOrigin) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getEvalOrigin");
return *frame->GetEvalOrigin();
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return *call_site.GetEvalOrigin();
}
BUILTIN(CallSitePrototypeGetFileName) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getFileName");
return *frame->GetFileName();
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return *call_site.GetFileName();
}
namespace {
bool CallSiteIsStrict(Isolate* isolate, Handle<JSObject> receiver) {
Handle<Object> strict;
Handle<Symbol> symbol = isolate->factory()->call_site_strict_symbol();
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, strict,
JSObject::GetProperty(receiver, symbol));
return strict->BooleanValue();
}
} // namespace
BUILTIN(CallSitePrototypeGetFunction) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getFunction");
if (frame->IsStrict() || frame->IsWasmFrame()) {
if (CallSiteIsStrict(isolate, recv))
return *isolate->factory()->undefined_value();
}
return frame->function();
Handle<Symbol> symbol = isolate->factory()->call_site_function_symbol();
RETURN_RESULT_OR_FAILURE(isolate, JSObject::GetProperty(recv, symbol));
}
BUILTIN(CallSitePrototypeGetFunctionName) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getFunctionName");
return *frame->GetFunctionName();
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return *call_site.GetFunctionName();
}
BUILTIN(CallSitePrototypeGetLineNumber) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getLineNumber");
return PositiveNumberOrNull(frame->GetLineNumber(), isolate);
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
int line_number = call_site.IsWasm() ? call_site.wasm_func_index()
: call_site.GetLineNumber();
return PositiveNumberOrNull(line_number, isolate);
}
BUILTIN(CallSitePrototypeGetMethodName) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getMethodName");
return *frame->GetMethodName();
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return *call_site.GetMethodName();
}
BUILTIN(CallSitePrototypeGetPosition) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getPosition");
return Smi::FromInt(frame->GetPosition());
Handle<Symbol> symbol = isolate->factory()->call_site_position_symbol();
RETURN_RESULT_OR_FAILURE(isolate, JSObject::GetProperty(recv, symbol));
}
BUILTIN(CallSitePrototypeGetScriptNameOrSourceURL) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getScriptNameOrSourceUrl");
return *frame->GetScriptNameOrSourceUrl();
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return *call_site.GetScriptNameOrSourceUrl();
}
BUILTIN(CallSitePrototypeGetThis) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getThis");
if (frame->IsStrict() || frame->ForceConstructor() || frame->IsWasmFrame()) {
if (CallSiteIsStrict(isolate, recv))
return *isolate->factory()->undefined_value();
Handle<Object> receiver;
Handle<Symbol> symbol = isolate->factory()->call_site_receiver_symbol();
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
JSObject::GetProperty(recv, symbol));
if (*receiver == isolate->heap()->call_site_constructor_symbol())
return *isolate->factory()->undefined_value();
}
return frame->receiver();
return *receiver;
}
BUILTIN(CallSitePrototypeGetTypeName) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "getTypeName");
return *frame->GetTypeName();
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return *call_site.GetTypeName();
}
BUILTIN(CallSitePrototypeIsConstructor) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "isConstructor");
return isolate->heap()->ToBoolean(frame->IsConstructor());
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return isolate->heap()->ToBoolean(call_site.IsConstructor());
}
BUILTIN(CallSitePrototypeIsEval) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "isEval");
return isolate->heap()->ToBoolean(frame->IsEval());
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return isolate->heap()->ToBoolean(call_site.IsEval());
}
BUILTIN(CallSitePrototypeIsNative) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "isNative");
return isolate->heap()->ToBoolean(frame->IsNative());
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return isolate->heap()->ToBoolean(call_site.IsNative());
}
BUILTIN(CallSitePrototypeIsToplevel) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "isToplevel");
return isolate->heap()->ToBoolean(frame->IsToplevel());
CallSite call_site(isolate, recv);
CHECK(call_site.IsJavaScript() || call_site.IsWasm());
return isolate->heap()->ToBoolean(call_site.IsToplevel());
}
BUILTIN(CallSitePrototypeToString) {
HandleScope scope(isolate);
CHECK_CALLSITE(recv, "toString");
return *frame->ToString();
RETURN_RESULT_OR_FAILURE(isolate, CallSiteUtils::ToString(isolate, recv));
}
#undef CHECK_CALLSITE
......
......@@ -434,6 +434,31 @@ void StackGuard::InitThread(const ExecutionAccess& lock) {
// --- C a l l s t o n a t i v e s ---
Handle<String> Execution::GetStackTraceLine(Handle<Object> recv,
Handle<JSFunction> fun,
Handle<Object> pos,
Handle<Object> is_global) {
Isolate* isolate = fun->GetIsolate();
Handle<Object> strict_mode = isolate->factory()->ToBoolean(false);
MaybeHandle<Object> maybe_callsite =
CallSiteUtils::Construct(isolate, recv, fun, pos, strict_mode);
if (maybe_callsite.is_null()) {
isolate->clear_pending_exception();
return isolate->factory()->empty_string();
}
MaybeHandle<String> maybe_to_string =
CallSiteUtils::ToString(isolate, maybe_callsite.ToHandleChecked());
if (maybe_to_string.is_null()) {
isolate->clear_pending_exception();
return isolate->factory()->empty_string();
}
return maybe_to_string.ToHandleChecked();
}
void StackGuard::HandleGCInterrupt() {
if (CheckAndClearInterrupt(GC_REQUEST)) {
isolate_->heap()->HandleGCRequest();
......
......@@ -48,6 +48,11 @@ class Execution final : public AllStatic {
Handle<Object> receiver, int argc,
Handle<Object> argv[],
MaybeHandle<Object>* exception_out = NULL);
static Handle<String> GetStackTraceLine(Handle<Object> recv,
Handle<JSFunction> fun,
Handle<Object> pos,
Handle<Object> is_global);
};
......
......@@ -917,13 +917,6 @@ Handle<Script> Factory::NewScript(Handle<String> source) {
return script;
}
Handle<StackTraceFrame> Factory::NewStackTraceFrame() {
Handle<StackTraceFrame> frame =
Handle<StackTraceFrame>::cast(NewStruct(STACK_TRACE_FRAME_TYPE));
frame->set_flags(0);
frame->set_offset(0);
return frame;
}
Handle<Foreign> Factory::NewForeign(Address addr, PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(isolate(),
......
......@@ -292,8 +292,6 @@ class Factory final {
Handle<Script> NewScript(Handle<String> source);
Handle<StackTraceFrame> NewStackTraceFrame();
// Foreign objects are pretenured when allocated by the bootstrapper.
Handle<Foreign> NewForeign(Address addr,
PretenureFlag pretenure = NOT_TENURED);
......
......@@ -161,7 +161,13 @@
V(array_iteration_kind_symbol) \
V(array_iterator_next_symbol) \
V(array_iterator_object_symbol) \
V(call_site_frame_symbol) \
V(call_site_constructor_symbol) \
V(call_site_function_symbol) \
V(call_site_position_symbol) \
V(call_site_receiver_symbol) \
V(call_site_strict_symbol) \
V(call_site_wasm_obj_symbol) \
V(call_site_wasm_func_index_symbol) \
V(class_end_position_symbol) \
V(class_start_position_symbol) \
V(detailed_stack_trace_symbol) \
......
This diff is collapsed.
This diff is collapsed.
......@@ -42,6 +42,40 @@ class MessageLocation {
Handle<JSFunction> function_;
};
class CallSite {
public:
CallSite(Isolate* isolate, Handle<JSObject> call_site_obj);
Handle<Object> GetFileName();
Handle<Object> GetFunctionName();
Handle<Object> GetScriptNameOrSourceUrl();
Handle<Object> GetMethodName();
Handle<Object> GetTypeName();
Handle<Object> GetEvalOrigin();
// Return 1-based line number, including line offset.
int GetLineNumber();
// Return 1-based column number, including column offset if first line.
int GetColumnNumber();
bool IsNative();
bool IsToplevel();
bool IsEval();
bool IsConstructor();
bool IsJavaScript() { return !fun_.is_null(); }
bool IsWasm() { return !wasm_obj_.is_null(); }
int wasm_func_index() const { return wasm_func_index_; }
private:
Isolate* isolate_;
Handle<Object> receiver_;
Handle<JSFunction> fun_;
int32_t pos_ = -1;
Handle<JSObject> wasm_obj_;
uint32_t wasm_func_index_ = static_cast<uint32_t>(-1);
};
// Determines how stack trace collection skips frames.
enum FrameSkipMode {
// Unconditionally skips the first frame. Used e.g. when the Error constructor
......@@ -73,6 +107,16 @@ class ErrorUtils : public AllStatic {
Handle<Object> stack_trace);
};
class CallSiteUtils : public AllStatic {
public:
static MaybeHandle<Object> Construct(Isolate* isolate,
Handle<Object> receiver,
Handle<Object> fun, Handle<Object> pos,
Handle<Object> strict_mode);
static MaybeHandle<String> ToString(Isolate* isolate, Handle<Object> recv);
};
#define MESSAGE_TEMPLATES(T) \
/* Error */ \
T(None, "") \
......
......@@ -1016,10 +1016,6 @@ void Script::ScriptVerify() {
VerifyPointer(line_ends());
}
void StackTraceFrame::StackTraceFrameVerify() {
CHECK(IsStackTraceFrame());
VerifyPointer(abstract_code());
}
void NormalizedMapCache::NormalizedMapCacheVerify() {
FixedArray::cast(this)->FixedArrayVerify();
......
......@@ -5818,29 +5818,6 @@ void Script::set_origin_options(ScriptOriginOptions origin_options) {
(origin_options.Flags() << kOriginOptionsShift));
}
SMI_ACCESSORS(StackTraceFrame, flags, kFlagsOffset)
ACCESSORS(StackTraceFrame, abstract_code, AbstractCode, kAbstractCodeOffset)
SMI_ACCESSORS(StackTraceFrame, offset, kOffsetOffset)
ACCESSORS_CHECKED(StackTraceFrame, receiver, Object, kReceiverOffset,
!IsWasmFrame())
ACCESSORS_CHECKED(StackTraceFrame, function, JSFunction, kFunctionOffset,
!IsWasmFrame())
ACCESSORS_CHECKED(StackTraceFrame, wasm_object, Object, kWasmObjectOffset,
IsWasmFrame())
SMI_ACCESSORS_CHECKED(StackTraceFrame, wasm_function_index,
kWasmFunctionIndexOffset, IsWasmFrame())
bool StackTraceFrame::IsWasmFrame() const {
return ((flags() & kIsWasmFrame) != 0);
}
bool StackTraceFrame::IsJavaScriptFrame() const { return !IsWasmFrame(); }
bool StackTraceFrame::IsStrict() const { return ((flags() & kIsStrict) != 0); }
bool StackTraceFrame::ForceConstructor() const {
return ((flags() & kForceConstructor) != 0);
}
ACCESSORS(DebugInfo, shared, SharedFunctionInfo, kSharedFunctionInfoIndex)
ACCESSORS(DebugInfo, debug_bytecode_array, Object, kDebugBytecodeArrayIndex)
......
......@@ -1274,21 +1274,6 @@ void Script::ScriptPrint(std::ostream& os) { // NOLINT
os << "\n";
}
void StackTraceFrame::StackTraceFramePrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "StackTraceFrame");
os << "\n - flags: " << flags();
os << "\n - abstract_code: " << Brief(abstract_code());
os << "\n - offset: " << offset();
if (IsWasmFrame()) {
os << "\n - wasm_object: " << Brief(wasm_object());
os << "\n - wasm_function_index data: " << wasm_function_index();
} else {
DCHECK(IsJavaScriptFrame());
os << "\n - receiver: " << Brief(receiver());
os << "\n - function: " << Brief(function());
}
os << "\n";
}
void DebugInfo::DebugInfoPrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "DebugInfo");
......
This diff is collapsed.
......@@ -389,7 +389,6 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
V(ALLOCATION_MEMENTO_TYPE) \
V(ALLOCATION_SITE_TYPE) \
V(SCRIPT_TYPE) \
V(STACK_TRACE_FRAME_TYPE) \
V(TYPE_FEEDBACK_INFO_TYPE) \
V(ALIASED_ARGUMENTS_ENTRY_TYPE) \
V(BOX_TYPE) \
......@@ -505,7 +504,6 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
V(FUNCTION_TEMPLATE_INFO, FunctionTemplateInfo, function_template_info) \
V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info) \
V(SCRIPT, Script, script) \
V(STACK_TRACE_FRAME, StackTraceFrame, stack_trace_frame) \
V(ALLOCATION_SITE, AllocationSite, allocation_site) \
V(ALLOCATION_MEMENTO, AllocationMemento, allocation_memento) \
V(TYPE_FEEDBACK_INFO, TypeFeedbackInfo, type_feedback_info) \
......@@ -677,7 +675,6 @@ enum InstanceType {
ALLOCATION_SITE_TYPE,
ALLOCATION_MEMENTO_TYPE,
SCRIPT_TYPE,
STACK_TRACE_FRAME_TYPE,
TYPE_FEEDBACK_INFO_TYPE,
ALIASED_ARGUMENTS_ENTRY_TYPE,
BOX_TYPE,
......@@ -6507,6 +6504,7 @@ class Box : public Struct {
DISALLOW_IMPLICIT_CONSTRUCTORS(Box);
};
// Container for metadata stored on each prototype map.
class PrototypeInfo : public Struct {
public:
......@@ -6791,88 +6789,6 @@ class Script: public Struct {
DISALLOW_IMPLICIT_CONSTRUCTORS(Script);
};
class StackTraceFrame : public Struct {
public:
// --- Fields for JS and Wasm frames. ---
static const int kIsWasmFrame = 1 << 0;
static const int kForceConstructor = 1 << 1;
static const int kIsStrict = 1 << 2;
// [flags]
DECL_INT_ACCESSORS(flags)
// [abstract_code]
DECL_ACCESSORS(abstract_code, AbstractCode)
// [offset]
DECL_INT_ACCESSORS(offset)
// --- Fields for JS frames. ---
// [receiver]
DECL_ACCESSORS(receiver, Object)
// [function]
DECL_ACCESSORS(function, JSFunction)
// --- Fields for Wasm frames. ---
// [wasm_object]
DECL_ACCESSORS(wasm_object, Object)
// [wasm_function_index]
DECL_INT_ACCESSORS(wasm_function_index)
inline bool IsWasmFrame() const;
inline bool IsJavaScriptFrame() const;
inline bool IsStrict() const;
inline bool ForceConstructor() const;
Handle<Object> GetFileName();
Handle<Object> GetFunctionName();
Handle<Object> GetScriptNameOrSourceUrl();
Handle<Object> GetMethodName();
Handle<Object> GetTypeName();
Handle<Object> GetEvalOrigin();
int GetPosition();
// Return 1-based line number, including line offset.
int GetLineNumber();
// Return 1-based column number, including column offset if first line.
int GetColumnNumber();
bool IsNative();
bool IsToplevel();
bool IsEval();
bool IsConstructor();
Handle<String> ToString();
DECLARE_CAST(StackTraceFrame)
// Dispatched behavior.
DECLARE_PRINTER(StackTraceFrame)
DECLARE_VERIFIER(StackTraceFrame)
// Fields for all frame types.
static const int kFlagsOffset = HeapObject::kHeaderSize;
static const int kAbstractCodeOffset = kFlagsOffset + kPointerSize;
static const int kOffsetOffset = kAbstractCodeOffset + kPointerSize;
// Fields for JS frames.
static const int kReceiverOffset = kOffsetOffset + kPointerSize;
static const int kFunctionOffset = kReceiverOffset + kPointerSize;
// Fields for Wasm frames.
static const int kWasmObjectOffset = kOffsetOffset + kPointerSize;
static const int kWasmFunctionIndexOffset = kWasmObjectOffset + kPointerSize;
static const int kSize = kFunctionOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(StackTraceFrame);
};
// List of builtin functions we want to identify to improve code
// generation.
......
......@@ -115,27 +115,22 @@ RUNTIME_FUNCTION(Runtime_ThrowWasmError) {
// TODO(wasm): This implementation is temporary, see bug #5007:
// https://bugs.chromium.org/p/v8/issues/detail?id=5007
Handle<JSObject> error = Handle<JSObject>::cast(error_obj);
// Patch the stack trace (array of <receiver, function, code, position>).
Handle<Object> stack_trace_obj = JSReceiver::GetDataProperty(
error, isolate->factory()->stack_trace_symbol());
// Patch the stack trace (array of <receiver, function, code, position>).
if (stack_trace_obj->IsJSArray()) {
Handle<FixedArray> stack_elements(
FixedArray::cast(JSArray::cast(*stack_trace_obj)->elements()));
Handle<StackTraceFrame> frame =
handle(StackTraceFrame::cast(stack_elements->get(0)));
DCHECK(frame->IsWasmFrame());
DCHECK(frame->offset() >= 0);
frame->set_offset(-1 - byte_offset);
DCHECK_EQ(1, stack_elements->length() % 4);
DCHECK(Code::cast(stack_elements->get(3))->kind() == Code::WASM_FUNCTION);
DCHECK(stack_elements->get(4)->IsSmi() &&
Smi::cast(stack_elements->get(4))->value() >= 0);
stack_elements->set(4, Smi::FromInt(-1 - byte_offset));
}
// Patch the detailed stack trace (array of JSObjects with various
// properties).
Handle<Object> detailed_stack_trace_obj = JSReceiver::GetDataProperty(
error, isolate->factory()->detailed_stack_trace_symbol());
// Patch the detailed stack trace (array of JSObjects with various
// properties).
if (detailed_stack_trace_obj->IsJSArray()) {
Handle<FixedArray> stack_elements(
FixedArray::cast(JSArray::cast(*detailed_stack_trace_obj)->elements()));
......
......@@ -248,7 +248,6 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case TRANSITION_ARRAY_TYPE:
case FOREIGN_TYPE:
case SCRIPT_TYPE:
case STACK_TRACE_FRAME_TYPE:
case CODE_TYPE:
case PROPERTY_CELL_TYPE:
return kOtherInternal & kTaggedPointer;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment