Commit fbc419df authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[cleanup] Use IsNull, IsUndefined and IsNullOrUndefined in CSA

Bug: v8:6921
Change-Id: Icbbb7c08b9ff9f20339988770d88d96653a9ddef
Reviewed-on: https://chromium-review.googlesource.com/718656
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48890}
parent 7390c2fc
......@@ -363,10 +363,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
// TODO(danno): Seriously? Do we really need to throw the exact error
// message on null and undefined so that the webkit tests pass?
Label throw_null_undefined_exception(this, Label::kDeferred);
GotoIf(WordEqual(receiver(), NullConstant()),
&throw_null_undefined_exception);
GotoIf(WordEqual(receiver(), UndefinedConstant()),
&throw_null_undefined_exception);
GotoIf(IsNullOrUndefined(receiver()), &throw_null_undefined_exception);
// By the book: taken directly from the ECMAScript 2015 specification
......@@ -859,8 +856,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
TF_BUILTIN(FastArrayPop, CodeStubAssembler) {
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget),
UndefinedConstant()));
CSA_ASSERT(this, IsUndefined(Parameter(BuiltinDescriptor::kNewTarget)));
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
Node* receiver = args.GetReceiver();
......@@ -969,8 +965,7 @@ TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
// arguments are reordered.
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget),
UndefinedConstant()));
CSA_ASSERT(this, IsUndefined(Parameter(BuiltinDescriptor::kNewTarget)));
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
Node* receiver = args.GetReceiver();
......@@ -1401,8 +1396,7 @@ TF_BUILTIN(FastArraySlice, FastArraySliceCodeStubAssembler) {
TF_BUILTIN(FastArrayShift, CodeStubAssembler) {
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget),
UndefinedConstant()));
CSA_ASSERT(this, IsUndefined(Parameter(BuiltinDescriptor::kNewTarget)));
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
Node* receiver = args.GetReceiver();
......@@ -2730,7 +2724,7 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
Label if_istypedarray(this), if_isgeneric(this);
// If a is undefined, return CreateIterResultObject(undefined, true)
GotoIf(WordEqual(array, UndefinedConstant()), &allocate_iterator_result);
GotoIf(IsUndefined(array), &allocate_iterator_result);
Node* array_type = LoadInstanceType(array);
Branch(InstanceTypeEqual(array_type, JS_TYPED_ARRAY_TYPE), &if_istypedarray,
......
......@@ -1744,7 +1744,7 @@ TF_BUILTIN(WeakMapLookupHashIndex, CollectionsBuiltinsAssembler) {
IntPtrAdd(index, IntPtrConstant(WeakHashTable::kElementsStartIndex));
Node* current = LoadFixedArrayElement(table, index);
GotoIf(WordEqual(current, UndefinedConstant()), &if_not_found);
GotoIf(IsUndefined(current), &if_not_found);
GotoIf(WordEqual(current, key), &if_found);
// See HashTable::NextProbe().
......
......@@ -33,9 +33,7 @@ void ConversionBuiltinsAssembler::Generate_NonPrimitiveToPrimitive(
// Check if {exotic_to_prim} is neither null nor undefined.
Label ordinary_to_primitive(this);
GotoIf(WordEqual(exotic_to_prim, NullConstant()), &ordinary_to_primitive);
GotoIf(WordEqual(exotic_to_prim, UndefinedConstant()),
&ordinary_to_primitive);
GotoIf(IsNullOrUndefined(exotic_to_prim), &ordinary_to_primitive);
{
// Invoke the {exotic_to_prim} method on the {input} with a string
// representation of the {hint}.
......
......@@ -283,7 +283,7 @@ TF_BUILTIN(NumberParseInt, CodeStubAssembler) {
// Check if {radix} is treated as 10 (i.e. undefined, 0 or 10).
Label if_radix10(this), if_generic(this, Label::kDeferred);
GotoIf(WordEqual(radix, UndefinedConstant()), &if_radix10);
GotoIf(IsUndefined(radix), &if_radix10);
GotoIf(WordEqual(radix, SmiConstant(10)), &if_radix10);
GotoIf(WordEqual(radix, SmiConstant(0)), &if_radix10);
Goto(&if_generic);
......
......@@ -577,7 +577,7 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
no_properties(this);
{
Comment("Argument 1 check: prototype");
GotoIf(WordEqual(prototype, NullConstant()), &prototype_valid);
GotoIf(IsNull(prototype), &prototype_valid);
BranchIfJSReceiver(prototype, &prototype_valid, &call_runtime);
}
......@@ -587,7 +587,7 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
// Check that we have a simple object
GotoIf(TaggedIsSmi(properties), &call_runtime);
// Undefined implies no properties.
GotoIf(WordEqual(properties, UndefinedConstant()), &no_properties);
GotoIf(IsUndefined(properties), &no_properties);
Node* properties_map = LoadMap(properties);
GotoIf(IsSpecialReceiverMap(properties_map), &call_runtime);
// Stay on the fast path only if there are no elements.
......@@ -608,7 +608,7 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
VARIABLE(properties, MachineRepresentation::kTagged);
Label non_null_proto(this), instantiate_map(this), good(this);
Branch(WordEqual(prototype, NullConstant()), &good, &non_null_proto);
Branch(IsNull(prototype), &good, &non_null_proto);
BIND(&good);
{
......@@ -634,7 +634,7 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
Comment("Load ObjectCreateMap from PrototypeInfo");
Node* weak_cell =
LoadObjectField(prototype_info, PrototypeInfo::kObjectCreateMap);
GotoIf(WordEqual(weak_cell, UndefinedConstant()), &call_runtime);
GotoIf(IsUndefined(weak_cell), &call_runtime);
map.Bind(LoadWeakCellValue(weak_cell, &call_runtime));
Goto(&instantiate_map);
}
......@@ -769,8 +769,7 @@ TF_BUILTIN(CreateGeneratorObject, ObjectBuiltinsAssembler) {
TF_BUILTIN(ObjectGetOwnPropertyDescriptor, ObjectBuiltinsAssembler) {
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget),
UndefinedConstant()));
CSA_ASSERT(this, IsUndefined(Parameter(BuiltinDescriptor::kNewTarget)));
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
Node* object = args.GetOptionalArgumentValue(0);
......
......@@ -302,8 +302,7 @@ Node* PromiseBuiltinsAssembler::SpeciesConstructor(Node* context, Node* object,
GetProperty(context, constructor, isolate->factory()->species_symbol());
// 6. If S is either undefined or null, return defaultConstructor.
GotoIf(IsUndefined(species), &out);
GotoIf(WordEqual(species, NullConstant()), &out);
GotoIf(IsNullOrUndefined(species), &out);
// 7. If IsConstructor(S) is true, return S.
Label throw_error(this);
......@@ -1456,13 +1455,11 @@ TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
Node* const capability = LoadContextElement(context, kCapabilitySlot);
Label if_alreadyinvoked(this, Label::kDeferred);
GotoIf(WordNotEqual(
LoadObjectField(capability, PromiseCapability::kResolveOffset),
UndefinedConstant()),
GotoIfNot(IsUndefined(
LoadObjectField(capability, PromiseCapability::kResolveOffset)),
&if_alreadyinvoked);
GotoIf(WordNotEqual(
LoadObjectField(capability, PromiseCapability::kRejectOffset),
UndefinedConstant()),
GotoIfNot(IsUndefined(
LoadObjectField(capability, PromiseCapability::kRejectOffset)),
&if_alreadyinvoked);
StoreObjectField(capability, PromiseCapability::kResolveOffset, resolve);
......
......@@ -654,7 +654,6 @@ Node* RegExpBuiltinsAssembler::RegExpExecInternal(Node* const context,
Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
Node* const context, Node* const regexp, Node* const string,
Label* if_didnotmatch, const bool is_fastpath) {
Node* const null = NullConstant();
Node* const int_zero = IntPtrConstant(0);
Node* const smi_zero = SmiConstant(0);
......@@ -722,7 +721,7 @@ Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
BIND(&if_isoob);
{
StoreLastIndex(context, regexp, smi_zero, is_fastpath);
var_result.Bind(null);
var_result.Bind(NullConstant());
Goto(if_didnotmatch);
}
}
......@@ -750,7 +749,7 @@ Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBodyWithoutResult(
// {match_indices} is either null or the RegExpMatchInfo array.
// Return early if exec failed, possibly updating last index.
GotoIfNot(WordEqual(match_indices, null), &successful_match);
GotoIfNot(IsNull(match_indices), &successful_match);
GotoIfNot(should_update_last_index, if_didnotmatch);
......@@ -780,8 +779,6 @@ Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBody(Node* const context,
Node* const regexp,
Node* const string,
const bool is_fastpath) {
Node* const null = NullConstant();
VARIABLE(var_result, MachineRepresentation::kTagged);
Label if_didnotmatch(this), out(this);
......@@ -799,7 +796,7 @@ Node* RegExpBuiltinsAssembler::RegExpPrototypeExecBody(Node* const context,
BIND(&if_didnotmatch);
{
var_result.Bind(null);
var_result.Bind(NullConstant());
Goto(&out);
}
......@@ -1704,7 +1701,7 @@ Node* RegExpBuiltinsAssembler::RegExpExec(Node* context, Node* regexp,
Node* const result = CallJS(call_callable, context, exec, regexp, string);
var_result.Bind(result);
GotoIf(WordEqual(result, NullConstant()), &out);
GotoIf(IsNull(result), &out);
ThrowIfNotJSReceiver(context, result,
MessageTemplate::kInvalidRegExpExecResult, "");
......@@ -1763,8 +1760,7 @@ TF_BUILTIN(RegExpPrototypeTest, RegExpBuiltinsAssembler) {
Node* const match_indices = RegExpExec(context, receiver, string);
// Return true iff exec matched successfully.
Node* const result =
SelectBooleanConstant(WordNotEqual(match_indices, NullConstant()));
Node* const result = SelectBooleanConstant(IsNotNull(match_indices));
Return(result);
}
}
......@@ -1983,7 +1979,6 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
CSA_ASSERT(this, IsString(string));
if (is_fastpath) CSA_ASSERT(this, IsFastRegExp(context, regexp));
Node* const null = NullConstant();
Node* const int_zero = IntPtrConstant(0);
Node* const smi_zero = SmiConstant(0);
......@@ -2045,7 +2040,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
Node* const result = RegExpExec(context, regexp, string);
Label load_match(this);
Branch(WordEqual(result, null), &if_didnotmatch, &load_match);
Branch(IsNull(result), &if_didnotmatch, &load_match);
BIND(&load_match);
{
......@@ -2078,7 +2073,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeMatchBody(Node* const context,
{
// Return null if there were no matches, otherwise just exit the loop.
GotoIfNot(IntPtrEqual(array.length(), int_zero), &out);
Return(null);
Return(NullConstant());
}
BIND(&if_didmatch);
......@@ -2244,7 +2239,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSearchBodySlow(
// Return -1 if no match was found.
{
Label next(this);
GotoIfNot(WordEqual(exec_result, NullConstant()), &next);
GotoIfNot(IsNull(exec_result), &next);
Return(SmiConstant(-1));
BIND(&next);
}
......@@ -2319,7 +2314,6 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
CSA_ASSERT(this, TaggedIsSmi(limit));
CSA_ASSERT(this, IsString(string));
Node* const null = NullConstant();
Node* const smi_zero = SmiConstant(0);
Node* const int_zero = IntPtrConstant(0);
Node* const int_limit = SmiUntag(limit);
......@@ -2357,7 +2351,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
smi_zero, last_match_info);
Label return_singleton_array(this);
Branch(WordEqual(match_indices, null), &return_singleton_array,
Branch(IsNull(match_indices), &return_singleton_array,
&return_empty_array);
BIND(&return_singleton_array);
......@@ -2421,7 +2415,7 @@ void RegExpBuiltinsAssembler::RegExpPrototypeSplitBody(Node* const context,
// We're done if no match was found.
{
Label next(this);
Branch(WordEqual(match_indices, null), &push_suffix_and_out, &next);
Branch(IsNull(match_indices), &push_suffix_and_out, &next);
BIND(&next);
}
......@@ -2675,7 +2669,6 @@ Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath(
Isolate* const isolate = this->isolate();
Node* const null = NullConstant();
Node* const undefined = UndefinedConstant();
Node* const int_zero = IntPtrConstant(0);
Node* const int_one = IntPtrConstant(1);
......@@ -2714,7 +2707,7 @@ Node* RegExpBuiltinsAssembler::ReplaceGlobalCallableFastPath(
// If no matches, return the subject string.
var_result.Bind(string);
GotoIf(WordEqual(res, null), &out);
GotoIf(IsNull(res), &out);
// Reload last match info since it might have changed.
last_match_info =
......@@ -3109,7 +3102,6 @@ TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) {
Node* const string = Parameter(Descriptor::kString);
Node* const context = Parameter(Descriptor::kContext);
Node* const null = NullConstant();
Node* const smi_zero = SmiConstant(0);
CSA_ASSERT(this, IsJSRegExp(regexp));
......@@ -3122,6 +3114,7 @@ TF_BUILTIN(RegExpInternalMatch, RegExpBuiltinsAssembler) {
Node* const match_indices = RegExpExecInternal(context, regexp, string,
smi_zero, internal_match_info);
Node* const null = NullConstant();
Label if_matched(this), if_didnotmatch(this);
Branch(WordEqual(match_indices, null), &if_didnotmatch, &if_matched);
......
......@@ -1033,10 +1033,6 @@ void StringIncludesIndexOfAssembler::Generate(SearchVariant variant) {
}
}
compiler::Node* StringBuiltinsAssembler::IsNullOrUndefined(Node* const value) {
return Word32Or(IsUndefined(value), IsNull(value));
}
void StringBuiltinsAssembler::RequireObjectCoercible(Node* const context,
Node* const value,
const char* method_name) {
......@@ -1703,7 +1699,7 @@ TF_BUILTIN(StringPrototypeSlice, StringBuiltinsAssembler) {
// 5. If end is undefined, let intEnd be len;
var_end.Bind(length);
GotoIf(WordEqual(end, UndefinedConstant()), &out);
GotoIf(IsUndefined(end), &out);
// else let intEnd be ? ToInteger(end).
Node* const end_int =
......@@ -1889,8 +1885,7 @@ TF_BUILTIN(StringPrototypeSubstr, StringBuiltinsAssembler) {
// Default to {string_length} if {length} is undefined.
{
Label if_isundefined(this, Label::kDeferred), if_isnotundefined(this);
Branch(WordEqual(length, UndefinedConstant()), &if_isundefined,
&if_isnotundefined);
Branch(IsUndefined(length), &if_isundefined, &if_isnotundefined);
BIND(&if_isundefined);
var_length.Bind(string_length);
......@@ -2037,7 +2032,7 @@ TF_BUILTIN(StringPrototypeSubstring, StringBuiltinsAssembler) {
// Conversion and bounds-checks for {end}.
{
var_end.Bind(length);
GotoIf(WordEqual(end, UndefinedConstant()), &out);
GotoIf(IsUndefined(end), &out);
var_end.Bind(ToSmiBetweenZeroAnd(context, end, length));
......
......@@ -63,7 +63,6 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
Node* IndexOfDollarChar(Node* const context, Node* const string);
Node* IsNullOrUndefined(Node* const value);
void RequireObjectCoercible(Node* const context, Node* const value,
const char* method_name);
......
......@@ -803,7 +803,7 @@ void CodeStubAssembler::BranchIfPrototypesHaveNoElements(
{
Node* map = var_map.value();
Node* prototype = LoadMapPrototype(map);
GotoIf(WordEqual(prototype, NullConstant()), definitely_no_elements);
GotoIf(IsNull(prototype), definitely_no_elements);
Node* prototype_map = LoadMap(prototype);
// Pessimistically assume elements if a Proxy, Special API Object,
// or JSValue wrapper is found on the prototype chain. After this
......@@ -3686,23 +3686,11 @@ Node* CodeStubAssembler::ToThisString(Node* context, Node* value,
BIND(&if_valueisnotstring);
{
// Check if the {value} is null.
Label if_valueisnullorundefined(this, Label::kDeferred),
if_valueisnotnullorundefined(this, Label::kDeferred),
if_valueisnotnull(this, Label::kDeferred);
Branch(WordEqual(value, NullConstant()), &if_valueisnullorundefined,
&if_valueisnotnull);
BIND(&if_valueisnotnull);
{
// Check if the {value} is undefined.
Branch(WordEqual(value, UndefinedConstant()),
&if_valueisnullorundefined, &if_valueisnotnullorundefined);
BIND(&if_valueisnotnullorundefined);
{
Label if_valueisnullorundefined(this, Label::kDeferred);
GotoIf(IsNullOrUndefined(value), &if_valueisnullorundefined);
// Convert the {value} to a String.
var_value.Bind(CallBuiltin(Builtins::kToString, context, value));
Goto(&if_valueisstring);
}
}
BIND(&if_valueisnullorundefined);
{
......@@ -4100,6 +4088,10 @@ Node* CodeStubAssembler::IsNullOrJSReceiver(Node* object) {
return Word32Or(IsJSReceiver(object), IsNull(object));
}
Node* CodeStubAssembler::IsNullOrUndefined(Node* const value) {
return Word32Or(IsUndefined(value), IsNull(value));
}
Node* CodeStubAssembler::IsJSGlobalProxyInstanceType(Node* instance_type) {
return InstanceTypeEqual(instance_type, JS_GLOBAL_PROXY_TYPE);
}
......@@ -4489,8 +4481,7 @@ Node* CodeStubAssembler::StringFromCharCode(Node* code) {
Label if_entryisundefined(this, Label::kDeferred),
if_entryisnotundefined(this);
Node* entry = LoadFixedArrayElement(cache, code_index);
Branch(WordEqual(entry, UndefinedConstant()), &if_entryisundefined,
&if_entryisnotundefined);
Branch(IsUndefined(entry), &if_entryisundefined, &if_entryisnotundefined);
BIND(&if_entryisundefined);
{
......@@ -7024,9 +7015,7 @@ void CodeStubAssembler::TryPrototypeChainLookup(
Node* proto = LoadMapPrototype(holder_map);
Label if_not_null(this);
Branch(WordEqual(proto, NullConstant()), if_end, &if_not_null);
BIND(&if_not_null);
GotoIf(IsNull(proto), if_end);
Node* map = LoadMap(proto);
Node* instance_type = LoadMapInstanceType(map);
......@@ -7059,9 +7048,7 @@ void CodeStubAssembler::TryPrototypeChainLookup(
Node* proto = LoadMapPrototype(var_holder_map.value());
Label if_not_null(this);
Branch(WordEqual(proto, NullConstant()), if_end, &if_not_null);
BIND(&if_not_null);
GotoIf(IsNull(proto), if_end);
Node* map = LoadMap(proto);
Node* instance_type = LoadMapInstanceType(map);
......
......@@ -1056,6 +1056,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* IsJSReceiverMap(Node* map);
Node* IsJSReceiver(Node* object);
Node* IsNullOrJSReceiver(Node* object);
Node* IsNullOrUndefined(Node* object);
Node* IsJSRegExp(Node* object);
Node* IsJSTypedArray(Node* object);
Node* IsJSValueInstanceType(Node* instance_type);
......
......@@ -509,8 +509,7 @@ void AccessorAssembler::HandleLoadICProtoHandlerCase(
{
Label load_from_cached_holder(this), done(this);
Branch(WordEqual(maybe_holder_cell, NullConstant()), &done,
&load_from_cached_holder);
Branch(IsNull(maybe_holder_cell), &done, &load_from_cached_holder);
BIND(&load_from_cached_holder);
{
......@@ -593,7 +592,7 @@ Node* AccessorAssembler::EmitLoadICProtoArrayCheck(const LoadICParameters* p,
VARIABLE(var_holder, MachineRepresentation::kTagged, p->receiver);
Label done(this);
GotoIf(WordEqual(maybe_holder_cell, NullConstant()), &done);
GotoIf(IsNull(maybe_holder_cell), &done);
{
// For regular holders, having passed the receiver map check and the
......
......@@ -108,7 +108,7 @@ void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
{
Node* map = var_map.value();
Node* prototype = LoadMapPrototype(map);
GotoIf(WordEqual(prototype, NullConstant()), only_fast_elements);
GotoIf(IsNull(prototype), only_fast_elements);
Node* prototype_map = LoadMap(prototype);
var_map.Bind(prototype_map);
Node* instance_type = LoadMapInstanceType(prototype_map);
......@@ -596,6 +596,7 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
// Bailout if it can be an integer indexed exotic case.
GotoIf(InstanceTypeEqual(instance_type, JS_TYPED_ARRAY_TYPE), bailout);
Node* proto = LoadMapPrototype(holder_map);
GotoIf(IsNull(proto), &ok_to_write);
var_holder.Bind(proto);
var_holder_map.Bind(LoadMap(proto));
Goto(&loop);
......
......@@ -2066,7 +2066,7 @@ IGNITION_HANDLER(TestTypeOf, InterpreterAssembler) {
GotoIf(TaggedIsSmi(object), &if_false);
// If the object is null then return true.
GotoIf(WordEqual(object, NullConstant()), &if_true);
GotoIf(IsNull(object), &if_true);
// Check if the object is a receiver type and is not undefined or callable.
Node* map = LoadMap(object);
......
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