Commit 5784773f authored by caitp's avatar caitp Committed by Commit bot

[builtins] move String.prototype[@@iterator] to C++ builtin

BUG=v8:5388
R=bmeurer@chromium.org, adamk@chromium.org
TBR=hpayer@chromium.org

Review-Url: https://codereview.chromium.org/2348493003
Cr-Commit-Position: refs/heads/master@{#39598}
parent d5ddd2be
......@@ -392,14 +392,12 @@ action("js2c") {
"src/js/regexp.js",
"src/js/arraybuffer.js",
"src/js/typedarray.js",
"src/js/iterator-prototype.js",
"src/js/collection.js",
"src/js/weak-collection.js",
"src/js/collection-iterator.js",
"src/js/promise.js",
"src/js/messages.js",
"src/js/array-iterator.js",
"src/js/string-iterator.js",
"src/js/templates.js",
"src/js/spread.js",
"src/js/proxy.js",
......@@ -927,6 +925,7 @@ v8_source_set("v8_base") {
"src/builtins/builtins-handler.cc",
"src/builtins/builtins-internal.cc",
"src/builtins/builtins-interpreter.cc",
"src/builtins/builtins-iterator.cc",
"src/builtins/builtins-json.cc",
"src/builtins/builtins-math.cc",
"src/builtins/builtins-number.cc",
......
......@@ -217,6 +217,7 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) {
case JS_MAP_TYPE:
case JS_SET_ITERATOR_TYPE:
case JS_MAP_ITERATOR_TYPE:
case JS_STRING_ITERATOR_TYPE:
case JS_WEAK_MAP_TYPE:
case JS_WEAK_SET_TYPE:
case JS_PROMISE_TYPE:
......
......@@ -660,6 +660,16 @@ void Genesis::CreateIteratorMaps(Handle<JSFunction> empty) {
// Create iterator-related meta-objects.
Handle<JSObject> iterator_prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
Handle<JSFunction> iterator_prototype_iterator = SimpleCreateFunction(
isolate(), factory()->NewStringFromAsciiChecked("[Symbol.iterator]"),
Builtins::kIteratorPrototypeIterator, 0, false);
iterator_prototype_iterator->shared()->set_native(true);
JSObject::AddProperty(iterator_prototype, factory()->iterator_symbol(),
iterator_prototype_iterator, DONT_ENUM);
native_context()->set_initial_iterator_prototype(*iterator_prototype);
Handle<JSObject> generator_object_prototype =
factory()->NewJSObject(isolate()->object_function(), TENURED);
native_context()->set_initial_generator_prototype(
......@@ -1408,6 +1418,38 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Builtins::kStringPrototypeTrimRight, 0, false);
SimpleInstallFunction(prototype, "valueOf",
Builtins::kStringPrototypeValueOf, 0, true);
Handle<JSFunction> iterator = SimpleCreateFunction(
isolate, factory->NewStringFromAsciiChecked("[Symbol.iterator]"),
Builtins::kStringPrototypeIterator, 0, true);
iterator->shared()->set_native(true);
JSObject::AddProperty(prototype, factory->iterator_symbol(), iterator,
static_cast<PropertyAttributes>(DONT_ENUM));
}
{ // --- S t r i n g I t e r a t o r ---
Handle<JSObject> iterator_prototype(
native_context()->initial_iterator_prototype());
Handle<JSObject> string_iterator_prototype =
factory->NewJSObject(isolate->object_function(), TENURED);
JSObject::ForceSetPrototype(string_iterator_prototype, iterator_prototype);
JSObject::AddProperty(
string_iterator_prototype, factory->to_string_tag_symbol(),
factory->NewStringFromAsciiChecked("String Iterator"),
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
InstallFunction(string_iterator_prototype, "next", JS_OBJECT_TYPE,
JSObject::kHeaderSize, MaybeHandle<JSObject>(),
Builtins::kStringIteratorPrototypeNext);
Handle<JSFunction> string_iterator_function = CreateFunction(
isolate, factory->NewStringFromAsciiChecked("StringIterator"),
JS_STRING_ITERATOR_TYPE, JSStringIterator::kSize,
string_iterator_prototype, Builtins::kIllegal);
native_context()->set_string_iterator_map(
string_iterator_function->initial_map());
}
{
......@@ -2468,17 +2510,12 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
native_context->set_object_to_string(*to_string);
}
Handle<JSObject> iterator_prototype;
{
PrototypeIterator iter(native_context->generator_object_prototype_map());
iter.Advance(); // Advance to the prototype of generator_object_prototype.
iterator_prototype = Handle<JSObject>(iter.GetCurrent<JSObject>());
Handle<JSObject> iterator_prototype(
native_context->initial_iterator_prototype());
JSObject::AddProperty(container,
factory->InternalizeUtf8String("IteratorPrototype"),
iterator_prototype, NONE);
}
JSObject::AddProperty(container,
factory->InternalizeUtf8String("IteratorPrototype"),
iterator_prototype, NONE);
{
PrototypeIterator iter(native_context->sloppy_generator_function_map());
......
// Copyright 2016 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.
#include "src/builtins/builtins.h"
#include "src/builtins/builtins-utils.h"
namespace v8 {
namespace internal {
void Builtins::Generate_IteratorPrototypeIterator(
CodeStubAssembler* assembler) {
assembler->Return(assembler->Parameter(0));
}
} // namespace internal
} // namespace v8
......@@ -616,5 +616,59 @@ void Builtins::Generate_StringPrototypeValueOf(CodeStubAssembler* assembler) {
assembler->Return(result);
}
BUILTIN(StringPrototypeIterator) {
HandleScope scope(isolate);
TO_THIS_STRING(object, "String.prototype[Symbol.iterator]");
Handle<String> string;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string,
Object::ToString(isolate, object));
return *isolate->factory()->NewJSStringIterator(string);
}
BUILTIN(StringIteratorPrototypeNext) {
HandleScope scope(isolate);
if (!args.receiver()->IsJSStringIterator()) {
Handle<String> reason = isolate->factory()->NewStringFromAsciiChecked(
"String Iterator.prototype.next");
THROW_NEW_ERROR_RETURN_FAILURE(
isolate,
NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, reason));
}
Handle<JSStringIterator> iterator =
Handle<JSStringIterator>::cast(args.receiver());
Handle<String> string(iterator->string());
int position = iterator->index();
int length = string->length();
if (position < length) {
uint16_t lead = string->Get(position);
if (lead >= 0xD800 && lead <= 0xDBFF && position + 1 < length) {
uint16_t trail = string->Get(position + 1);
if (V8_LIKELY(trail >= 0xDC00 && trail <= 0xDFFF)) {
// Return surrogate pair code units
iterator->set_index(position + 2);
Handle<String> value =
isolate->factory()->NewSurrogatePairString(lead, trail);
return *isolate->factory()->NewJSIteratorResult(value, false);
}
}
// Return single code unit
iterator->set_index(position + 1);
Handle<String> value =
isolate->factory()->LookupSingleCharacterStringFromCode(lead);
return *isolate->factory()->NewJSIteratorResult(value, false);
}
iterator->set_string(isolate->heap()->empty_string());
return *isolate->factory()->NewJSIteratorResult(
isolate->factory()->undefined_value(), true);
}
} // namespace internal
} // namespace v8
......@@ -376,6 +376,9 @@ namespace internal {
/* ES6 section 18.2.3 isNaN ( number ) */ \
TFJ(GlobalIsNaN, 2) \
\
/* ES6 #sec-%iteratorprototype%-@@iterator */ \
TFJ(IteratorPrototypeIterator, 1) \
\
/* JSON */ \
CPP(JsonParse) \
CPP(JsonStringify) \
......@@ -549,6 +552,11 @@ namespace internal {
CPP(StringPrototypeTrimRight) \
/* ES6 section 21.1.3.28 String.prototype.valueOf () */ \
TFJ(StringPrototypeValueOf, 1) \
/* ES6 #sec-string.prototype-@@iterator */ \
CPP(StringPrototypeIterator) \
\
/* StringIterator */ \
CPP(StringIteratorPrototypeNext) \
\
/* Symbol */ \
CPP(SymbolConstructor) \
......
......@@ -214,6 +214,7 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case JS_MAP_TYPE:
case JS_SET_ITERATOR_TYPE:
case JS_MAP_ITERATOR_TYPE:
case JS_STRING_ITERATOR_TYPE:
case JS_WEAK_MAP_TYPE:
case JS_WEAK_SET_TYPE:
case JS_PROMISE_TYPE:
......
......@@ -148,6 +148,7 @@ enum ContextLookupFlags {
V(GENERATOR_OBJECT_PROTOTYPE_MAP_INDEX, Map, generator_object_prototype_map) \
V(INITIAL_ARRAY_PROTOTYPE_INDEX, JSObject, initial_array_prototype) \
V(INITIAL_GENERATOR_PROTOTYPE_INDEX, JSObject, initial_generator_prototype) \
V(INITIAL_ITERATOR_PROTOTYPE_INDEX, JSObject, initial_iterator_prototype) \
V(INITIAL_OBJECT_PROTOTYPE_INDEX, JSObject, initial_object_prototype) \
V(INT16_ARRAY_FUN_INDEX, JSFunction, int16_array_fun) \
V(INT16X8_FUNCTION_INDEX, JSFunction, int16x8_function) \
......
......@@ -599,6 +599,19 @@ MaybeHandle<String> Factory::NewConsString(Handle<String> left,
return result;
}
Handle<String> Factory::NewSurrogatePairString(uint16_t lead, uint16_t trail) {
DCHECK_GE(lead, 0xD800);
DCHECK_LE(lead, 0xDBFF);
DCHECK_GE(trail, 0xDC00);
DCHECK_LE(trail, 0xDFFF);
Handle<SeqTwoByteString> str =
isolate()->factory()->NewRawTwoByteString(2).ToHandleChecked();
uc16* dest = str->GetChars();
dest[0] = lead;
dest[1] = trail;
return str;
}
Handle<String> Factory::NewProperSubString(Handle<String> str,
int begin,
......@@ -733,6 +746,17 @@ Handle<ExternalOneByteString> Factory::NewNativeSourceString(
return external_string;
}
Handle<JSStringIterator> Factory::NewJSStringIterator(Handle<String> string) {
Handle<Map> map(isolate()->native_context()->string_iterator_map(),
isolate());
Handle<String> flat_string = String::Flatten(string);
Handle<JSStringIterator> iterator =
Handle<JSStringIterator>::cast(NewJSObjectFromMap(map));
iterator->set_string(*flat_string);
iterator->set_index(0);
return iterator;
}
Handle<Symbol> Factory::NewSymbol() {
CALL_HEAP_FUNCTION(
......@@ -1764,6 +1788,15 @@ Handle<JSDataView> Factory::NewJSDataView() {
JSDataView);
}
Handle<JSIteratorResult> Factory::NewJSIteratorResult(Handle<Object> value,
bool done) {
Handle<Map> map(isolate()->native_context()->iterator_result_map());
Handle<JSIteratorResult> js_iter_result =
Handle<JSIteratorResult>::cast(NewJSObjectFromMap(map));
js_iter_result->set_value(*value);
js_iter_result->set_done(*ToBoolean(done));
return js_iter_result;
}
Handle<JSMap> Factory::NewJSMap() {
Handle<Map> map(isolate()->native_context()->js_map_map());
......
......@@ -180,6 +180,8 @@ class Factory final {
MUST_USE_RESULT MaybeHandle<String> NewStringFromTwoByte(
const ZoneVector<uc16>* str, PretenureFlag pretenure = NOT_TENURED);
Handle<JSStringIterator> NewJSStringIterator(Handle<String> string);
// Allocates an internalized string in old space based on the character
// stream.
Handle<String> NewInternalizedStringFromUtf8(Vector<const char> str,
......@@ -221,6 +223,10 @@ class Factory final {
MUST_USE_RESULT MaybeHandle<String> NewConsString(Handle<String> left,
Handle<String> right);
// Create or lookup a single characters tring made up of a utf16 surrogate
// pair.
Handle<String> NewSurrogatePairString(uint16_t lead, uint16_t trail);
// Create a new string object which holds a proper substring of a string.
Handle<String> NewProperSubString(Handle<String> str,
int begin,
......@@ -508,6 +514,8 @@ class Factory final {
Handle<JSDataView> NewJSDataView(Handle<JSArrayBuffer> buffer,
size_t byte_offset, size_t byte_length);
Handle<JSIteratorResult> NewJSIteratorResult(Handle<Object> value, bool done);
Handle<JSMap> NewJSMap();
Handle<JSSet> NewJSSet();
......
......@@ -119,6 +119,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case JS_MAP_TYPE:
case JS_SET_ITERATOR_TYPE:
case JS_MAP_ITERATOR_TYPE:
case JS_STRING_ITERATOR_TYPE:
case JS_PROMISE_TYPE:
case JS_BOUND_FUNCTION_TYPE:
return GetVisitorIdForSize(kVisitJSObject, kVisitJSObjectGeneric,
......
// Copyright 2015 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.
(function(global, utils) {
"use strict";
%CheckIsBootstrapping();
var GlobalObject = global.Object;
var IteratorPrototype = utils.ImportNow("IteratorPrototype");
var iteratorSymbol = utils.ImportNow("iterator_symbol");
// 25.1.2.1 %IteratorPrototype% [ @@iterator ] ( )
function IteratorPrototypeIterator() {
return this;
}
utils.SetFunctionName(IteratorPrototypeIterator, iteratorSymbol);
%AddNamedProperty(IteratorPrototype, iteratorSymbol,
IteratorPrototypeIterator, DONT_ENUM);
})
// Copyright 2014 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.
(function(global, utils) {
"use strict";
%CheckIsBootstrapping();
// -------------------------------------------------------------------
// Imports
var GlobalString = global.String;
var IteratorPrototype = utils.ImportNow("IteratorPrototype");
var iteratorSymbol = utils.ImportNow("iterator_symbol");
var stringIteratorIteratedStringSymbol =
utils.ImportNow("string_iterator_iterated_string_symbol");
var stringIteratorNextIndexSymbol =
utils.ImportNow("string_iterator_next_index_symbol");
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
// -------------------------------------------------------------------
function StringIterator() {}
// 21.1.5.1 CreateStringIterator Abstract Operation
function CreateStringIterator(string) {
CHECK_OBJECT_COERCIBLE(string, 'String.prototype[Symbol.iterator]');
var s = TO_STRING(string);
var iterator = new StringIterator;
SET_PRIVATE(iterator, stringIteratorIteratedStringSymbol, s);
SET_PRIVATE(iterator, stringIteratorNextIndexSymbol, 0);
return iterator;
}
// ES6 section 21.1.5.2.1 %StringIteratorPrototype%.next ( )
function StringIteratorNext() {
var iterator = this;
var value = UNDEFINED;
var done = true;
if (!IS_RECEIVER(iterator) ||
!HAS_DEFINED_PRIVATE(iterator, stringIteratorNextIndexSymbol)) {
throw %make_type_error(kIncompatibleMethodReceiver,
'String Iterator.prototype.next');
}
var s = GET_PRIVATE(iterator, stringIteratorIteratedStringSymbol);
if (!IS_UNDEFINED(s)) {
var position = GET_PRIVATE(iterator, stringIteratorNextIndexSymbol);
var length = TO_UINT32(s.length);
if (position >= length) {
SET_PRIVATE(iterator, stringIteratorIteratedStringSymbol, UNDEFINED);
} else {
var first = %_StringCharCodeAt(s, position);
value = %_StringCharFromCode(first);
done = false;
position++;
if (first >= 0xD800 && first <= 0xDBFF && position < length) {
var second = %_StringCharCodeAt(s, position);
if (second >= 0xDC00 && second <= 0xDFFF) {
value += %_StringCharFromCode(second);
position++;
}
}
SET_PRIVATE(iterator, stringIteratorNextIndexSymbol, position);
}
}
return %_CreateIterResultObject(value, done);
}
// 21.1.3.27 String.prototype [ @@iterator ]( )
function StringPrototypeIterator() {
return CreateStringIterator(this);
}
//-------------------------------------------------------------------
%FunctionSetPrototype(StringIterator, {__proto__: IteratorPrototype});
%FunctionSetInstanceClassName(StringIterator, 'String Iterator');
utils.InstallFunctions(StringIterator.prototype, DONT_ENUM, [
'next', StringIteratorNext
]);
%AddNamedProperty(StringIterator.prototype, toStringTagSymbol,
"String Iterator", READ_ONLY | DONT_ENUM);
utils.SetFunctionName(StringPrototypeIterator, iteratorSymbol);
%AddNamedProperty(GlobalString.prototype, iteratorSymbol,
StringPrototypeIterator, DONT_ENUM);
})
......@@ -474,6 +474,7 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3) {
case JS_MAP_TYPE:
case JS_SET_ITERATOR_TYPE:
case JS_MAP_ITERATOR_TYPE:
case JS_STRING_ITERATOR_TYPE:
case JS_REGEXP_TYPE:
case JS_GLOBAL_PROXY_TYPE:
case JS_GLOBAL_OBJECT_TYPE:
......
......@@ -152,6 +152,9 @@ void HeapObject::HeapObjectVerify() {
case JS_MAP_ITERATOR_TYPE:
JSMapIterator::cast(this)->JSMapIteratorVerify();
break;
case JS_STRING_ITERATOR_TYPE:
JSStringIterator::cast(this)->JSStringIteratorVerify();
break;
case JS_WEAK_MAP_TYPE:
JSWeakMap::cast(this)->JSWeakMapVerify();
break;
......@@ -779,6 +782,13 @@ void JSWeakMap::JSWeakMapVerify() {
CHECK(table()->IsHashTable() || table()->IsUndefined(GetIsolate()));
}
void JSStringIterator::JSStringIteratorVerify() {
CHECK(IsJSStringIterator());
JSObjectVerify();
CHECK(string()->IsString());
CHECK_GE(index(), 0);
CHECK_LE(index(), String::kMaxLength);
}
void JSWeakSet::JSWeakSetVerify() {
CHECK(IsJSWeakSet());
......
......@@ -701,6 +701,7 @@ TYPE_CHECKER(Map, MAP_TYPE)
TYPE_CHECKER(FixedDoubleArray, FIXED_DOUBLE_ARRAY_TYPE)
TYPE_CHECKER(WeakFixedArray, FIXED_ARRAY_TYPE)
TYPE_CHECKER(TransitionArray, TRANSITION_ARRAY_TYPE)
TYPE_CHECKER(JSStringIterator, JS_STRING_ITERATOR_TYPE)
bool HeapObject::IsJSWeakCollection() const {
return IsJSWeakMap() || IsJSWeakSet();
......@@ -2113,6 +2114,8 @@ int JSObject::GetHeaderSize(InstanceType type) {
return JSArgumentsObject::kHeaderSize;
case JS_ERROR_TYPE:
return JSObject::kHeaderSize;
case JS_STRING_ITERATOR_TYPE:
return JSStringIterator::kSize;
default:
UNREACHABLE();
return 0;
......@@ -3282,6 +3285,7 @@ CAST_ACCESSOR(JSReceiver)
CAST_ACCESSOR(JSRegExp)
CAST_ACCESSOR(JSSet)
CAST_ACCESSOR(JSSetIterator)
CAST_ACCESSOR(JSStringIterator)
CAST_ACCESSOR(JSTypedArray)
CAST_ACCESSOR(JSValue)
CAST_ACCESSOR(JSWeakCollection)
......@@ -8270,6 +8274,12 @@ static inline Handle<Object> MakeEntryPair(Isolate* isolate, Handle<Name> key,
FAST_ELEMENTS, 2);
}
ACCESSORS(JSIteratorResult, value, Object, kValueOffset)
ACCESSORS(JSIteratorResult, done, Object, kDoneOffset)
ACCESSORS(JSStringIterator, string, String, kStringOffset)
SMI_ACCESSORS(JSStringIterator, index, kNextIndexOffset)
#undef TYPE_CHECKER
#undef CAST_ACCESSOR
#undef INT_ACCESSORS
......
......@@ -57,6 +57,7 @@
// - JSCollection
// - JSSet
// - JSMap
// - JSStringIterator
// - JSSetIterator
// - JSMapIterator
// - JSWeakCollection
......@@ -433,6 +434,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
V(JS_PROMISE_TYPE) \
V(JS_REGEXP_TYPE) \
V(JS_ERROR_TYPE) \
V(JS_STRING_ITERATOR_TYPE) \
\
V(JS_BOUND_FUNCTION_TYPE) \
V(JS_FUNCTION_TYPE) \
......@@ -728,6 +730,7 @@ enum InstanceType {
JS_PROMISE_TYPE,
JS_REGEXP_TYPE,
JS_ERROR_TYPE,
JS_STRING_ITERATOR_TYPE,
JS_BOUND_FUNCTION_TYPE,
JS_FUNCTION_TYPE, // LAST_JS_OBJECT_TYPE, LAST_JS_RECEIVER_TYPE
......@@ -1009,6 +1012,7 @@ template <class C> inline bool Is(Object* obj);
V(JSProxy) \
V(JSError) \
V(JSPromise) \
V(JSStringIterator) \
V(JSSet) \
V(JSMap) \
V(JSSetIterator) \
......@@ -2615,6 +2619,10 @@ class JSDataPropertyDescriptor: public JSObject {
// as specified by ES6 section 25.1.1.3 The IteratorResult Interface
class JSIteratorResult: public JSObject {
public:
DECL_ACCESSORS(value, Object)
DECL_ACCESSORS(done, Object)
// Offsets of object fields.
static const int kValueOffset = JSObject::kHeaderSize;
static const int kDoneOffset = kValueOffset + kPointerSize;
......@@ -10325,6 +10333,28 @@ class JSMap : public JSCollection {
DISALLOW_IMPLICIT_CONSTRUCTORS(JSMap);
};
class JSStringIterator : public JSObject {
public:
// Dispatched behavior.
DECLARE_PRINTER(JSStringIterator)
DECLARE_VERIFIER(JSStringIterator)
DECLARE_CAST(JSStringIterator)
// [string]: the [[IteratedString]] internal field.
DECL_ACCESSORS(string, String)
// [index]: The [[StringIteratorNextIndex]] internal field.
inline int index() const;
inline void set_index(int value);
static const int kStringOffset = JSObject::kHeaderSize;
static const int kNextIndexOffset = kStringOffset + kPointerSize;
static const int kSize = kNextIndexOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSStringIterator);
};
// OrderedHashTableIterator is an iterator that iterates over the keys and
// values of an OrderedHashTable.
......
......@@ -495,6 +495,7 @@
'builtins/builtins-handler.cc',
'builtins/builtins-internal.cc',
'builtins/builtins-interpreter.cc',
'builtins/builtins-iterator.cc',
'builtins/builtins-json.cc',
'builtins/builtins-math.cc',
'builtins/builtins-number.cc',
......@@ -2204,14 +2205,12 @@
'js/regexp.js',
'js/arraybuffer.js',
'js/typedarray.js',
'js/iterator-prototype.js',
'js/collection.js',
'js/weak-collection.js',
'js/collection-iterator.js',
'js/promise.js',
'js/messages.js',
'js/array-iterator.js',
'js/string-iterator.js',
'js/templates.js',
'js/spread.js',
'js/proxy.js',
......
......@@ -79,7 +79,7 @@ bytecodes: [
/* 15 S> */ B(LdrUndefined), R(0),
B(CreateArrayLiteral), U8(0), U8(0), U8(9),
B(Star), R(1),
B(CallJSRuntime), U8(139), R(0), U8(2),
B(CallJSRuntime), U8(140), R(0), U8(2),
/* 44 S> */ B(Return),
]
constant pool: [
......
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