[refactor] Separate generated builtins and C++ builtins into separate files

This is in preparation for linking the former only into mksnapshot.
Just shuffling code around, no changes in functionality.

BUG=v8:6055

Review-Url: https://codereview.chromium.org/2752143004
Cr-Commit-Position: refs/heads/master@{#43858}
This commit is contained in:
jkummerow 2017-03-16 04:32:01 -07:00 committed by Commit bot
parent 24b9ffa487
commit b3507ff022
49 changed files with 9999 additions and 9766 deletions

View File

@ -808,6 +808,7 @@ v8_source_set("v8_nosnapshot") {
":js2c_experimental_extras",
":js2c_extras",
":v8_base",
":v8_builtins_generators",
]
sources = [
@ -833,6 +834,7 @@ v8_source_set("v8_snapshot") {
":js2c_experimental_extras",
":js2c_extras",
":v8_base",
":v8_builtins_generators",
]
public_deps = [
# This should be public so downstream targets can declare the snapshot
@ -859,6 +861,7 @@ if (v8_use_external_startup_data) {
":js2c_experimental_extras",
":js2c_extras",
":v8_base",
":v8_builtins_generators",
]
public_deps = [
":natives_blob",
@ -874,6 +877,53 @@ if (v8_use_external_startup_data) {
}
}
v8_source_set("v8_builtins_generators") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
deps = [
":v8_base",
]
sources = [
### gcmole(all) ###
"src/builtins/builtins-arguments-gen.cc",
"src/builtins/builtins-arguments.h",
"src/builtins/builtins-array-gen.cc",
"src/builtins/builtins-async-function-gen.cc",
"src/builtins/builtins-async-gen.cc",
"src/builtins/builtins-async-iterator-gen.cc",
"src/builtins/builtins-async.h",
"src/builtins/builtins-boolean-gen.cc",
"src/builtins/builtins-constructor-gen.cc",
"src/builtins/builtins-constructor.h",
"src/builtins/builtins-conversion-gen.cc",
"src/builtins/builtins-date-gen.cc",
"src/builtins/builtins-forin-gen.cc",
"src/builtins/builtins-forin.h",
"src/builtins/builtins-function-gen.cc",
"src/builtins/builtins-generator-gen.cc",
"src/builtins/builtins-global-gen.cc",
"src/builtins/builtins-handler-gen.cc",
"src/builtins/builtins-ic-gen.cc",
"src/builtins/builtins-internal-gen.cc",
"src/builtins/builtins-math-gen.cc",
"src/builtins/builtins-number-gen.cc",
"src/builtins/builtins-object-gen.cc",
"src/builtins/builtins-promise-gen.cc",
"src/builtins/builtins-promise.h",
"src/builtins/builtins-regexp-gen.cc",
"src/builtins/builtins-regexp-gen.h",
"src/builtins/builtins-sharedarraybuffer-gen.cc",
"src/builtins/builtins-string-gen.cc",
"src/builtins/builtins-symbol-gen.cc",
"src/builtins/builtins-typedarray-gen.cc",
"src/builtins/builtins-utils-gen.h",
"src/builtins/builtins-wasm-gen.cc",
]
configs = [ ":internal_config" ]
}
# This is split out to be a non-code containing target that the Chromium browser
# DLL can depend upon to get only a version string.
v8_header_set("v8_version") {
@ -972,49 +1022,36 @@ v8_source_set("v8_base") {
"src/bootstrapper.cc",
"src/bootstrapper.h",
"src/builtins/builtins-api.cc",
"src/builtins/builtins-arguments.cc",
"src/builtins/builtins-arguments.h",
"src/builtins/builtins-array.cc",
"src/builtins/builtins-arraybuffer.cc",
"src/builtins/builtins-async-function.cc",
"src/builtins/builtins-async-iterator.cc",
"src/builtins/builtins-async.cc",
"src/builtins/builtins-async.h",
"src/builtins/builtins-boolean.cc",
"src/builtins/builtins-call.cc",
"src/builtins/builtins-callsite.cc",
"src/builtins/builtins-constructor.cc",
"src/builtins/builtins-constructor.h",
"src/builtins/builtins-conversion.cc",
"src/builtins/builtins-dataview.cc",
"src/builtins/builtins-date.cc",
"src/builtins/builtins-debug.cc",
"src/builtins/builtins-error.cc",
"src/builtins/builtins-forin.cc",
"src/builtins/builtins-forin.h",
"src/builtins/builtins-function.cc",
"src/builtins/builtins-generator.cc",
"src/builtins/builtins-global.cc",
"src/builtins/builtins-handler.cc",
"src/builtins/builtins-ic.cc",
"src/builtins/builtins-internal.cc",
"src/builtins/builtins-interpreter.cc",
"src/builtins/builtins-json.cc",
"src/builtins/builtins-math.cc",
"src/builtins/builtins-number.cc",
"src/builtins/builtins-object.cc",
"src/builtins/builtins-promise.cc",
"src/builtins/builtins-promise.h",
"src/builtins/builtins-proxy.cc",
"src/builtins/builtins-reflect.cc",
"src/builtins/builtins-regexp-gen.h",
"src/builtins/builtins-regexp.cc",
"src/builtins/builtins-regexp.h",
"src/builtins/builtins-sharedarraybuffer.cc",
"src/builtins/builtins-string.cc",
"src/builtins/builtins-symbol.cc",
"src/builtins/builtins-typedarray.cc",
"src/builtins/builtins-utils.h",
"src/builtins/builtins-wasm.cc",
"src/builtins/builtins.cc",
"src/builtins/builtins.h",
"src/cached-powers.cc",

View File

@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "src/builtins/builtins-arguments.h"
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "src/builtins/builtins-async.h"
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
#include "src/objects-inl.h"
@ -11,13 +11,9 @@
namespace v8 {
namespace internal {
typedef compiler::Node Node;
typedef CodeStubAssembler::ParameterMode ParameterMode;
typedef compiler::CodeAssemblerState CodeAssemblerState;
class AsyncFunctionBuiltinsAssembler : public AsyncBuiltinsAssembler {
public:
explicit AsyncFunctionBuiltinsAssembler(CodeAssemblerState* state)
explicit AsyncFunctionBuiltinsAssembler(compiler::CodeAssemblerState* state)
: AsyncBuiltinsAssembler(state) {}
protected:

View File

@ -3,15 +3,12 @@
// found in the LICENSE file.
#include "src/builtins/builtins-async.h"
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
#include "src/frames-inl.h"
namespace v8 {
namespace internal {
using compiler::Node;
Node* AsyncBuiltinsAssembler::Await(
Node* context, Node* generator, Node* value, Node* outer_promise,
const NodeGenerator1& create_closure_context, int on_resolve_context_index,

View File

@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "src/builtins/builtins-async.h"
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
@ -12,6 +12,8 @@
namespace v8 {
namespace internal {
using compiler::Node;
namespace {
// Describe fields of Context associated with the AsyncIterator unwrap closure.
@ -22,7 +24,7 @@ class ValueUnwrapContext {
class AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler {
public:
explicit AsyncFromSyncBuiltinsAssembler(CodeAssemblerState* state)
explicit AsyncFromSyncBuiltinsAssembler(compiler::CodeAssemblerState* state)
: AsyncBuiltinsAssembler(state) {}
void ThrowIfNotAsyncFromSyncIterator(Node* const context, Node* const object,

View File

@ -12,7 +12,7 @@ namespace internal {
class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler {
public:
explicit AsyncBuiltinsAssembler(CodeAssemblerState* state)
explicit AsyncBuiltinsAssembler(compiler::CodeAssemblerState* state)
: PromiseBuiltinsAssembler(state) {}
protected:

View File

@ -0,0 +1,37 @@
// Copyright 2017 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-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
// ES6 section 19.3 Boolean Objects
// ES6 section 19.3.3.2 Boolean.prototype.toString ( )
TF_BUILTIN(BooleanPrototypeToString, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Node* value = ToThisValue(context, receiver, PrimitiveType::kBoolean,
"Boolean.prototype.toString");
Node* result = LoadObjectField(value, Oddball::kToStringOffset);
Return(result);
}
// ES6 section 19.3.3.3 Boolean.prototype.valueOf ( )
TF_BUILTIN(BooleanPrototypeValueOf, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Node* result = ToThisValue(context, receiver, PrimitiveType::kBoolean,
"Boolean.prototype.valueOf");
Return(result);
}
} // namespace internal
} // namespace v8

View File

@ -4,7 +4,6 @@
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
#include "src/counters.h"
#include "src/objects-inl.h"
@ -36,34 +35,5 @@ BUILTIN(BooleanConstructor_ConstructStub) {
return *result;
}
// ES6 section 19.3.3.2 Boolean.prototype.toString ( )
void Builtins::Generate_BooleanPrototypeToString(
compiler::CodeAssemblerState* state) {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(0);
Node* context = assembler.Parameter(3);
Node* value = assembler.ToThisValue(
context, receiver, PrimitiveType::kBoolean, "Boolean.prototype.toString");
Node* result = assembler.LoadObjectField(value, Oddball::kToStringOffset);
assembler.Return(result);
}
// ES6 section 19.3.3.3 Boolean.prototype.valueOf ( )
void Builtins::Generate_BooleanPrototypeValueOf(
compiler::CodeAssemblerState* state) {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(0);
Node* context = assembler.Parameter(3);
Node* result = assembler.ToThisValue(
context, receiver, PrimitiveType::kBoolean, "Boolean.prototype.valueOf");
assembler.Return(result);
}
} // namespace internal
} // namespace v8

View File

@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins-constructor.h"
#include "src/ast/ast.h"
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins-constructor.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
@ -21,9 +21,6 @@ Node* ConstructorBuiltinsAssembler::EmitFastNewClosure(Node* shared_info,
Node* feedback_vector,
Node* slot,
Node* context) {
typedef compiler::CodeAssembler::Label Label;
typedef compiler::CodeAssembler::Variable Variable;
Isolate* isolate = this->isolate();
Factory* factory = isolate->factory();
IncrementCounter(isolate->counters()->fast_new_closure_total(), 1);
@ -211,9 +208,10 @@ Node* ConstructorBuiltinsAssembler::EmitFastNewObject(Node* context,
return var_obj.value();
}
Node* ConstructorBuiltinsAssembler::EmitFastNewObject(
Node* context, Node* target, Node* new_target,
CodeAssemblerLabel* call_runtime) {
Node* ConstructorBuiltinsAssembler::EmitFastNewObject(Node* context,
Node* target,
Node* new_target,
Label* call_runtime) {
CSA_ASSERT(this, HasInstanceType(target, JS_FUNCTION_TYPE));
CSA_ASSERT(this, IsJSReceiver(new_target));
@ -403,18 +401,6 @@ TF_BUILTIN(FastNewFunctionContextFunction, ConstructorBuiltinsAssembler) {
ScopeType::FUNCTION_SCOPE));
}
Handle<Code> Builtins::NewFunctionContext(ScopeType scope_type) {
switch (scope_type) {
case ScopeType::EVAL_SCOPE:
return FastNewFunctionContextEval();
case ScopeType::FUNCTION_SCOPE:
return FastNewFunctionContextFunction();
default:
UNREACHABLE();
}
return Handle<Code>::null();
}
Node* ConstructorBuiltinsAssembler::EmitFastCloneRegExp(Node* closure,
Node* literal_index,
Node* pattern,
@ -501,12 +487,8 @@ Node* ConstructorBuiltinsAssembler::NonEmptyShallowClone(
}
Node* ConstructorBuiltinsAssembler::EmitFastCloneShallowArray(
Node* closure, Node* literal_index, Node* context,
CodeAssemblerLabel* call_runtime, AllocationSiteMode allocation_site_mode) {
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
typedef compiler::Node Node;
Node* closure, Node* literal_index, Node* context, Label* call_runtime,
AllocationSiteMode allocation_site_mode) {
Label zero_capacity(this), cow_elements(this), fast_elements(this),
return_result(this);
Variable result(this, MachineRepresentation::kTagged);
@ -641,19 +623,6 @@ TF_BUILTIN(FastCloneShallowArrayDontTrack, ConstructorBuiltinsAssembler) {
CreateFastCloneShallowArrayBuiltin(DONT_TRACK_ALLOCATION_SITE);
}
Handle<Code> Builtins::NewCloneShallowArray(
AllocationSiteMode allocation_mode) {
switch (allocation_mode) {
case TRACK_ALLOCATION_SITE:
return FastCloneShallowArrayTrack();
case DONT_TRACK_ALLOCATION_SITE:
return FastCloneShallowArrayDontTrack();
default:
UNREACHABLE();
}
return Handle<Code>::null();
}
// static
int ConstructorBuiltinsAssembler::FastCloneShallowObjectPropertiesCount(
int literal_length) {
@ -667,7 +636,7 @@ int ConstructorBuiltinsAssembler::FastCloneShallowObjectPropertiesCount(
}
Node* ConstructorBuiltinsAssembler::EmitFastCloneShallowObject(
CodeAssemblerLabel* call_runtime, Node* closure, Node* literals_index,
Label* call_runtime, Node* closure, Node* literals_index,
Node* properties_count) {
Node* cell = LoadObjectField(closure, JSFunction::kFeedbackVectorOffset);
Node* feedback_vector = LoadObjectField(cell, Cell::kValueOffset);
@ -768,27 +737,5 @@ SHALLOW_OBJECT_BUILTIN(4);
SHALLOW_OBJECT_BUILTIN(5);
SHALLOW_OBJECT_BUILTIN(6);
Handle<Code> Builtins::NewCloneShallowObject(int length) {
switch (length) {
case 0:
return FastCloneShallowObject0();
case 1:
return FastCloneShallowObject1();
case 2:
return FastCloneShallowObject2();
case 3:
return FastCloneShallowObject3();
case 4:
return FastCloneShallowObject4();
case 5:
return FastCloneShallowObject5();
case 6:
return FastCloneShallowObject6();
default:
UNREACHABLE();
}
return Handle<Code>::null();
}
} // namespace internal
} // namespace v8

View File

@ -7,13 +7,9 @@
namespace v8 {
namespace internal {
typedef compiler::Node Node;
typedef compiler::CodeAssemblerState CodeAssemblerState;
typedef compiler::CodeAssemblerLabel CodeAssemblerLabel;
class ConstructorBuiltinsAssembler : public CodeStubAssembler {
public:
explicit ConstructorBuiltinsAssembler(CodeAssemblerState* state)
explicit ConstructorBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
Node* EmitFastNewClosure(Node* shared_info, Node* feedback_vector, Node* slot,
@ -25,8 +21,7 @@ class ConstructorBuiltinsAssembler : public CodeStubAssembler {
Node* EmitFastCloneRegExp(Node* closure, Node* literal_index, Node* pattern,
Node* flags, Node* context);
Node* EmitFastCloneShallowArray(Node* closure, Node* literal_index,
Node* context,
CodeAssemblerLabel* call_runtime,
Node* context, Label* call_runtime,
AllocationSiteMode allocation_site_mode);
// Maximum number of elements in copied array (chosen so that even an array
@ -40,15 +35,15 @@ class ConstructorBuiltinsAssembler : public CodeStubAssembler {
// Maximum number of properties in copied objects.
static const int kMaximumClonedShallowObjectProperties = 6;
static int FastCloneShallowObjectPropertiesCount(int literal_length);
Node* EmitFastCloneShallowObject(CodeAssemblerLabel* call_runtime,
Node* closure, Node* literals_index,
Node* EmitFastCloneShallowObject(Label* call_runtime, Node* closure,
Node* literals_index,
Node* properties_count);
void CreateFastCloneShallowObjectBuiltin(int properties_count);
Node* EmitFastNewObject(Node* context, Node* target, Node* new_target);
Node* EmitFastNewObject(Node* context, Node* target, Node* new_target,
CodeAssemblerLabel* call_runtime);
Label* call_runtime);
private:
static const int kMaximumSlots = 0x8000;

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
@ -22,19 +22,6 @@ class ConversionBuiltinsAssembler : public CodeStubAssembler {
void Generate_OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint);
};
Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) {
switch (hint) {
case ToPrimitiveHint::kDefault:
return NonPrimitiveToPrimitive_Default();
case ToPrimitiveHint::kNumber:
return NonPrimitiveToPrimitive_Number();
case ToPrimitiveHint::kString:
return NonPrimitiveToPrimitive_String();
}
UNREACHABLE();
return Handle<Code>::null();
}
// ES6 section 7.1.1 ToPrimitive ( input [ , PreferredType ] )
void ConversionBuiltinsAssembler::Generate_NonPrimitiveToPrimitive(
ToPrimitiveHint hint) {
@ -169,17 +156,6 @@ TF_BUILTIN(ToString, CodeStubAssembler) {
{ Return(CallRuntime(Runtime::kToString, context, input)); }
}
Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) {
switch (hint) {
case OrdinaryToPrimitiveHint::kNumber:
return OrdinaryToPrimitive_Number();
case OrdinaryToPrimitiveHint::kString:
return OrdinaryToPrimitive_String();
}
UNREACHABLE();
return Handle<Code>::null();
}
// 7.1.1.1 OrdinaryToPrimitive ( O, hint )
void ConversionBuiltinsAssembler::Generate_OrdinaryToPrimitive(
OrdinaryToPrimitiveHint hint) {

View File

@ -0,0 +1,220 @@
// Copyright 2017 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-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
// ES6 section 20.3 Date Objects
class DateBuiltinsAssembler : public CodeStubAssembler {
public:
explicit DateBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void Generate_DatePrototype_GetField(int field_index);
};
void DateBuiltinsAssembler::Generate_DatePrototype_GetField(int field_index) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Label receiver_not_date(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &receiver_not_date);
Node* receiver_instance_type = LoadInstanceType(receiver);
GotoIf(Word32NotEqual(receiver_instance_type, Int32Constant(JS_DATE_TYPE)),
&receiver_not_date);
// Load the specified date field, falling back to the runtime as necessary.
if (field_index == JSDate::kDateValue) {
Return(LoadObjectField(receiver, JSDate::kValueOffset));
} else {
if (field_index < JSDate::kFirstUncachedField) {
Label stamp_mismatch(this, Label::kDeferred);
Node* date_cache_stamp = Load(
MachineType::AnyTagged(),
ExternalConstant(ExternalReference::date_cache_stamp(isolate())));
Node* cache_stamp = LoadObjectField(receiver, JSDate::kCacheStampOffset);
GotoIf(WordNotEqual(date_cache_stamp, cache_stamp), &stamp_mismatch);
Return(LoadObjectField(
receiver, JSDate::kValueOffset + field_index * kPointerSize));
Bind(&stamp_mismatch);
}
Node* field_index_smi = SmiConstant(Smi::FromInt(field_index));
Node* function =
ExternalConstant(ExternalReference::get_date_field_function(isolate()));
Node* result = CallCFunction2(
MachineType::AnyTagged(), MachineType::AnyTagged(),
MachineType::AnyTagged(), function, receiver, field_index_smi);
Return(result);
}
// Raise a TypeError if the receiver is not a date.
Bind(&receiver_not_date);
{
CallRuntime(Runtime::kThrowNotDateError, context);
Unreachable();
}
}
TF_BUILTIN(DatePrototypeGetDate, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kDay);
}
TF_BUILTIN(DatePrototypeGetDay, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kWeekday);
}
TF_BUILTIN(DatePrototypeGetFullYear, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kYear);
}
TF_BUILTIN(DatePrototypeGetHours, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kHour);
}
TF_BUILTIN(DatePrototypeGetMilliseconds, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMillisecond);
}
TF_BUILTIN(DatePrototypeGetMinutes, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMinute);
}
TF_BUILTIN(DatePrototypeGetMonth, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMonth);
}
TF_BUILTIN(DatePrototypeGetSeconds, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kSecond);
}
TF_BUILTIN(DatePrototypeGetTime, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kDateValue);
}
TF_BUILTIN(DatePrototypeGetTimezoneOffset, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kTimezoneOffset);
}
TF_BUILTIN(DatePrototypeGetUTCDate, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kDayUTC);
}
TF_BUILTIN(DatePrototypeGetUTCDay, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kWeekdayUTC);
}
TF_BUILTIN(DatePrototypeGetUTCFullYear, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kYearUTC);
}
TF_BUILTIN(DatePrototypeGetUTCHours, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kHourUTC);
}
TF_BUILTIN(DatePrototypeGetUTCMilliseconds, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMillisecondUTC);
}
TF_BUILTIN(DatePrototypeGetUTCMinutes, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMinuteUTC);
}
TF_BUILTIN(DatePrototypeGetUTCMonth, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMonthUTC);
}
TF_BUILTIN(DatePrototypeGetUTCSeconds, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kSecondUTC);
}
TF_BUILTIN(DatePrototypeValueOf, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kDateValue);
}
TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* hint = Parameter(1);
Node* context = Parameter(4);
// Check if the {receiver} is actually a JSReceiver.
Label receiver_is_invalid(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &receiver_is_invalid);
GotoIfNot(IsJSReceiver(receiver), &receiver_is_invalid);
// Dispatch to the appropriate OrdinaryToPrimitive builtin.
Label hint_is_number(this), hint_is_string(this),
hint_is_invalid(this, Label::kDeferred);
// Fast cases for internalized strings.
Node* number_string = LoadRoot(Heap::knumber_stringRootIndex);
GotoIf(WordEqual(hint, number_string), &hint_is_number);
Node* default_string = LoadRoot(Heap::kdefault_stringRootIndex);
GotoIf(WordEqual(hint, default_string), &hint_is_string);
Node* string_string = LoadRoot(Heap::kstring_stringRootIndex);
GotoIf(WordEqual(hint, string_string), &hint_is_string);
// Slow-case with actual string comparisons.
Callable string_equal = CodeFactory::StringEqual(isolate());
GotoIf(TaggedIsSmi(hint), &hint_is_invalid);
GotoIfNot(IsString(hint), &hint_is_invalid);
GotoIf(WordEqual(CallStub(string_equal, context, hint, number_string),
TrueConstant()),
&hint_is_number);
GotoIf(WordEqual(CallStub(string_equal, context, hint, default_string),
TrueConstant()),
&hint_is_string);
GotoIf(WordEqual(CallStub(string_equal, context, hint, string_string),
TrueConstant()),
&hint_is_string);
Goto(&hint_is_invalid);
// Use the OrdinaryToPrimitive builtin to convert to a Number.
Bind(&hint_is_number);
{
Callable callable = CodeFactory::OrdinaryToPrimitive(
isolate(), OrdinaryToPrimitiveHint::kNumber);
Node* result = CallStub(callable, context, receiver);
Return(result);
}
// Use the OrdinaryToPrimitive builtin to convert to a String.
Bind(&hint_is_string);
{
Callable callable = CodeFactory::OrdinaryToPrimitive(
isolate(), OrdinaryToPrimitiveHint::kString);
Node* result = CallStub(callable, context, receiver);
Return(result);
}
// Raise a TypeError if the {hint} is invalid.
Bind(&hint_is_invalid);
{
CallRuntime(Runtime::kThrowInvalidHint, context, hint);
Unreachable();
}
// Raise a TypeError if the {receiver} is not a JSReceiver instance.
Bind(&receiver_is_invalid);
{
CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
HeapConstant(factory()->NewStringFromAsciiChecked(
"Date.prototype [ @@toPrimitive ]", TENURED)),
receiver);
Unreachable();
}
}
} // namespace internal
} // namespace v8

View File

@ -17,15 +17,6 @@ namespace internal {
// -----------------------------------------------------------------------------
// ES6 section 20.3 Date Objects
class DateBuiltinsAssembler : public CodeStubAssembler {
public:
explicit DateBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void Generate_DatePrototype_GetField(int field_index);
};
namespace {
// ES6 section 20.3.1.1 Time Values and Time Range
@ -904,200 +895,5 @@ BUILTIN(DatePrototypeToJson) {
}
}
void DateBuiltinsAssembler::Generate_DatePrototype_GetField(int field_index) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Label receiver_not_date(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &receiver_not_date);
Node* receiver_instance_type = LoadInstanceType(receiver);
GotoIf(Word32NotEqual(receiver_instance_type, Int32Constant(JS_DATE_TYPE)),
&receiver_not_date);
// Load the specified date field, falling back to the runtime as necessary.
if (field_index == JSDate::kDateValue) {
Return(LoadObjectField(receiver, JSDate::kValueOffset));
} else {
if (field_index < JSDate::kFirstUncachedField) {
Label stamp_mismatch(this, Label::kDeferred);
Node* date_cache_stamp = Load(
MachineType::AnyTagged(),
ExternalConstant(ExternalReference::date_cache_stamp(isolate())));
Node* cache_stamp = LoadObjectField(receiver, JSDate::kCacheStampOffset);
GotoIf(WordNotEqual(date_cache_stamp, cache_stamp), &stamp_mismatch);
Return(LoadObjectField(
receiver, JSDate::kValueOffset + field_index * kPointerSize));
Bind(&stamp_mismatch);
}
Node* field_index_smi = SmiConstant(Smi::FromInt(field_index));
Node* function =
ExternalConstant(ExternalReference::get_date_field_function(isolate()));
Node* result = CallCFunction2(
MachineType::AnyTagged(), MachineType::AnyTagged(),
MachineType::AnyTagged(), function, receiver, field_index_smi);
Return(result);
}
// Raise a TypeError if the receiver is not a date.
Bind(&receiver_not_date);
{
CallRuntime(Runtime::kThrowNotDateError, context);
Unreachable();
}
}
TF_BUILTIN(DatePrototypeGetDate, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kDay);
}
TF_BUILTIN(DatePrototypeGetDay, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kWeekday);
}
TF_BUILTIN(DatePrototypeGetFullYear, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kYear);
}
TF_BUILTIN(DatePrototypeGetHours, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kHour);
}
TF_BUILTIN(DatePrototypeGetMilliseconds, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMillisecond);
}
TF_BUILTIN(DatePrototypeGetMinutes, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMinute);
}
TF_BUILTIN(DatePrototypeGetMonth, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMonth);
}
TF_BUILTIN(DatePrototypeGetSeconds, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kSecond);
}
TF_BUILTIN(DatePrototypeGetTime, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kDateValue);
}
TF_BUILTIN(DatePrototypeGetTimezoneOffset, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kTimezoneOffset);
}
TF_BUILTIN(DatePrototypeGetUTCDate, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kDayUTC);
}
TF_BUILTIN(DatePrototypeGetUTCDay, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kWeekdayUTC);
}
TF_BUILTIN(DatePrototypeGetUTCFullYear, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kYearUTC);
}
TF_BUILTIN(DatePrototypeGetUTCHours, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kHourUTC);
}
TF_BUILTIN(DatePrototypeGetUTCMilliseconds, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMillisecondUTC);
}
TF_BUILTIN(DatePrototypeGetUTCMinutes, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMinuteUTC);
}
TF_BUILTIN(DatePrototypeGetUTCMonth, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kMonthUTC);
}
TF_BUILTIN(DatePrototypeGetUTCSeconds, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kSecondUTC);
}
TF_BUILTIN(DatePrototypeValueOf, DateBuiltinsAssembler) {
Generate_DatePrototype_GetField(JSDate::kDateValue);
}
TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* hint = Parameter(1);
Node* context = Parameter(4);
// Check if the {receiver} is actually a JSReceiver.
Label receiver_is_invalid(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &receiver_is_invalid);
GotoIfNot(IsJSReceiver(receiver), &receiver_is_invalid);
// Dispatch to the appropriate OrdinaryToPrimitive builtin.
Label hint_is_number(this), hint_is_string(this),
hint_is_invalid(this, Label::kDeferred);
// Fast cases for internalized strings.
Node* number_string = LoadRoot(Heap::knumber_stringRootIndex);
GotoIf(WordEqual(hint, number_string), &hint_is_number);
Node* default_string = LoadRoot(Heap::kdefault_stringRootIndex);
GotoIf(WordEqual(hint, default_string), &hint_is_string);
Node* string_string = LoadRoot(Heap::kstring_stringRootIndex);
GotoIf(WordEqual(hint, string_string), &hint_is_string);
// Slow-case with actual string comparisons.
Callable string_equal = CodeFactory::StringEqual(isolate());
GotoIf(TaggedIsSmi(hint), &hint_is_invalid);
GotoIfNot(IsString(hint), &hint_is_invalid);
GotoIf(WordEqual(CallStub(string_equal, context, hint, number_string),
TrueConstant()),
&hint_is_number);
GotoIf(WordEqual(CallStub(string_equal, context, hint, default_string),
TrueConstant()),
&hint_is_string);
GotoIf(WordEqual(CallStub(string_equal, context, hint, string_string),
TrueConstant()),
&hint_is_string);
Goto(&hint_is_invalid);
// Use the OrdinaryToPrimitive builtin to convert to a Number.
Bind(&hint_is_number);
{
Callable callable = CodeFactory::OrdinaryToPrimitive(
isolate(), OrdinaryToPrimitiveHint::kNumber);
Node* result = CallStub(callable, context, receiver);
Return(result);
}
// Use the OrdinaryToPrimitive builtin to convert to a String.
Bind(&hint_is_string);
{
Callable callable = CodeFactory::OrdinaryToPrimitive(
isolate(), OrdinaryToPrimitiveHint::kString);
Node* result = CallStub(callable, context, receiver);
Return(result);
}
// Raise a TypeError if the {hint} is invalid.
Bind(&hint_is_invalid);
{
CallRuntime(Runtime::kThrowInvalidHint, context, hint);
Unreachable();
}
// Raise a TypeError if the {receiver} is not a JSReceiver instance.
Bind(&receiver_is_invalid);
{
CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
HeapConstant(factory()->NewStringFromAsciiChecked(
"Date.prototype [ @@toPrimitive ]", TENURED)),
receiver);
Unreachable();
}
}
} // namespace internal
} // namespace v8

View File

@ -4,7 +4,7 @@
#include "src/builtins/builtins-forin.h"
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"

View File

@ -0,0 +1,178 @@
// Copyright 2017 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-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
Label slow(this);
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
// Check that receiver has instance type of JS_FUNCTION_TYPE
Node* receiver = args.GetReceiver();
GotoIf(TaggedIsSmi(receiver), &slow);
Node* receiver_map = LoadMap(receiver);
Node* instance_type = LoadMapInstanceType(receiver_map);
GotoIf(Word32NotEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)), &slow);
// Disallow binding of slow-mode functions. We need to figure out whether the
// length and name property are in the original state.
Comment("Disallow binding of slow-mode functions");
GotoIf(IsDictionaryMap(receiver_map), &slow);
// Check whether the length and name properties are still present as
// AccessorInfo objects. In that case, their value can be recomputed even if
// the actual value on the object changes.
Comment("Check descriptor array length");
Node* descriptors = LoadMapDescriptors(receiver_map);
Node* descriptors_length = LoadFixedArrayBaseLength(descriptors);
GotoIf(SmiLessThanOrEqual(descriptors_length, SmiConstant(1)), &slow);
// Check whether the length and name properties are still present as
// AccessorInfo objects. In that case, their value can be recomputed even if
// the actual value on the object changes.
Comment("Check name and length properties");
const int length_index = JSFunction::kLengthDescriptorIndex;
Node* maybe_length = LoadFixedArrayElement(
descriptors, DescriptorArray::ToKeyIndex(length_index));
GotoIf(WordNotEqual(maybe_length, LoadRoot(Heap::klength_stringRootIndex)),
&slow);
Node* maybe_length_accessor = LoadFixedArrayElement(
descriptors, DescriptorArray::ToValueIndex(length_index));
GotoIf(TaggedIsSmi(maybe_length_accessor), &slow);
Node* length_value_map = LoadMap(maybe_length_accessor);
GotoIfNot(IsAccessorInfoMap(length_value_map), &slow);
const int name_index = JSFunction::kNameDescriptorIndex;
Node* maybe_name = LoadFixedArrayElement(
descriptors, DescriptorArray::ToKeyIndex(name_index));
GotoIf(WordNotEqual(maybe_name, LoadRoot(Heap::kname_stringRootIndex)),
&slow);
Node* maybe_name_accessor = LoadFixedArrayElement(
descriptors, DescriptorArray::ToValueIndex(name_index));
GotoIf(TaggedIsSmi(maybe_name_accessor), &slow);
Node* name_value_map = LoadMap(maybe_name_accessor);
GotoIfNot(IsAccessorInfoMap(name_value_map), &slow);
// Choose the right bound function map based on whether the target is
// constructable.
Comment("Choose the right bound function map");
Variable bound_function_map(this, MachineRepresentation::kTagged);
Label with_constructor(this);
VariableList vars({&bound_function_map}, zone());
Node* native_context = LoadNativeContext(context);
Label map_done(this, vars);
Node* bit_field = LoadMapBitField(receiver_map);
int mask = static_cast<int>(1 << Map::kIsConstructor);
GotoIf(IsSetWord32(bit_field, mask), &with_constructor);
bound_function_map.Bind(LoadContextElement(
native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
Goto(&map_done);
Bind(&with_constructor);
bound_function_map.Bind(LoadContextElement(
native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
Goto(&map_done);
Bind(&map_done);
// Verify that __proto__ matches that of a the target bound function.
Comment("Verify that __proto__ matches target bound function");
Node* prototype = LoadMapPrototype(receiver_map);
Node* expected_prototype = LoadMapPrototype(bound_function_map.value());
GotoIf(WordNotEqual(prototype, expected_prototype), &slow);
// Allocate the arguments array.
Comment("Allocate the arguments array");
Variable argument_array(this, MachineRepresentation::kTagged);
Label empty_arguments(this);
Label arguments_done(this, &argument_array);
GotoIf(Uint32LessThanOrEqual(argc, Int32Constant(1)), &empty_arguments);
Node* elements_length = ChangeUint32ToWord(Int32Sub(argc, Int32Constant(1)));
Node* elements = AllocateFixedArray(FAST_ELEMENTS, elements_length);
Variable index(this, MachineType::PointerRepresentation());
index.Bind(IntPtrConstant(0));
VariableList foreach_vars({&index}, zone());
args.ForEach(foreach_vars,
[this, elements, &index](Node* arg) {
StoreFixedArrayElement(elements, index.value(), arg);
Increment(index);
},
IntPtrConstant(1));
argument_array.Bind(elements);
Goto(&arguments_done);
Bind(&empty_arguments);
argument_array.Bind(EmptyFixedArrayConstant());
Goto(&arguments_done);
Bind(&arguments_done);
// Determine bound receiver.
Comment("Determine bound receiver");
Variable bound_receiver(this, MachineRepresentation::kTagged);
Label has_receiver(this);
Label receiver_done(this, &bound_receiver);
GotoIf(Word32NotEqual(argc, Int32Constant(0)), &has_receiver);
bound_receiver.Bind(UndefinedConstant());
Goto(&receiver_done);
Bind(&has_receiver);
bound_receiver.Bind(args.AtIndex(0));
Goto(&receiver_done);
Bind(&receiver_done);
// Allocate the resulting bound function.
Comment("Allocate the resulting bound function");
Node* bound_function = Allocate(JSBoundFunction::kSize);
StoreMapNoWriteBarrier(bound_function, bound_function_map.value());
StoreObjectFieldNoWriteBarrier(
bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver);
StoreObjectFieldNoWriteBarrier(bound_function,
JSBoundFunction::kBoundThisOffset,
bound_receiver.value());
StoreObjectFieldNoWriteBarrier(bound_function,
JSBoundFunction::kBoundArgumentsOffset,
argument_array.value());
Node* empty_fixed_array = EmptyFixedArrayConstant();
StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kPropertiesOffset,
empty_fixed_array);
StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kElementsOffset,
empty_fixed_array);
args.PopAndReturn(bound_function);
Bind(&slow);
Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
MachineType::TaggedPointer());
TailCallStub(CodeFactory::FunctionPrototypeBind(isolate()), context, target,
new_target, argc);
}
// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V )
TF_BUILTIN(FunctionPrototypeHasInstance, CodeStubAssembler) {
Node* f = Parameter(0);
Node* v = Parameter(1);
Node* context = Parameter(4);
Node* result = OrdinaryHasInstance(context, f, v);
Return(result);
}
} // namespace internal
} // namespace v8

View File

@ -5,7 +5,6 @@
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
#include "src/compiler.h"
#include "src/conversions.h"
#include "src/counters.h"
@ -272,162 +271,6 @@ Object* DoFunctionBind(Isolate* isolate, BuiltinArguments args) {
// ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args )
BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); }
TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) {
Label slow(this);
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
Node* new_target = Parameter(BuiltinDescriptor::kNewTarget);
CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
// Check that receiver has instance type of JS_FUNCTION_TYPE
Node* receiver = args.GetReceiver();
GotoIf(TaggedIsSmi(receiver), &slow);
Node* receiver_map = LoadMap(receiver);
Node* instance_type = LoadMapInstanceType(receiver_map);
GotoIf(Word32NotEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)), &slow);
// Disallow binding of slow-mode functions. We need to figure out whether the
// length and name property are in the original state.
Comment("Disallow binding of slow-mode functions");
GotoIf(IsDictionaryMap(receiver_map), &slow);
// Check whether the length and name properties are still present as
// AccessorInfo objects. In that case, their value can be recomputed even if
// the actual value on the object changes.
Comment("Check descriptor array length");
Node* descriptors = LoadMapDescriptors(receiver_map);
Node* descriptors_length = LoadFixedArrayBaseLength(descriptors);
GotoIf(SmiLessThanOrEqual(descriptors_length, SmiConstant(1)), &slow);
// Check whether the length and name properties are still present as
// AccessorInfo objects. In that case, their value can be recomputed even if
// the actual value on the object changes.
Comment("Check name and length properties");
const int length_index = JSFunction::kLengthDescriptorIndex;
Node* maybe_length = LoadFixedArrayElement(
descriptors, DescriptorArray::ToKeyIndex(length_index));
GotoIf(WordNotEqual(maybe_length, LoadRoot(Heap::klength_stringRootIndex)),
&slow);
Node* maybe_length_accessor = LoadFixedArrayElement(
descriptors, DescriptorArray::ToValueIndex(length_index));
GotoIf(TaggedIsSmi(maybe_length_accessor), &slow);
Node* length_value_map = LoadMap(maybe_length_accessor);
GotoIfNot(IsAccessorInfoMap(length_value_map), &slow);
const int name_index = JSFunction::kNameDescriptorIndex;
Node* maybe_name = LoadFixedArrayElement(
descriptors, DescriptorArray::ToKeyIndex(name_index));
GotoIf(WordNotEqual(maybe_name, LoadRoot(Heap::kname_stringRootIndex)),
&slow);
Node* maybe_name_accessor = LoadFixedArrayElement(
descriptors, DescriptorArray::ToValueIndex(name_index));
GotoIf(TaggedIsSmi(maybe_name_accessor), &slow);
Node* name_value_map = LoadMap(maybe_name_accessor);
GotoIfNot(IsAccessorInfoMap(name_value_map), &slow);
// Choose the right bound function map based on whether the target is
// constructable.
Comment("Choose the right bound function map");
Variable bound_function_map(this, MachineRepresentation::kTagged);
Label with_constructor(this);
VariableList vars({&bound_function_map}, zone());
Node* native_context = LoadNativeContext(context);
Label map_done(this, vars);
Node* bit_field = LoadMapBitField(receiver_map);
int mask = static_cast<int>(1 << Map::kIsConstructor);
GotoIf(IsSetWord32(bit_field, mask), &with_constructor);
bound_function_map.Bind(LoadContextElement(
native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
Goto(&map_done);
Bind(&with_constructor);
bound_function_map.Bind(LoadContextElement(
native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
Goto(&map_done);
Bind(&map_done);
// Verify that __proto__ matches that of a the target bound function.
Comment("Verify that __proto__ matches target bound function");
Node* prototype = LoadMapPrototype(receiver_map);
Node* expected_prototype = LoadMapPrototype(bound_function_map.value());
GotoIf(WordNotEqual(prototype, expected_prototype), &slow);
// Allocate the arguments array.
Comment("Allocate the arguments array");
Variable argument_array(this, MachineRepresentation::kTagged);
Label empty_arguments(this);
Label arguments_done(this, &argument_array);
GotoIf(Uint32LessThanOrEqual(argc, Int32Constant(1)), &empty_arguments);
Node* elements_length = ChangeUint32ToWord(Int32Sub(argc, Int32Constant(1)));
Node* elements = AllocateFixedArray(FAST_ELEMENTS, elements_length);
Variable index(this, MachineType::PointerRepresentation());
index.Bind(IntPtrConstant(0));
VariableList foreach_vars({&index}, zone());
args.ForEach(foreach_vars,
[this, elements, &index](Node* arg) {
StoreFixedArrayElement(elements, index.value(), arg);
Increment(index);
},
IntPtrConstant(1));
argument_array.Bind(elements);
Goto(&arguments_done);
Bind(&empty_arguments);
argument_array.Bind(EmptyFixedArrayConstant());
Goto(&arguments_done);
Bind(&arguments_done);
// Determine bound receiver.
Comment("Determine bound receiver");
Variable bound_receiver(this, MachineRepresentation::kTagged);
Label has_receiver(this);
Label receiver_done(this, &bound_receiver);
GotoIf(Word32NotEqual(argc, Int32Constant(0)), &has_receiver);
bound_receiver.Bind(UndefinedConstant());
Goto(&receiver_done);
Bind(&has_receiver);
bound_receiver.Bind(args.AtIndex(0));
Goto(&receiver_done);
Bind(&receiver_done);
// Allocate the resulting bound function.
Comment("Allocate the resulting bound function");
Node* bound_function = Allocate(JSBoundFunction::kSize);
StoreMapNoWriteBarrier(bound_function, bound_function_map.value());
StoreObjectFieldNoWriteBarrier(
bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver);
StoreObjectFieldNoWriteBarrier(bound_function,
JSBoundFunction::kBoundThisOffset,
bound_receiver.value());
StoreObjectFieldNoWriteBarrier(bound_function,
JSBoundFunction::kBoundArgumentsOffset,
argument_array.value());
Node* empty_fixed_array = EmptyFixedArrayConstant();
StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kPropertiesOffset,
empty_fixed_array);
StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kElementsOffset,
empty_fixed_array);
args.PopAndReturn(bound_function);
Bind(&slow);
Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset,
MachineType::TaggedPointer());
TailCallStub(CodeFactory::FunctionPrototypeBind(isolate()), context, target,
new_target, argc);
}
// TODO(verwaest): This is a temporary helper until the FastFunctionBind stub
// can tailcall to the builtin directly.
RUNTIME_FUNCTION(Runtime_FunctionBind) {
@ -454,14 +297,5 @@ BUILTIN(FunctionPrototypeToString) {
"Function.prototype.toString")));
}
// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V )
TF_BUILTIN(FunctionPrototypeHasInstance, CodeStubAssembler) {
Node* f = Parameter(0);
Node* v = Parameter(1);
Node* context = Parameter(4);
Node* result = OrdinaryHasInstance(context, f, v);
Return(result);
}
} // namespace internal
} // namespace v8

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
@ -12,11 +12,9 @@
namespace v8 {
namespace internal {
typedef compiler::CodeAssemblerState CodeAssemblerState;
class GeneratorBuiltinsAssembler : public CodeStubAssembler {
public:
explicit GeneratorBuiltinsAssembler(CodeAssemblerState* state)
explicit GeneratorBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:

View File

@ -0,0 +1,108 @@
// Copyright 2017 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-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
// ES6 section 18.2.2 isFinite ( number )
TF_BUILTIN(GlobalIsFinite, CodeStubAssembler) {
Node* context = Parameter(4);
Label return_true(this), return_false(this);
// We might need to loop once for ToNumber conversion.
Variable var_num(this, MachineRepresentation::kTagged);
Label loop(this, &var_num);
var_num.Bind(Parameter(1));
Goto(&loop);
Bind(&loop);
{
Node* num = var_num.value();
// Check if {num} is a Smi or a HeapObject.
GotoIf(TaggedIsSmi(num), &return_true);
// Check if {num} is a HeapNumber.
Label if_numisheapnumber(this),
if_numisnotheapnumber(this, Label::kDeferred);
Branch(IsHeapNumberMap(LoadMap(num)), &if_numisheapnumber,
&if_numisnotheapnumber);
Bind(&if_numisheapnumber);
{
// Check if {num} contains a finite, non-NaN value.
Node* num_value = LoadHeapNumberValue(num);
BranchIfFloat64IsNaN(Float64Sub(num_value, num_value), &return_false,
&return_true);
}
Bind(&if_numisnotheapnumber);
{
// Need to convert {num} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_num.Bind(CallStub(callable, context, num));
Goto(&loop);
}
}
Bind(&return_true);
Return(BooleanConstant(true));
Bind(&return_false);
Return(BooleanConstant(false));
}
// ES6 section 18.2.3 isNaN ( number )
TF_BUILTIN(GlobalIsNaN, CodeStubAssembler) {
Node* context = Parameter(4);
Label return_true(this), return_false(this);
// We might need to loop once for ToNumber conversion.
Variable var_num(this, MachineRepresentation::kTagged);
Label loop(this, &var_num);
var_num.Bind(Parameter(1));
Goto(&loop);
Bind(&loop);
{
Node* num = var_num.value();
// Check if {num} is a Smi or a HeapObject.
GotoIf(TaggedIsSmi(num), &return_false);
// Check if {num} is a HeapNumber.
Label if_numisheapnumber(this),
if_numisnotheapnumber(this, Label::kDeferred);
Branch(IsHeapNumberMap(LoadMap(num)), &if_numisheapnumber,
&if_numisnotheapnumber);
Bind(&if_numisheapnumber);
{
// Check if {num} contains a NaN.
Node* num_value = LoadHeapNumberValue(num);
BranchIfFloat64IsNaN(num_value, &return_true, &return_false);
}
Bind(&if_numisnotheapnumber);
{
// Need to convert {num} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_num.Bind(CallStub(callable, context, num));
Goto(&loop);
}
}
Bind(&return_true);
Return(BooleanConstant(true));
Bind(&return_false);
Return(BooleanConstant(false));
}
} // namespace internal
} // namespace v8

View File

@ -5,7 +5,6 @@
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
#include "src/compiler.h"
#include "src/counters.h"
#include "src/objects-inl.h"
@ -103,100 +102,5 @@ BUILTIN(GlobalEval) {
Execution::Call(isolate, function, target_global_proxy, 0, nullptr));
}
// ES6 section 18.2.2 isFinite ( number )
TF_BUILTIN(GlobalIsFinite, CodeStubAssembler) {
Node* context = Parameter(4);
Label return_true(this), return_false(this);
// We might need to loop once for ToNumber conversion.
Variable var_num(this, MachineRepresentation::kTagged);
Label loop(this, &var_num);
var_num.Bind(Parameter(1));
Goto(&loop);
Bind(&loop);
{
Node* num = var_num.value();
// Check if {num} is a Smi or a HeapObject.
GotoIf(TaggedIsSmi(num), &return_true);
// Check if {num} is a HeapNumber.
Label if_numisheapnumber(this),
if_numisnotheapnumber(this, Label::kDeferred);
Branch(IsHeapNumberMap(LoadMap(num)), &if_numisheapnumber,
&if_numisnotheapnumber);
Bind(&if_numisheapnumber);
{
// Check if {num} contains a finite, non-NaN value.
Node* num_value = LoadHeapNumberValue(num);
BranchIfFloat64IsNaN(Float64Sub(num_value, num_value), &return_false,
&return_true);
}
Bind(&if_numisnotheapnumber);
{
// Need to convert {num} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_num.Bind(CallStub(callable, context, num));
Goto(&loop);
}
}
Bind(&return_true);
Return(BooleanConstant(true));
Bind(&return_false);
Return(BooleanConstant(false));
}
// ES6 section 18.2.3 isNaN ( number )
TF_BUILTIN(GlobalIsNaN, CodeStubAssembler) {
Node* context = Parameter(4);
Label return_true(this), return_false(this);
// We might need to loop once for ToNumber conversion.
Variable var_num(this, MachineRepresentation::kTagged);
Label loop(this, &var_num);
var_num.Bind(Parameter(1));
Goto(&loop);
Bind(&loop);
{
Node* num = var_num.value();
// Check if {num} is a Smi or a HeapObject.
GotoIf(TaggedIsSmi(num), &return_false);
// Check if {num} is a HeapNumber.
Label if_numisheapnumber(this),
if_numisnotheapnumber(this, Label::kDeferred);
Branch(IsHeapNumberMap(LoadMap(num)), &if_numisheapnumber,
&if_numisnotheapnumber);
Bind(&if_numisheapnumber);
{
// Check if {num} contains a NaN.
Node* num_value = LoadHeapNumberValue(num);
BranchIfFloat64IsNaN(num_value, &return_true, &return_false);
}
Bind(&if_numisnotheapnumber);
{
// Need to convert {num} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_num.Bind(CallStub(callable, context, num));
Goto(&loop);
}
}
Bind(&return_true);
Return(BooleanConstant(true));
Bind(&return_false);
Return(BooleanConstant(false));
}
} // namespace internal
} // namespace v8

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
#include "src/ic/handler-compiler.h"

View File

@ -2,10 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/ic/accessor-assembler.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {

View File

@ -0,0 +1,174 @@
// Copyright 2017 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-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
#include "src/macro-assembler.h"
#include "src/runtime/runtime.h"
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
// Interrupt and stack checks.
void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
masm->TailCallRuntime(Runtime::kInterrupt);
}
void Builtins::Generate_StackCheck(MacroAssembler* masm) {
masm->TailCallRuntime(Runtime::kStackGuard);
}
// -----------------------------------------------------------------------------
// TurboFan support builtins.
TF_BUILTIN(CopyFastSmiOrObjectElements, CodeStubAssembler) {
typedef CopyFastSmiOrObjectElementsDescriptor Descriptor;
Node* object = Parameter(Descriptor::kObject);
// Load the {object}s elements.
Node* source = LoadObjectField(object, JSObject::kElementsOffset);
ParameterMode mode = OptimalParameterMode();
Node* length = TaggedToParameter(LoadFixedArrayBaseLength(source), mode);
// Check if we can allocate in new space.
ElementsKind kind = FAST_ELEMENTS;
int max_elements = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind);
Label if_newspace(this), if_oldspace(this);
Branch(UintPtrOrSmiLessThan(length, IntPtrOrSmiConstant(max_elements, mode),
mode),
&if_newspace, &if_oldspace);
Bind(&if_newspace);
{
Node* target = AllocateFixedArray(kind, length, mode);
CopyFixedArrayElements(kind, source, target, length, SKIP_WRITE_BARRIER,
mode);
StoreObjectField(object, JSObject::kElementsOffset, target);
Return(target);
}
Bind(&if_oldspace);
{
Node* target = AllocateFixedArray(kind, length, mode, kPretenured);
CopyFixedArrayElements(kind, source, target, length, UPDATE_WRITE_BARRIER,
mode);
StoreObjectField(object, JSObject::kElementsOffset, target);
Return(target);
}
}
TF_BUILTIN(GrowFastDoubleElements, CodeStubAssembler) {
typedef GrowArrayElementsDescriptor Descriptor;
Node* object = Parameter(Descriptor::kObject);
Node* key = Parameter(Descriptor::kKey);
Node* context = Parameter(Descriptor::kContext);
Label runtime(this, Label::kDeferred);
Node* elements = LoadElements(object);
elements = TryGrowElementsCapacity(object, elements, FAST_DOUBLE_ELEMENTS,
key, &runtime);
Return(elements);
Bind(&runtime);
TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
}
TF_BUILTIN(GrowFastSmiOrObjectElements, CodeStubAssembler) {
typedef GrowArrayElementsDescriptor Descriptor;
Node* object = Parameter(Descriptor::kObject);
Node* key = Parameter(Descriptor::kKey);
Node* context = Parameter(Descriptor::kContext);
Label runtime(this, Label::kDeferred);
Node* elements = LoadElements(object);
elements =
TryGrowElementsCapacity(object, elements, FAST_ELEMENTS, key, &runtime);
Return(elements);
Bind(&runtime);
TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
}
TF_BUILTIN(NewUnmappedArgumentsElements, CodeStubAssembler) {
typedef NewArgumentsElementsDescriptor Descriptor;
Node* frame = Parameter(Descriptor::kFrame);
Node* length = SmiToWord(Parameter(Descriptor::kLength));
// Check if we can allocate in new space.
ElementsKind kind = FAST_ELEMENTS;
int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind);
Label if_newspace(this), if_oldspace(this, Label::kDeferred);
Branch(IntPtrLessThan(length, IntPtrConstant(max_elements)), &if_newspace,
&if_oldspace);
Bind(&if_newspace);
{
// Prefer EmptyFixedArray in case of non-positive {length} (the {length}
// can be negative here for rest parameters).
Label if_empty(this), if_notempty(this);
Branch(IntPtrLessThanOrEqual(length, IntPtrConstant(0)), &if_empty,
&if_notempty);
Bind(&if_empty);
Return(EmptyFixedArrayConstant());
Bind(&if_notempty);
{
// Allocate a FixedArray in new space.
Node* result = AllocateFixedArray(kind, length);
// Compute the effective {offset} into the {frame}.
Node* offset = IntPtrAdd(length, IntPtrConstant(1));
// Copy the parameters from {frame} (starting at {offset}) to {result}.
Variable var_index(this, MachineType::PointerRepresentation());
Label loop(this, &var_index), done_loop(this);
var_index.Bind(IntPtrConstant(0));
Goto(&loop);
Bind(&loop);
{
// Load the current {index}.
Node* index = var_index.value();
// Check if we are done.
GotoIf(WordEqual(index, length), &done_loop);
// Load the parameter at the given {index}.
Node* value = Load(MachineType::AnyTagged(), frame,
WordShl(IntPtrSub(offset, index),
IntPtrConstant(kPointerSizeLog2)));
// Store the {value} into the {result}.
StoreFixedArrayElement(result, index, value, SKIP_WRITE_BARRIER);
// Continue with next {index}.
var_index.Bind(IntPtrAdd(index, IntPtrConstant(1)));
Goto(&loop);
}
Bind(&done_loop);
Return(result);
}
}
Bind(&if_oldspace);
{
// Allocate in old space (or large object space).
TailCallRuntime(Runtime::kNewArgumentsElements, NoContextConstant(),
BitcastWordToTagged(frame), SmiFromWord(length));
}
}
TF_BUILTIN(ReturnReceiver, CodeStubAssembler) { Return(Parameter(0)); }
} // namespace internal
} // namespace v8

View File

@ -4,10 +4,8 @@
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
#include "src/counters.h"
#include "src/interface-descriptors.h"
#include "src/macro-assembler.h"
#include "src/objects-inl.h"
namespace v8 {
@ -42,164 +40,5 @@ BUILTIN(RestrictedStrictArgumentsPropertiesThrower) {
isolate, NewTypeError(MessageTemplate::kStrictPoisonPill));
}
// -----------------------------------------------------------------------------
// Interrupt and stack checks.
void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
masm->TailCallRuntime(Runtime::kInterrupt);
}
void Builtins::Generate_StackCheck(MacroAssembler* masm) {
masm->TailCallRuntime(Runtime::kStackGuard);
}
// -----------------------------------------------------------------------------
// TurboFan support builtins.
TF_BUILTIN(CopyFastSmiOrObjectElements, CodeStubAssembler) {
typedef CopyFastSmiOrObjectElementsDescriptor Descriptor;
Node* object = Parameter(Descriptor::kObject);
// Load the {object}s elements.
Node* source = LoadObjectField(object, JSObject::kElementsOffset);
ParameterMode mode = OptimalParameterMode();
Node* length = TaggedToParameter(LoadFixedArrayBaseLength(source), mode);
// Check if we can allocate in new space.
ElementsKind kind = FAST_ELEMENTS;
int max_elements = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind);
Label if_newspace(this), if_oldspace(this);
Branch(UintPtrOrSmiLessThan(length, IntPtrOrSmiConstant(max_elements, mode),
mode),
&if_newspace, &if_oldspace);
Bind(&if_newspace);
{
Node* target = AllocateFixedArray(kind, length, mode);
CopyFixedArrayElements(kind, source, target, length, SKIP_WRITE_BARRIER,
mode);
StoreObjectField(object, JSObject::kElementsOffset, target);
Return(target);
}
Bind(&if_oldspace);
{
Node* target = AllocateFixedArray(kind, length, mode, kPretenured);
CopyFixedArrayElements(kind, source, target, length, UPDATE_WRITE_BARRIER,
mode);
StoreObjectField(object, JSObject::kElementsOffset, target);
Return(target);
}
}
TF_BUILTIN(GrowFastDoubleElements, CodeStubAssembler) {
typedef GrowArrayElementsDescriptor Descriptor;
Node* object = Parameter(Descriptor::kObject);
Node* key = Parameter(Descriptor::kKey);
Node* context = Parameter(Descriptor::kContext);
Label runtime(this, Label::kDeferred);
Node* elements = LoadElements(object);
elements = TryGrowElementsCapacity(object, elements, FAST_DOUBLE_ELEMENTS,
key, &runtime);
Return(elements);
Bind(&runtime);
TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
}
TF_BUILTIN(GrowFastSmiOrObjectElements, CodeStubAssembler) {
typedef GrowArrayElementsDescriptor Descriptor;
Node* object = Parameter(Descriptor::kObject);
Node* key = Parameter(Descriptor::kKey);
Node* context = Parameter(Descriptor::kContext);
Label runtime(this, Label::kDeferred);
Node* elements = LoadElements(object);
elements =
TryGrowElementsCapacity(object, elements, FAST_ELEMENTS, key, &runtime);
Return(elements);
Bind(&runtime);
TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
}
TF_BUILTIN(NewUnmappedArgumentsElements, CodeStubAssembler) {
typedef NewArgumentsElementsDescriptor Descriptor;
Node* frame = Parameter(Descriptor::kFrame);
Node* length = SmiToWord(Parameter(Descriptor::kLength));
// Check if we can allocate in new space.
ElementsKind kind = FAST_ELEMENTS;
int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind);
Label if_newspace(this), if_oldspace(this, Label::kDeferred);
Branch(IntPtrLessThan(length, IntPtrConstant(max_elements)), &if_newspace,
&if_oldspace);
Bind(&if_newspace);
{
// Prefer EmptyFixedArray in case of non-positive {length} (the {length}
// can be negative here for rest parameters).
Label if_empty(this), if_notempty(this);
Branch(IntPtrLessThanOrEqual(length, IntPtrConstant(0)), &if_empty,
&if_notempty);
Bind(&if_empty);
Return(EmptyFixedArrayConstant());
Bind(&if_notempty);
{
// Allocate a FixedArray in new space.
Node* result = AllocateFixedArray(kind, length);
// Compute the effective {offset} into the {frame}.
Node* offset = IntPtrAdd(length, IntPtrConstant(1));
// Copy the parameters from {frame} (starting at {offset}) to {result}.
Variable var_index(this, MachineType::PointerRepresentation());
Label loop(this, &var_index), done_loop(this);
var_index.Bind(IntPtrConstant(0));
Goto(&loop);
Bind(&loop);
{
// Load the current {index}.
Node* index = var_index.value();
// Check if we are done.
GotoIf(WordEqual(index, length), &done_loop);
// Load the parameter at the given {index}.
Node* value = Load(MachineType::AnyTagged(), frame,
WordShl(IntPtrSub(offset, index),
IntPtrConstant(kPointerSizeLog2)));
// Store the {value} into the {result}.
StoreFixedArrayElement(result, index, value, SKIP_WRITE_BARRIER);
// Continue with next {index}.
var_index.Bind(IntPtrAdd(index, IntPtrConstant(1)));
Goto(&loop);
}
Bind(&done_loop);
Return(result);
}
}
Bind(&if_oldspace);
{
// Allocate in old space (or large object space).
TailCallRuntime(Runtime::kNewArgumentsElements, NoContextConstant(),
BitcastWordToTagged(frame), SmiFromWord(length));
}
}
TF_BUILTIN(ReturnReceiver, CodeStubAssembler) { Return(Parameter(0)); }
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,476 @@
// Copyright 2017 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-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
// ES6 section 20.2.2 Function Properties of the Math Object
class MathBuiltinsAssembler : public CodeStubAssembler {
public:
explicit MathBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void MathRoundingOperation(Node* (CodeStubAssembler::*float64op)(Node*));
void MathUnaryOperation(Node* (CodeStubAssembler::*float64op)(Node*));
void MathMaxMin(Node* (CodeStubAssembler::*float64op)(Node*, Node*),
double default_val);
};
// ES6 section - 20.2.2.1 Math.abs ( x )
TF_BUILTIN(MathAbs, CodeStubAssembler) {
Node* context = Parameter(4);
// We might need to loop once for ToNumber conversion.
Variable var_x(this, MachineRepresentation::kTagged);
Label loop(this, &var_x);
var_x.Bind(Parameter(1));
Goto(&loop);
Bind(&loop);
{
// Load the current {x} value.
Node* x = var_x.value();
// Check if {x} is a Smi or a HeapObject.
Label if_xissmi(this), if_xisnotsmi(this);
Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
Bind(&if_xissmi);
{
// Check if {x} is already positive.
Label if_xispositive(this), if_xisnotpositive(this);
BranchIfSmiLessThanOrEqual(SmiConstant(Smi::FromInt(0)), x,
&if_xispositive, &if_xisnotpositive);
Bind(&if_xispositive);
{
// Just return the input {x}.
Return(x);
}
Bind(&if_xisnotpositive);
{
// Try to negate the {x} value.
Node* pair =
IntPtrSubWithOverflow(IntPtrConstant(0), BitcastTaggedToWord(x));
Node* overflow = Projection(1, pair);
Label if_overflow(this, Label::kDeferred), if_notoverflow(this);
Branch(overflow, &if_overflow, &if_notoverflow);
Bind(&if_notoverflow);
{
// There is a Smi representation for negated {x}.
Node* result = Projection(0, pair);
Return(BitcastWordToTagged(result));
}
Bind(&if_overflow);
{ Return(NumberConstant(0.0 - Smi::kMinValue)); }
}
}
Bind(&if_xisnotsmi);
{
// Check if {x} is a HeapNumber.
Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
Branch(IsHeapNumberMap(LoadMap(x)), &if_xisheapnumber,
&if_xisnotheapnumber);
Bind(&if_xisheapnumber);
{
Node* x_value = LoadHeapNumberValue(x);
Node* value = Float64Abs(x_value);
Node* result = AllocateHeapNumberWithValue(value);
Return(result);
}
Bind(&if_xisnotheapnumber);
{
// Need to convert {x} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_x.Bind(CallStub(callable, context, x));
Goto(&loop);
}
}
}
}
void MathBuiltinsAssembler::MathRoundingOperation(
Node* (CodeStubAssembler::*float64op)(Node*)) {
Node* context = Parameter(4);
// We might need to loop once for ToNumber conversion.
Variable var_x(this, MachineRepresentation::kTagged);
Label loop(this, &var_x);
var_x.Bind(Parameter(1));
Goto(&loop);
Bind(&loop);
{
// Load the current {x} value.
Node* x = var_x.value();
// Check if {x} is a Smi or a HeapObject.
Label if_xissmi(this), if_xisnotsmi(this);
Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
Bind(&if_xissmi);
{
// Nothing to do when {x} is a Smi.
Return(x);
}
Bind(&if_xisnotsmi);
{
// Check if {x} is a HeapNumber.
Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
Branch(IsHeapNumberMap(LoadMap(x)), &if_xisheapnumber,
&if_xisnotheapnumber);
Bind(&if_xisheapnumber);
{
Node* x_value = LoadHeapNumberValue(x);
Node* value = (this->*float64op)(x_value);
Node* result = ChangeFloat64ToTagged(value);
Return(result);
}
Bind(&if_xisnotheapnumber);
{
// Need to convert {x} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_x.Bind(CallStub(callable, context, x));
Goto(&loop);
}
}
}
}
void MathBuiltinsAssembler::MathUnaryOperation(
Node* (CodeStubAssembler::*float64op)(Node*)) {
Node* x = Parameter(1);
Node* context = Parameter(4);
Node* x_value = TruncateTaggedToFloat64(context, x);
Node* value = (this->*float64op)(x_value);
Node* result = AllocateHeapNumberWithValue(value);
Return(result);
}
void MathBuiltinsAssembler::MathMaxMin(
Node* (CodeStubAssembler::*float64op)(Node*, Node*), double default_val) {
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
CodeStubArguments arguments(this, ChangeInt32ToIntPtr(argc));
argc = arguments.GetLength();
Variable result(this, MachineRepresentation::kFloat64);
result.Bind(Float64Constant(default_val));
CodeStubAssembler::VariableList vars({&result}, zone());
arguments.ForEach(vars, [this, float64op, context, &result](Node* arg) {
Node* float_value = TruncateTaggedToFloat64(context, arg);
result.Bind((this->*float64op)(result.value(), float_value));
});
arguments.PopAndReturn(ChangeFloat64ToTagged(result.value()));
}
// ES6 section 20.2.2.2 Math.acos ( x )
TF_BUILTIN(MathAcos, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Acos);
}
// ES6 section 20.2.2.3 Math.acosh ( x )
TF_BUILTIN(MathAcosh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Acosh);
}
// ES6 section 20.2.2.4 Math.asin ( x )
TF_BUILTIN(MathAsin, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Asin);
}
// ES6 section 20.2.2.5 Math.asinh ( x )
TF_BUILTIN(MathAsinh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Asinh);
}
// ES6 section 20.2.2.6 Math.atan ( x )
TF_BUILTIN(MathAtan, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Atan);
}
// ES6 section 20.2.2.7 Math.atanh ( x )
TF_BUILTIN(MathAtanh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Atanh);
}
// ES6 section 20.2.2.8 Math.atan2 ( y, x )
TF_BUILTIN(MathAtan2, CodeStubAssembler) {
Node* y = Parameter(1);
Node* x = Parameter(2);
Node* context = Parameter(5);
Node* y_value = TruncateTaggedToFloat64(context, y);
Node* x_value = TruncateTaggedToFloat64(context, x);
Node* value = Float64Atan2(y_value, x_value);
Node* result = AllocateHeapNumberWithValue(value);
Return(result);
}
// ES6 section 20.2.2.10 Math.ceil ( x )
TF_BUILTIN(MathCeil, MathBuiltinsAssembler) {
MathRoundingOperation(&CodeStubAssembler::Float64Ceil);
}
// ES6 section 20.2.2.9 Math.cbrt ( x )
TF_BUILTIN(MathCbrt, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Cbrt);
}
// ES6 section 20.2.2.11 Math.clz32 ( x )
TF_BUILTIN(MathClz32, CodeStubAssembler) {
Node* context = Parameter(4);
// Shared entry point for the clz32 operation.
Variable var_clz32_x(this, MachineRepresentation::kWord32);
Label do_clz32(this);
// We might need to loop once for ToNumber conversion.
Variable var_x(this, MachineRepresentation::kTagged);
Label loop(this, &var_x);
var_x.Bind(Parameter(1));
Goto(&loop);
Bind(&loop);
{
// Load the current {x} value.
Node* x = var_x.value();
// Check if {x} is a Smi or a HeapObject.
Label if_xissmi(this), if_xisnotsmi(this);
Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
Bind(&if_xissmi);
{
var_clz32_x.Bind(SmiToWord32(x));
Goto(&do_clz32);
}
Bind(&if_xisnotsmi);
{
// Check if {x} is a HeapNumber.
Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
Branch(IsHeapNumberMap(LoadMap(x)), &if_xisheapnumber,
&if_xisnotheapnumber);
Bind(&if_xisheapnumber);
{
var_clz32_x.Bind(TruncateHeapNumberValueToWord32(x));
Goto(&do_clz32);
}
Bind(&if_xisnotheapnumber);
{
// Need to convert {x} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_x.Bind(CallStub(callable, context, x));
Goto(&loop);
}
}
}
Bind(&do_clz32);
{
Node* x_value = var_clz32_x.value();
Node* value = Word32Clz(x_value);
Node* result = ChangeInt32ToTagged(value);
Return(result);
}
}
// ES6 section 20.2.2.12 Math.cos ( x )
TF_BUILTIN(MathCos, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Cos);
}
// ES6 section 20.2.2.13 Math.cosh ( x )
TF_BUILTIN(MathCosh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Cosh);
}
// ES6 section 20.2.2.14 Math.exp ( x )
TF_BUILTIN(MathExp, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Exp);
}
// ES6 section 20.2.2.15 Math.expm1 ( x )
TF_BUILTIN(MathExpm1, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Expm1);
}
// ES6 section 20.2.2.16 Math.floor ( x )
TF_BUILTIN(MathFloor, MathBuiltinsAssembler) {
MathRoundingOperation(&CodeStubAssembler::Float64Floor);
}
// ES6 section 20.2.2.17 Math.fround ( x )
TF_BUILTIN(MathFround, CodeStubAssembler) {
Node* x = Parameter(1);
Node* context = Parameter(4);
Node* x_value = TruncateTaggedToFloat64(context, x);
Node* value32 = TruncateFloat64ToFloat32(x_value);
Node* value = ChangeFloat32ToFloat64(value32);
Node* result = AllocateHeapNumberWithValue(value);
Return(result);
}
// ES6 section 20.2.2.19 Math.imul ( x, y )
TF_BUILTIN(MathImul, CodeStubAssembler) {
Node* x = Parameter(1);
Node* y = Parameter(2);
Node* context = Parameter(5);
Node* x_value = TruncateTaggedToWord32(context, x);
Node* y_value = TruncateTaggedToWord32(context, y);
Node* value = Int32Mul(x_value, y_value);
Node* result = ChangeInt32ToTagged(value);
Return(result);
}
// ES6 section 20.2.2.20 Math.log ( x )
TF_BUILTIN(MathLog, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Log);
}
// ES6 section 20.2.2.21 Math.log1p ( x )
TF_BUILTIN(MathLog1p, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Log1p);
}
// ES6 section 20.2.2.22 Math.log10 ( x )
TF_BUILTIN(MathLog10, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Log10);
}
// ES6 section 20.2.2.23 Math.log2 ( x )
TF_BUILTIN(MathLog2, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Log2);
}
// ES6 section 20.2.2.26 Math.pow ( x, y )
TF_BUILTIN(MathPow, CodeStubAssembler) {
Node* x = Parameter(1);
Node* y = Parameter(2);
Node* context = Parameter(5);
Node* x_value = TruncateTaggedToFloat64(context, x);
Node* y_value = TruncateTaggedToFloat64(context, y);
Node* value = Float64Pow(x_value, y_value);
Node* result = ChangeFloat64ToTagged(value);
Return(result);
}
// ES6 section 20.2.2.27 Math.random ( )
TF_BUILTIN(MathRandom, CodeStubAssembler) {
Node* context = Parameter(3);
Node* native_context = LoadNativeContext(context);
// Load cache index.
Variable smi_index(this, MachineRepresentation::kTagged);
smi_index.Bind(
LoadContextElement(native_context, Context::MATH_RANDOM_INDEX_INDEX));
// Cached random numbers are exhausted if index is 0. Go to slow path.
Label if_cached(this);
GotoIf(SmiAbove(smi_index.value(), SmiConstant(Smi::kZero)), &if_cached);
// Cache exhausted, populate the cache. Return value is the new index.
smi_index.Bind(CallRuntime(Runtime::kGenerateRandomNumbers, context));
Goto(&if_cached);
// Compute next index by decrement.
Bind(&if_cached);
Node* new_smi_index = SmiSub(smi_index.value(), SmiConstant(Smi::FromInt(1)));
StoreContextElement(native_context, Context::MATH_RANDOM_INDEX_INDEX,
new_smi_index);
// Load and return next cached random number.
Node* array =
LoadContextElement(native_context, Context::MATH_RANDOM_CACHE_INDEX);
Node* random = LoadFixedDoubleArrayElement(
array, new_smi_index, MachineType::Float64(), 0, SMI_PARAMETERS);
Return(AllocateHeapNumberWithValue(random));
}
// ES6 section 20.2.2.28 Math.round ( x )
TF_BUILTIN(MathRound, MathBuiltinsAssembler) {
MathRoundingOperation(&CodeStubAssembler::Float64Round);
}
// ES6 section 20.2.2.29 Math.sign ( x )
TF_BUILTIN(MathSign, CodeStubAssembler) {
// Convert the {x} value to a Number.
Node* x = Parameter(1);
Node* context = Parameter(4);
Node* x_value = TruncateTaggedToFloat64(context, x);
// Return -1 if {x} is negative, 1 if {x} is positive, or {x} itself.
Label if_xisnegative(this), if_xispositive(this);
GotoIf(Float64LessThan(x_value, Float64Constant(0.0)), &if_xisnegative);
GotoIf(Float64LessThan(Float64Constant(0.0), x_value), &if_xispositive);
Return(ChangeFloat64ToTagged(x_value));
Bind(&if_xisnegative);
Return(SmiConstant(Smi::FromInt(-1)));
Bind(&if_xispositive);
Return(SmiConstant(Smi::FromInt(1)));
}
// ES6 section 20.2.2.30 Math.sin ( x )
TF_BUILTIN(MathSin, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Sin);
}
// ES6 section 20.2.2.31 Math.sinh ( x )
TF_BUILTIN(MathSinh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Sinh);
}
// ES6 section 20.2.2.32 Math.sqrt ( x )
TF_BUILTIN(MathSqrt, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Sqrt);
}
// ES6 section 20.2.2.33 Math.tan ( x )
TF_BUILTIN(MathTan, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Tan);
}
// ES6 section 20.2.2.34 Math.tanh ( x )
TF_BUILTIN(MathTanh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Tanh);
}
// ES6 section 20.2.2.35 Math.trunc ( x )
TF_BUILTIN(MathTrunc, MathBuiltinsAssembler) {
MathRoundingOperation(&CodeStubAssembler::Float64Trunc);
}
// ES6 section 20.2.2.24 Math.max ( value1, value2 , ...values )
TF_BUILTIN(MathMax, MathBuiltinsAssembler) {
MathMaxMin(&CodeStubAssembler::Float64Max, -1.0 * V8_INFINITY);
}
// ES6 section 20.2.2.25 Math.min ( value1, value2 , ...values )
TF_BUILTIN(MathMin, MathBuiltinsAssembler) {
MathMaxMin(&CodeStubAssembler::Float64Min, V8_INFINITY);
}
} // namespace internal
} // namespace v8

View File

@ -4,8 +4,6 @@
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
#include "src/counters.h"
#include "src/objects-inl.h"
@ -15,324 +13,6 @@ namespace internal {
// -----------------------------------------------------------------------------
// ES6 section 20.2.2 Function Properties of the Math Object
class MathBuiltinsAssembler : public CodeStubAssembler {
public:
explicit MathBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void MathRoundingOperation(Node* (CodeStubAssembler::*float64op)(Node*));
void MathUnaryOperation(Node* (CodeStubAssembler::*float64op)(Node*));
void MathMaxMin(Node* (CodeStubAssembler::*float64op)(Node*, Node*),
double default_val);
};
// ES6 section - 20.2.2.1 Math.abs ( x )
TF_BUILTIN(MathAbs, CodeStubAssembler) {
Node* context = Parameter(4);
// We might need to loop once for ToNumber conversion.
Variable var_x(this, MachineRepresentation::kTagged);
Label loop(this, &var_x);
var_x.Bind(Parameter(1));
Goto(&loop);
Bind(&loop);
{
// Load the current {x} value.
Node* x = var_x.value();
// Check if {x} is a Smi or a HeapObject.
Label if_xissmi(this), if_xisnotsmi(this);
Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
Bind(&if_xissmi);
{
// Check if {x} is already positive.
Label if_xispositive(this), if_xisnotpositive(this);
BranchIfSmiLessThanOrEqual(SmiConstant(Smi::FromInt(0)), x,
&if_xispositive, &if_xisnotpositive);
Bind(&if_xispositive);
{
// Just return the input {x}.
Return(x);
}
Bind(&if_xisnotpositive);
{
// Try to negate the {x} value.
Node* pair =
IntPtrSubWithOverflow(IntPtrConstant(0), BitcastTaggedToWord(x));
Node* overflow = Projection(1, pair);
Label if_overflow(this, Label::kDeferred), if_notoverflow(this);
Branch(overflow, &if_overflow, &if_notoverflow);
Bind(&if_notoverflow);
{
// There is a Smi representation for negated {x}.
Node* result = Projection(0, pair);
Return(BitcastWordToTagged(result));
}
Bind(&if_overflow);
{ Return(NumberConstant(0.0 - Smi::kMinValue)); }
}
}
Bind(&if_xisnotsmi);
{
// Check if {x} is a HeapNumber.
Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
Branch(IsHeapNumberMap(LoadMap(x)), &if_xisheapnumber,
&if_xisnotheapnumber);
Bind(&if_xisheapnumber);
{
Node* x_value = LoadHeapNumberValue(x);
Node* value = Float64Abs(x_value);
Node* result = AllocateHeapNumberWithValue(value);
Return(result);
}
Bind(&if_xisnotheapnumber);
{
// Need to convert {x} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_x.Bind(CallStub(callable, context, x));
Goto(&loop);
}
}
}
}
void MathBuiltinsAssembler::MathRoundingOperation(
Node* (CodeStubAssembler::*float64op)(Node*)) {
Node* context = Parameter(4);
// We might need to loop once for ToNumber conversion.
Variable var_x(this, MachineRepresentation::kTagged);
Label loop(this, &var_x);
var_x.Bind(Parameter(1));
Goto(&loop);
Bind(&loop);
{
// Load the current {x} value.
Node* x = var_x.value();
// Check if {x} is a Smi or a HeapObject.
Label if_xissmi(this), if_xisnotsmi(this);
Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
Bind(&if_xissmi);
{
// Nothing to do when {x} is a Smi.
Return(x);
}
Bind(&if_xisnotsmi);
{
// Check if {x} is a HeapNumber.
Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
Branch(IsHeapNumberMap(LoadMap(x)), &if_xisheapnumber,
&if_xisnotheapnumber);
Bind(&if_xisheapnumber);
{
Node* x_value = LoadHeapNumberValue(x);
Node* value = (this->*float64op)(x_value);
Node* result = ChangeFloat64ToTagged(value);
Return(result);
}
Bind(&if_xisnotheapnumber);
{
// Need to convert {x} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_x.Bind(CallStub(callable, context, x));
Goto(&loop);
}
}
}
}
void MathBuiltinsAssembler::MathUnaryOperation(
Node* (CodeStubAssembler::*float64op)(Node*)) {
Node* x = Parameter(1);
Node* context = Parameter(4);
Node* x_value = TruncateTaggedToFloat64(context, x);
Node* value = (this->*float64op)(x_value);
Node* result = AllocateHeapNumberWithValue(value);
Return(result);
}
void MathBuiltinsAssembler::MathMaxMin(
Node* (CodeStubAssembler::*float64op)(Node*, Node*), double default_val) {
Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
Node* context = Parameter(BuiltinDescriptor::kContext);
CodeStubArguments arguments(this, ChangeInt32ToIntPtr(argc));
argc = arguments.GetLength();
Variable result(this, MachineRepresentation::kFloat64);
result.Bind(Float64Constant(default_val));
CodeStubAssembler::VariableList vars({&result}, zone());
arguments.ForEach(vars, [this, float64op, context, &result](Node* arg) {
Node* float_value = TruncateTaggedToFloat64(context, arg);
result.Bind((this->*float64op)(result.value(), float_value));
});
arguments.PopAndReturn(ChangeFloat64ToTagged(result.value()));
}
// ES6 section 20.2.2.2 Math.acos ( x )
TF_BUILTIN(MathAcos, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Acos);
}
// ES6 section 20.2.2.3 Math.acosh ( x )
TF_BUILTIN(MathAcosh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Acosh);
}
// ES6 section 20.2.2.4 Math.asin ( x )
TF_BUILTIN(MathAsin, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Asin);
}
// ES6 section 20.2.2.5 Math.asinh ( x )
TF_BUILTIN(MathAsinh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Asinh);
}
// ES6 section 20.2.2.6 Math.atan ( x )
TF_BUILTIN(MathAtan, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Atan);
}
// ES6 section 20.2.2.7 Math.atanh ( x )
TF_BUILTIN(MathAtanh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Atanh);
}
// ES6 section 20.2.2.8 Math.atan2 ( y, x )
TF_BUILTIN(MathAtan2, CodeStubAssembler) {
Node* y = Parameter(1);
Node* x = Parameter(2);
Node* context = Parameter(5);
Node* y_value = TruncateTaggedToFloat64(context, y);
Node* x_value = TruncateTaggedToFloat64(context, x);
Node* value = Float64Atan2(y_value, x_value);
Node* result = AllocateHeapNumberWithValue(value);
Return(result);
}
// ES6 section 20.2.2.10 Math.ceil ( x )
TF_BUILTIN(MathCeil, MathBuiltinsAssembler) {
MathRoundingOperation(&CodeStubAssembler::Float64Ceil);
}
// ES6 section 20.2.2.9 Math.cbrt ( x )
TF_BUILTIN(MathCbrt, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Cbrt);
}
// ES6 section 20.2.2.11 Math.clz32 ( x )
TF_BUILTIN(MathClz32, CodeStubAssembler) {
Node* context = Parameter(4);
// Shared entry point for the clz32 operation.
Variable var_clz32_x(this, MachineRepresentation::kWord32);
Label do_clz32(this);
// We might need to loop once for ToNumber conversion.
Variable var_x(this, MachineRepresentation::kTagged);
Label loop(this, &var_x);
var_x.Bind(Parameter(1));
Goto(&loop);
Bind(&loop);
{
// Load the current {x} value.
Node* x = var_x.value();
// Check if {x} is a Smi or a HeapObject.
Label if_xissmi(this), if_xisnotsmi(this);
Branch(TaggedIsSmi(x), &if_xissmi, &if_xisnotsmi);
Bind(&if_xissmi);
{
var_clz32_x.Bind(SmiToWord32(x));
Goto(&do_clz32);
}
Bind(&if_xisnotsmi);
{
// Check if {x} is a HeapNumber.
Label if_xisheapnumber(this), if_xisnotheapnumber(this, Label::kDeferred);
Branch(IsHeapNumberMap(LoadMap(x)), &if_xisheapnumber,
&if_xisnotheapnumber);
Bind(&if_xisheapnumber);
{
var_clz32_x.Bind(TruncateHeapNumberValueToWord32(x));
Goto(&do_clz32);
}
Bind(&if_xisnotheapnumber);
{
// Need to convert {x} to a Number first.
Callable callable = CodeFactory::NonNumberToNumber(isolate());
var_x.Bind(CallStub(callable, context, x));
Goto(&loop);
}
}
}
Bind(&do_clz32);
{
Node* x_value = var_clz32_x.value();
Node* value = Word32Clz(x_value);
Node* result = ChangeInt32ToTagged(value);
Return(result);
}
}
// ES6 section 20.2.2.12 Math.cos ( x )
TF_BUILTIN(MathCos, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Cos);
}
// ES6 section 20.2.2.13 Math.cosh ( x )
TF_BUILTIN(MathCosh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Cosh);
}
// ES6 section 20.2.2.14 Math.exp ( x )
TF_BUILTIN(MathExp, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Exp);
}
// ES6 section 20.2.2.15 Math.expm1 ( x )
TF_BUILTIN(MathExpm1, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Expm1);
}
// ES6 section 20.2.2.16 Math.floor ( x )
TF_BUILTIN(MathFloor, MathBuiltinsAssembler) {
MathRoundingOperation(&CodeStubAssembler::Float64Floor);
}
// ES6 section 20.2.2.17 Math.fround ( x )
TF_BUILTIN(MathFround, CodeStubAssembler) {
Node* x = Parameter(1);
Node* context = Parameter(4);
Node* x_value = TruncateTaggedToFloat64(context, x);
Node* value32 = TruncateFloat64ToFloat32(x_value);
Node* value = ChangeFloat32ToFloat64(value32);
Node* result = AllocateHeapNumberWithValue(value);
Return(result);
}
// ES6 section 20.2.2.18 Math.hypot ( value1, value2, ...values )
BUILTIN(MathHypot) {
HandleScope scope(isolate);
@ -385,146 +65,5 @@ BUILTIN(MathHypot) {
return *isolate->factory()->NewNumber(std::sqrt(sum) * max);
}
// ES6 section 20.2.2.19 Math.imul ( x, y )
TF_BUILTIN(MathImul, CodeStubAssembler) {
Node* x = Parameter(1);
Node* y = Parameter(2);
Node* context = Parameter(5);
Node* x_value = TruncateTaggedToWord32(context, x);
Node* y_value = TruncateTaggedToWord32(context, y);
Node* value = Int32Mul(x_value, y_value);
Node* result = ChangeInt32ToTagged(value);
Return(result);
}
// ES6 section 20.2.2.20 Math.log ( x )
TF_BUILTIN(MathLog, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Log);
}
// ES6 section 20.2.2.21 Math.log1p ( x )
TF_BUILTIN(MathLog1p, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Log1p);
}
// ES6 section 20.2.2.22 Math.log10 ( x )
TF_BUILTIN(MathLog10, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Log10);
}
// ES6 section 20.2.2.23 Math.log2 ( x )
TF_BUILTIN(MathLog2, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Log2);
}
// ES6 section 20.2.2.26 Math.pow ( x, y )
TF_BUILTIN(MathPow, CodeStubAssembler) {
Node* x = Parameter(1);
Node* y = Parameter(2);
Node* context = Parameter(5);
Node* x_value = TruncateTaggedToFloat64(context, x);
Node* y_value = TruncateTaggedToFloat64(context, y);
Node* value = Float64Pow(x_value, y_value);
Node* result = ChangeFloat64ToTagged(value);
Return(result);
}
// ES6 section 20.2.2.27 Math.random ( )
TF_BUILTIN(MathRandom, CodeStubAssembler) {
Node* context = Parameter(3);
Node* native_context = LoadNativeContext(context);
// Load cache index.
Variable smi_index(this, MachineRepresentation::kTagged);
smi_index.Bind(
LoadContextElement(native_context, Context::MATH_RANDOM_INDEX_INDEX));
// Cached random numbers are exhausted if index is 0. Go to slow path.
Label if_cached(this);
GotoIf(SmiAbove(smi_index.value(), SmiConstant(Smi::kZero)), &if_cached);
// Cache exhausted, populate the cache. Return value is the new index.
smi_index.Bind(CallRuntime(Runtime::kGenerateRandomNumbers, context));
Goto(&if_cached);
// Compute next index by decrement.
Bind(&if_cached);
Node* new_smi_index = SmiSub(smi_index.value(), SmiConstant(Smi::FromInt(1)));
StoreContextElement(native_context, Context::MATH_RANDOM_INDEX_INDEX,
new_smi_index);
// Load and return next cached random number.
Node* array =
LoadContextElement(native_context, Context::MATH_RANDOM_CACHE_INDEX);
Node* random = LoadFixedDoubleArrayElement(
array, new_smi_index, MachineType::Float64(), 0, SMI_PARAMETERS);
Return(AllocateHeapNumberWithValue(random));
}
// ES6 section 20.2.2.28 Math.round ( x )
TF_BUILTIN(MathRound, MathBuiltinsAssembler) {
MathRoundingOperation(&CodeStubAssembler::Float64Round);
}
// ES6 section 20.2.2.29 Math.sign ( x )
TF_BUILTIN(MathSign, CodeStubAssembler) {
// Convert the {x} value to a Number.
Node* x = Parameter(1);
Node* context = Parameter(4);
Node* x_value = TruncateTaggedToFloat64(context, x);
// Return -1 if {x} is negative, 1 if {x} is positive, or {x} itself.
Label if_xisnegative(this), if_xispositive(this);
GotoIf(Float64LessThan(x_value, Float64Constant(0.0)), &if_xisnegative);
GotoIf(Float64LessThan(Float64Constant(0.0), x_value), &if_xispositive);
Return(ChangeFloat64ToTagged(x_value));
Bind(&if_xisnegative);
Return(SmiConstant(Smi::FromInt(-1)));
Bind(&if_xispositive);
Return(SmiConstant(Smi::FromInt(1)));
}
// ES6 section 20.2.2.30 Math.sin ( x )
TF_BUILTIN(MathSin, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Sin);
}
// ES6 section 20.2.2.31 Math.sinh ( x )
TF_BUILTIN(MathSinh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Sinh);
}
// ES6 section 20.2.2.32 Math.sqrt ( x )
TF_BUILTIN(MathSqrt, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Sqrt);
}
// ES6 section 20.2.2.33 Math.tan ( x )
TF_BUILTIN(MathTan, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Tan);
}
// ES6 section 20.2.2.34 Math.tanh ( x )
TF_BUILTIN(MathTanh, MathBuiltinsAssembler) {
MathUnaryOperation(&CodeStubAssembler::Float64Tanh);
}
// ES6 section 20.2.2.35 Math.trunc ( x )
TF_BUILTIN(MathTrunc, MathBuiltinsAssembler) {
MathRoundingOperation(&CodeStubAssembler::Float64Trunc);
}
// ES6 section 20.2.2.24 Math.max ( value1, value2 , ...values )
TF_BUILTIN(MathMax, MathBuiltinsAssembler) {
MathMaxMin(&CodeStubAssembler::Float64Max, -1.0 * V8_INFINITY);
}
// ES6 section 20.2.2.25 Math.min ( value1, value2 , ...values )
TF_BUILTIN(MathMin, MathBuiltinsAssembler) {
MathMaxMin(&CodeStubAssembler::Float64Min, V8_INFINITY);
}
} // namespace internal
} // namespace v8

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,413 @@
// Copyright 2017 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-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
// ES6 section 19.1 Object Objects
typedef compiler::Node Node;
class ObjectBuiltinsAssembler : public CodeStubAssembler {
public:
explicit ObjectBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void IsString(Node* object, Label* if_string, Label* if_notstring);
void ReturnToStringFormat(Node* context, Node* string);
};
void ObjectBuiltinsAssembler::IsString(Node* object, Label* if_string,
Label* if_notstring) {
Label if_notsmi(this);
Branch(TaggedIsSmi(object), if_notstring, &if_notsmi);
Bind(&if_notsmi);
{
Node* instance_type = LoadInstanceType(object);
Branch(IsStringInstanceType(instance_type), if_string, if_notstring);
}
}
void ObjectBuiltinsAssembler::ReturnToStringFormat(Node* context,
Node* string) {
Node* lhs = HeapConstant(factory()->NewStringFromStaticChars("[object "));
Node* rhs = HeapConstant(factory()->NewStringFromStaticChars("]"));
Callable callable =
CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
Return(CallStub(callable, context, CallStub(callable, context, lhs, string),
rhs));
}
TF_BUILTIN(ObjectHasOwnProperty, ObjectBuiltinsAssembler) {
Node* object = Parameter(0);
Node* key = Parameter(1);
Node* context = Parameter(4);
Label call_runtime(this), return_true(this), return_false(this);
// Smi receivers do not have own properties.
Label if_objectisnotsmi(this);
Branch(TaggedIsSmi(object), &return_false, &if_objectisnotsmi);
Bind(&if_objectisnotsmi);
Node* map = LoadMap(object);
Node* instance_type = LoadMapInstanceType(map);
{
Variable var_index(this, MachineType::PointerRepresentation());
Variable var_unique(this, MachineRepresentation::kTagged);
Label keyisindex(this), if_iskeyunique(this);
TryToName(key, &keyisindex, &var_index, &if_iskeyunique, &var_unique,
&call_runtime);
Bind(&if_iskeyunique);
TryHasOwnProperty(object, map, instance_type, var_unique.value(),
&return_true, &return_false, &call_runtime);
Bind(&keyisindex);
// Handle negative keys in the runtime.
GotoIf(IntPtrLessThan(var_index.value(), IntPtrConstant(0)), &call_runtime);
TryLookupElement(object, map, instance_type, var_index.value(),
&return_true, &return_false, &call_runtime);
}
Bind(&return_true);
Return(BooleanConstant(true));
Bind(&return_false);
Return(BooleanConstant(false));
Bind(&call_runtime);
Return(CallRuntime(Runtime::kObjectHasOwnProperty, context, object, key));
}
// ES6 section 19.1.3.6 Object.prototype.toString
TF_BUILTIN(ObjectProtoToString, ObjectBuiltinsAssembler) {
Label return_undefined(this, Label::kDeferred),
return_null(this, Label::kDeferred),
return_arguments(this, Label::kDeferred), return_array(this),
return_api(this, Label::kDeferred), return_object(this),
return_regexp(this), return_function(this), return_error(this),
return_date(this), return_jsvalue(this),
return_jsproxy(this, Label::kDeferred);
Label if_isproxy(this, Label::kDeferred);
Label checkstringtag(this);
Label if_tostringtag(this), if_notostringtag(this);
Node* receiver = Parameter(0);
Node* context = Parameter(3);
GotoIf(WordEqual(receiver, UndefinedConstant()), &return_undefined);
GotoIf(WordEqual(receiver, NullConstant()), &return_null);
Callable to_object = CodeFactory::ToObject(isolate());
receiver = CallStub(to_object, context, receiver);
Node* receiver_instance_type = LoadInstanceType(receiver);
// for proxies, check IsArray before getting @@toStringTag
Variable var_proxy_is_array(this, MachineRepresentation::kTagged);
var_proxy_is_array.Bind(BooleanConstant(false));
Branch(Word32Equal(receiver_instance_type, Int32Constant(JS_PROXY_TYPE)),
&if_isproxy, &checkstringtag);
Bind(&if_isproxy);
{
// This can throw
var_proxy_is_array.Bind(
CallRuntime(Runtime::kArrayIsArray, context, receiver));
Goto(&checkstringtag);
}
Bind(&checkstringtag);
{
Node* to_string_tag_symbol =
HeapConstant(isolate()->factory()->to_string_tag_symbol());
GetPropertyStub stub(isolate());
Callable get_property =
Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
Node* to_string_tag_value =
CallStub(get_property, context, receiver, to_string_tag_symbol);
IsString(to_string_tag_value, &if_tostringtag, &if_notostringtag);
Bind(&if_tostringtag);
ReturnToStringFormat(context, to_string_tag_value);
}
Bind(&if_notostringtag);
{
size_t const kNumCases = 11;
Label* case_labels[kNumCases];
int32_t case_values[kNumCases];
case_labels[0] = &return_api;
case_values[0] = JS_API_OBJECT_TYPE;
case_labels[1] = &return_api;
case_values[1] = JS_SPECIAL_API_OBJECT_TYPE;
case_labels[2] = &return_arguments;
case_values[2] = JS_ARGUMENTS_TYPE;
case_labels[3] = &return_array;
case_values[3] = JS_ARRAY_TYPE;
case_labels[4] = &return_function;
case_values[4] = JS_BOUND_FUNCTION_TYPE;
case_labels[5] = &return_function;
case_values[5] = JS_FUNCTION_TYPE;
case_labels[6] = &return_error;
case_values[6] = JS_ERROR_TYPE;
case_labels[7] = &return_date;
case_values[7] = JS_DATE_TYPE;
case_labels[8] = &return_regexp;
case_values[8] = JS_REGEXP_TYPE;
case_labels[9] = &return_jsvalue;
case_values[9] = JS_VALUE_TYPE;
case_labels[10] = &return_jsproxy;
case_values[10] = JS_PROXY_TYPE;
Switch(receiver_instance_type, &return_object, case_values, case_labels,
arraysize(case_values));
Bind(&return_undefined);
Return(HeapConstant(isolate()->factory()->undefined_to_string()));
Bind(&return_null);
Return(HeapConstant(isolate()->factory()->null_to_string()));
Bind(&return_arguments);
Return(HeapConstant(isolate()->factory()->arguments_to_string()));
Bind(&return_array);
Return(HeapConstant(isolate()->factory()->array_to_string()));
Bind(&return_function);
Return(HeapConstant(isolate()->factory()->function_to_string()));
Bind(&return_error);
Return(HeapConstant(isolate()->factory()->error_to_string()));
Bind(&return_date);
Return(HeapConstant(isolate()->factory()->date_to_string()));
Bind(&return_regexp);
Return(HeapConstant(isolate()->factory()->regexp_to_string()));
Bind(&return_api);
{
Node* class_name = CallRuntime(Runtime::kClassOf, context, receiver);
ReturnToStringFormat(context, class_name);
}
Bind(&return_jsvalue);
{
Label return_boolean(this), return_number(this), return_string(this);
Node* value = LoadJSValueValue(receiver);
GotoIf(TaggedIsSmi(value), &return_number);
Node* instance_type = LoadInstanceType(value);
GotoIf(IsStringInstanceType(instance_type), &return_string);
GotoIf(Word32Equal(instance_type, Int32Constant(HEAP_NUMBER_TYPE)),
&return_number);
GotoIf(Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE)),
&return_boolean);
CSA_ASSERT(this, Word32Equal(instance_type, Int32Constant(SYMBOL_TYPE)));
Goto(&return_object);
Bind(&return_string);
Return(HeapConstant(isolate()->factory()->string_to_string()));
Bind(&return_number);
Return(HeapConstant(isolate()->factory()->number_to_string()));
Bind(&return_boolean);
Return(HeapConstant(isolate()->factory()->boolean_to_string()));
}
Bind(&return_jsproxy);
{
GotoIf(WordEqual(var_proxy_is_array.value(), BooleanConstant(true)),
&return_array);
Node* map = LoadMap(receiver);
// Return object if the proxy {receiver} is not callable.
Branch(IsCallableMap(map), &return_function, &return_object);
}
// Default
Bind(&return_object);
Return(HeapConstant(isolate()->factory()->object_to_string()));
}
}
// ES6 19.3.7 Object.prototype.valueOf
TF_BUILTIN(ObjectPrototypeValueOf, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Callable to_object = CodeFactory::ToObject(isolate());
receiver = CallStub(to_object, context, receiver);
Return(receiver);
}
TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
Node* prototype = Parameter(1);
Node* properties = Parameter(2);
Node* context = Parameter(3 + 2);
Label call_runtime(this, Label::kDeferred), prototype_valid(this),
no_properties(this);
{
Comment("Argument 1 check: prototype");
GotoIf(WordEqual(prototype, NullConstant()), &prototype_valid);
BranchIfJSReceiver(prototype, &prototype_valid, &call_runtime);
}
Bind(&prototype_valid);
{
Comment("Argument 2 check: properties");
// Check that we have a simple object
GotoIf(TaggedIsSmi(properties), &call_runtime);
// Undefined implies no properties.
GotoIf(WordEqual(properties, UndefinedConstant()), &no_properties);
Node* properties_map = LoadMap(properties);
GotoIf(IsSpecialReceiverMap(properties_map), &call_runtime);
// Stay on the fast path only if there are no elements.
GotoIfNot(WordEqual(LoadElements(properties),
LoadRoot(Heap::kEmptyFixedArrayRootIndex)),
&call_runtime);
// Handle dictionary objects or fast objects with properties in runtime.
Node* bit_field3 = LoadMapBitField3(properties_map);
GotoIf(IsSetWord32<Map::DictionaryMap>(bit_field3), &call_runtime);
Branch(IsSetWord32<Map::NumberOfOwnDescriptorsBits>(bit_field3),
&call_runtime, &no_properties);
}
// Create a new object with the given prototype.
Bind(&no_properties);
{
Variable map(this, MachineRepresentation::kTagged);
Variable properties(this, MachineRepresentation::kTagged);
Label non_null_proto(this), instantiate_map(this), good(this);
Branch(WordEqual(prototype, NullConstant()), &good, &non_null_proto);
Bind(&good);
{
map.Bind(LoadContextElement(
context, Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP));
properties.Bind(AllocateNameDictionary(NameDictionary::kInitialCapacity));
Goto(&instantiate_map);
}
Bind(&non_null_proto);
{
properties.Bind(EmptyFixedArrayConstant());
Node* object_function =
LoadContextElement(context, Context::OBJECT_FUNCTION_INDEX);
Node* object_function_map = LoadObjectField(
object_function, JSFunction::kPrototypeOrInitialMapOffset);
map.Bind(object_function_map);
GotoIf(WordEqual(prototype, LoadMapPrototype(map.value())),
&instantiate_map);
// Try loading the prototype info.
Node* prototype_info =
LoadMapPrototypeInfo(LoadMap(prototype), &call_runtime);
Comment("Load ObjectCreateMap from PrototypeInfo");
Node* weak_cell =
LoadObjectField(prototype_info, PrototypeInfo::kObjectCreateMap);
GotoIf(WordEqual(weak_cell, UndefinedConstant()), &call_runtime);
map.Bind(LoadWeakCellValue(weak_cell, &call_runtime));
Goto(&instantiate_map);
}
Bind(&instantiate_map);
{
Node* instance = AllocateJSObjectFromMap(map.value(), properties.value());
Return(instance);
}
}
Bind(&call_runtime);
{
Return(CallRuntime(Runtime::kObjectCreate, context, prototype, properties));
}
}
TF_BUILTIN(CreateIterResultObject, ObjectBuiltinsAssembler) {
typedef CreateIterResultObjectDescriptor Descriptor;
Node* const value = Parameter(Descriptor::kValue);
Node* const done = Parameter(Descriptor::kDone);
Node* const context = Parameter(Descriptor::kContext);
Node* const native_context = LoadNativeContext(context);
Node* const map =
LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
Node* const result = AllocateJSObjectFromMap(map);
StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, value);
StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, done);
Return(result);
}
TF_BUILTIN(HasProperty, ObjectBuiltinsAssembler) {
typedef HasPropertyDescriptor Descriptor;
Node* key = Parameter(Descriptor::kKey);
Node* object = Parameter(Descriptor::kObject);
Node* context = Parameter(Descriptor::kContext);
Return(HasProperty(object, key, context, Runtime::kHasProperty));
}
TF_BUILTIN(InstanceOf, ObjectBuiltinsAssembler) {
typedef CompareDescriptor Descriptor;
Node* object = Parameter(Descriptor::kLeft);
Node* callable = Parameter(Descriptor::kRight);
Node* context = Parameter(Descriptor::kContext);
Return(InstanceOf(object, callable, context));
}
// ES6 section 7.3.19 OrdinaryHasInstance ( C, O )
TF_BUILTIN(OrdinaryHasInstance, ObjectBuiltinsAssembler) {
typedef CompareDescriptor Descriptor;
Node* constructor = Parameter(Descriptor::kLeft);
Node* object = Parameter(Descriptor::kRight);
Node* context = Parameter(Descriptor::kContext);
Return(OrdinaryHasInstance(context, constructor, object));
}
TF_BUILTIN(GetSuperConstructor, ObjectBuiltinsAssembler) {
typedef TypeofDescriptor Descriptor;
Node* object = Parameter(Descriptor::kObject);
Node* context = Parameter(Descriptor::kContext);
Return(GetSuperConstructor(object, context));
}
} // namespace internal
} // namespace v8

View File

@ -15,89 +15,9 @@
namespace v8 {
namespace internal {
typedef compiler::Node Node;
class ObjectBuiltinsAssembler : public CodeStubAssembler {
public:
explicit ObjectBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void IsString(Node* object, Label* if_string, Label* if_notstring);
void ReturnToStringFormat(Node* context, Node* string);
};
void ObjectBuiltinsAssembler::IsString(Node* object, Label* if_string,
Label* if_notstring) {
Label if_notsmi(this);
Branch(TaggedIsSmi(object), if_notstring, &if_notsmi);
Bind(&if_notsmi);
{
Node* instance_type = LoadInstanceType(object);
Branch(IsStringInstanceType(instance_type), if_string, if_notstring);
}
}
void ObjectBuiltinsAssembler::ReturnToStringFormat(Node* context,
Node* string) {
Node* lhs = HeapConstant(factory()->NewStringFromStaticChars("[object "));
Node* rhs = HeapConstant(factory()->NewStringFromStaticChars("]"));
Callable callable =
CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
Return(CallStub(callable, context, CallStub(callable, context, lhs, string),
rhs));
}
// -----------------------------------------------------------------------------
// ES6 section 19.1 Object Objects
TF_BUILTIN(ObjectHasOwnProperty, ObjectBuiltinsAssembler) {
Node* object = Parameter(0);
Node* key = Parameter(1);
Node* context = Parameter(4);
Label call_runtime(this), return_true(this), return_false(this);
// Smi receivers do not have own properties.
Label if_objectisnotsmi(this);
Branch(TaggedIsSmi(object), &return_false, &if_objectisnotsmi);
Bind(&if_objectisnotsmi);
Node* map = LoadMap(object);
Node* instance_type = LoadMapInstanceType(map);
{
Variable var_index(this, MachineType::PointerRepresentation());
Variable var_unique(this, MachineRepresentation::kTagged);
Label keyisindex(this), if_iskeyunique(this);
TryToName(key, &keyisindex, &var_index, &if_iskeyunique, &var_unique,
&call_runtime);
Bind(&if_iskeyunique);
TryHasOwnProperty(object, map, instance_type, var_unique.value(),
&return_true, &return_false, &call_runtime);
Bind(&keyisindex);
// Handle negative keys in the runtime.
GotoIf(IntPtrLessThan(var_index.value(), IntPtrConstant(0)), &call_runtime);
TryLookupElement(object, map, instance_type, var_index.value(),
&return_true, &return_false, &call_runtime);
}
Bind(&return_true);
Return(BooleanConstant(true));
Bind(&return_false);
Return(BooleanConstant(false));
Bind(&call_runtime);
Return(CallRuntime(Runtime::kObjectHasOwnProperty, context, object, key));
}
// ES6 19.1.2.1 Object.assign
BUILTIN(ObjectAssign) {
HandleScope scope(isolate);
@ -137,264 +57,6 @@ BUILTIN(ObjectPrototypePropertyIsEnumerable) {
return isolate->heap()->ToBoolean((maybe.FromJust() & DONT_ENUM) == 0);
}
// ES6 section 19.1.3.6 Object.prototype.toString
TF_BUILTIN(ObjectProtoToString, ObjectBuiltinsAssembler) {
Label return_undefined(this, Label::kDeferred),
return_null(this, Label::kDeferred),
return_arguments(this, Label::kDeferred), return_array(this),
return_api(this, Label::kDeferred), return_object(this),
return_regexp(this), return_function(this), return_error(this),
return_date(this), return_jsvalue(this),
return_jsproxy(this, Label::kDeferred);
Label if_isproxy(this, Label::kDeferred);
Label checkstringtag(this);
Label if_tostringtag(this), if_notostringtag(this);
Node* receiver = Parameter(0);
Node* context = Parameter(3);
GotoIf(WordEqual(receiver, UndefinedConstant()), &return_undefined);
GotoIf(WordEqual(receiver, NullConstant()), &return_null);
Callable to_object = CodeFactory::ToObject(isolate());
receiver = CallStub(to_object, context, receiver);
Node* receiver_instance_type = LoadInstanceType(receiver);
// for proxies, check IsArray before getting @@toStringTag
Variable var_proxy_is_array(this, MachineRepresentation::kTagged);
var_proxy_is_array.Bind(BooleanConstant(false));
Branch(Word32Equal(receiver_instance_type, Int32Constant(JS_PROXY_TYPE)),
&if_isproxy, &checkstringtag);
Bind(&if_isproxy);
{
// This can throw
var_proxy_is_array.Bind(
CallRuntime(Runtime::kArrayIsArray, context, receiver));
Goto(&checkstringtag);
}
Bind(&checkstringtag);
{
Node* to_string_tag_symbol =
HeapConstant(isolate()->factory()->to_string_tag_symbol());
GetPropertyStub stub(isolate());
Callable get_property =
Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
Node* to_string_tag_value =
CallStub(get_property, context, receiver, to_string_tag_symbol);
IsString(to_string_tag_value, &if_tostringtag, &if_notostringtag);
Bind(&if_tostringtag);
ReturnToStringFormat(context, to_string_tag_value);
}
Bind(&if_notostringtag);
{
size_t const kNumCases = 11;
Label* case_labels[kNumCases];
int32_t case_values[kNumCases];
case_labels[0] = &return_api;
case_values[0] = JS_API_OBJECT_TYPE;
case_labels[1] = &return_api;
case_values[1] = JS_SPECIAL_API_OBJECT_TYPE;
case_labels[2] = &return_arguments;
case_values[2] = JS_ARGUMENTS_TYPE;
case_labels[3] = &return_array;
case_values[3] = JS_ARRAY_TYPE;
case_labels[4] = &return_function;
case_values[4] = JS_BOUND_FUNCTION_TYPE;
case_labels[5] = &return_function;
case_values[5] = JS_FUNCTION_TYPE;
case_labels[6] = &return_error;
case_values[6] = JS_ERROR_TYPE;
case_labels[7] = &return_date;
case_values[7] = JS_DATE_TYPE;
case_labels[8] = &return_regexp;
case_values[8] = JS_REGEXP_TYPE;
case_labels[9] = &return_jsvalue;
case_values[9] = JS_VALUE_TYPE;
case_labels[10] = &return_jsproxy;
case_values[10] = JS_PROXY_TYPE;
Switch(receiver_instance_type, &return_object, case_values, case_labels,
arraysize(case_values));
Bind(&return_undefined);
Return(HeapConstant(isolate()->factory()->undefined_to_string()));
Bind(&return_null);
Return(HeapConstant(isolate()->factory()->null_to_string()));
Bind(&return_arguments);
Return(HeapConstant(isolate()->factory()->arguments_to_string()));
Bind(&return_array);
Return(HeapConstant(isolate()->factory()->array_to_string()));
Bind(&return_function);
Return(HeapConstant(isolate()->factory()->function_to_string()));
Bind(&return_error);
Return(HeapConstant(isolate()->factory()->error_to_string()));
Bind(&return_date);
Return(HeapConstant(isolate()->factory()->date_to_string()));
Bind(&return_regexp);
Return(HeapConstant(isolate()->factory()->regexp_to_string()));
Bind(&return_api);
{
Node* class_name = CallRuntime(Runtime::kClassOf, context, receiver);
ReturnToStringFormat(context, class_name);
}
Bind(&return_jsvalue);
{
Label return_boolean(this), return_number(this), return_string(this);
Node* value = LoadJSValueValue(receiver);
GotoIf(TaggedIsSmi(value), &return_number);
Node* instance_type = LoadInstanceType(value);
GotoIf(IsStringInstanceType(instance_type), &return_string);
GotoIf(Word32Equal(instance_type, Int32Constant(HEAP_NUMBER_TYPE)),
&return_number);
GotoIf(Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE)),
&return_boolean);
CSA_ASSERT(this, Word32Equal(instance_type, Int32Constant(SYMBOL_TYPE)));
Goto(&return_object);
Bind(&return_string);
Return(HeapConstant(isolate()->factory()->string_to_string()));
Bind(&return_number);
Return(HeapConstant(isolate()->factory()->number_to_string()));
Bind(&return_boolean);
Return(HeapConstant(isolate()->factory()->boolean_to_string()));
}
Bind(&return_jsproxy);
{
GotoIf(WordEqual(var_proxy_is_array.value(), BooleanConstant(true)),
&return_array);
Node* map = LoadMap(receiver);
// Return object if the proxy {receiver} is not callable.
Branch(IsCallableMap(map), &return_function, &return_object);
}
// Default
Bind(&return_object);
Return(HeapConstant(isolate()->factory()->object_to_string()));
}
}
// ES6 19.3.7 Object.prototype.valueOf
TF_BUILTIN(ObjectPrototypeValueOf, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Callable to_object = CodeFactory::ToObject(isolate());
receiver = CallStub(to_object, context, receiver);
Return(receiver);
}
TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
Node* prototype = Parameter(1);
Node* properties = Parameter(2);
Node* context = Parameter(3 + 2);
Label call_runtime(this, Label::kDeferred), prototype_valid(this),
no_properties(this);
{
Comment("Argument 1 check: prototype");
GotoIf(WordEqual(prototype, NullConstant()), &prototype_valid);
BranchIfJSReceiver(prototype, &prototype_valid, &call_runtime);
}
Bind(&prototype_valid);
{
Comment("Argument 2 check: properties");
// Check that we have a simple object
GotoIf(TaggedIsSmi(properties), &call_runtime);
// Undefined implies no properties.
GotoIf(WordEqual(properties, UndefinedConstant()), &no_properties);
Node* properties_map = LoadMap(properties);
GotoIf(IsSpecialReceiverMap(properties_map), &call_runtime);
// Stay on the fast path only if there are no elements.
GotoIfNot(WordEqual(LoadElements(properties),
LoadRoot(Heap::kEmptyFixedArrayRootIndex)),
&call_runtime);
// Handle dictionary objects or fast objects with properties in runtime.
Node* bit_field3 = LoadMapBitField3(properties_map);
GotoIf(IsSetWord32<Map::DictionaryMap>(bit_field3), &call_runtime);
Branch(IsSetWord32<Map::NumberOfOwnDescriptorsBits>(bit_field3),
&call_runtime, &no_properties);
}
// Create a new object with the given prototype.
Bind(&no_properties);
{
Variable map(this, MachineRepresentation::kTagged);
Variable properties(this, MachineRepresentation::kTagged);
Label non_null_proto(this), instantiate_map(this), good(this);
Branch(WordEqual(prototype, NullConstant()), &good, &non_null_proto);
Bind(&good);
{
map.Bind(LoadContextElement(
context, Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP));
properties.Bind(AllocateNameDictionary(NameDictionary::kInitialCapacity));
Goto(&instantiate_map);
}
Bind(&non_null_proto);
{
properties.Bind(EmptyFixedArrayConstant());
Node* object_function =
LoadContextElement(context, Context::OBJECT_FUNCTION_INDEX);
Node* object_function_map = LoadObjectField(
object_function, JSFunction::kPrototypeOrInitialMapOffset);
map.Bind(object_function_map);
GotoIf(WordEqual(prototype, LoadMapPrototype(map.value())),
&instantiate_map);
// Try loading the prototype info.
Node* prototype_info =
LoadMapPrototypeInfo(LoadMap(prototype), &call_runtime);
Comment("Load ObjectCreateMap from PrototypeInfo");
Node* weak_cell =
LoadObjectField(prototype_info, PrototypeInfo::kObjectCreateMap);
GotoIf(WordEqual(weak_cell, UndefinedConstant()), &call_runtime);
map.Bind(LoadWeakCellValue(weak_cell, &call_runtime));
Goto(&instantiate_map);
}
Bind(&instantiate_map);
{
Node* instance = AllocateJSObjectFromMap(map.value(), properties.value());
Return(instance);
}
}
Bind(&call_runtime);
{
Return(CallRuntime(Runtime::kObjectCreate, context, prototype, properties));
}
}
// ES6 section 19.1.2.3 Object.defineProperties
BUILTIN(ObjectDefineProperties) {
HandleScope scope(isolate);
@ -888,64 +550,5 @@ BUILTIN(ObjectSeal) {
return *object;
}
TF_BUILTIN(CreateIterResultObject, ObjectBuiltinsAssembler) {
typedef CreateIterResultObjectDescriptor Descriptor;
Node* const value = Parameter(Descriptor::kValue);
Node* const done = Parameter(Descriptor::kDone);
Node* const context = Parameter(Descriptor::kContext);
Node* const native_context = LoadNativeContext(context);
Node* const map =
LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX);
Node* const result = AllocateJSObjectFromMap(map);
StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, value);
StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, done);
Return(result);
}
TF_BUILTIN(HasProperty, ObjectBuiltinsAssembler) {
typedef HasPropertyDescriptor Descriptor;
Node* key = Parameter(Descriptor::kKey);
Node* object = Parameter(Descriptor::kObject);
Node* context = Parameter(Descriptor::kContext);
Return(HasProperty(object, key, context, Runtime::kHasProperty));
}
TF_BUILTIN(InstanceOf, ObjectBuiltinsAssembler) {
typedef CompareDescriptor Descriptor;
Node* object = Parameter(Descriptor::kLeft);
Node* callable = Parameter(Descriptor::kRight);
Node* context = Parameter(Descriptor::kContext);
Return(InstanceOf(object, callable, context));
}
// ES6 section 7.3.19 OrdinaryHasInstance ( C, O )
TF_BUILTIN(OrdinaryHasInstance, ObjectBuiltinsAssembler) {
typedef CompareDescriptor Descriptor;
Node* constructor = Parameter(Descriptor::kLeft);
Node* object = Parameter(Descriptor::kRight);
Node* context = Parameter(Descriptor::kContext);
Return(OrdinaryHasInstance(context, constructor, object));
}
TF_BUILTIN(GetSuperConstructor, ObjectBuiltinsAssembler) {
typedef TypeofDescriptor Descriptor;
Node* object = Parameter(Descriptor::kObject);
Node* context = Parameter(Descriptor::kContext);
Return(GetSuperConstructor(object, context));
}
} // namespace internal
} // namespace v8

View File

@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins-promise.h"
#include "src/builtins/builtins-constructor.h"
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins-promise.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
@ -13,6 +13,8 @@
namespace v8 {
namespace internal {
using compiler::Node;
Node* PromiseBuiltinsAssembler::AllocateJSPromise(Node* context) {
Node* const native_context = LoadNativeContext(context);
Node* const promise_fun =
@ -410,7 +412,6 @@ Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(
Node* context, Node* promise, Node* on_resolve, Node* on_reject,
Node* deferred_promise, Node* deferred_on_resolve,
Node* deferred_on_reject) {
Variable var_on_resolve(this, MachineRepresentation::kTagged),
var_on_reject(this, MachineRepresentation::kTagged);

View File

@ -11,8 +11,6 @@
namespace v8 {
namespace internal {
typedef compiler::Node Node;
typedef CodeStubAssembler::ParameterMode ParameterMode;
typedef compiler::CodeAssemblerState CodeAssemblerState;
class PromiseBuiltinsAssembler : public CodeStubAssembler {
@ -48,7 +46,7 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler {
kOnFinallyContextLength,
};
explicit PromiseBuiltinsAssembler(CodeAssemblerState* state)
explicit PromiseBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
// These allocate and initialize a promise with pending state and
// undefined fields.

File diff suppressed because it is too large Load Diff

View File

@ -10,13 +10,9 @@
namespace v8 {
namespace internal {
typedef compiler::Node Node;
typedef compiler::CodeAssemblerState CodeAssemblerState;
typedef compiler::CodeAssemblerLabel CodeAssemblerLabel;
class RegExpBuiltinsAssembler : public CodeStubAssembler {
public:
explicit RegExpBuiltinsAssembler(CodeAssemblerState* state)
explicit RegExpBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
void BranchIfFastRegExp(Node* const context, Node* const map,

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,326 @@
// Copyright 2017 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-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
#include "src/objects.h"
namespace v8 {
namespace internal {
using compiler::Node;
class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler {
public:
explicit SharedArrayBufferBuiltinsAssembler(
compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void ValidateSharedTypedArray(Node* tagged, Node* context,
Node** out_instance_type,
Node** out_backing_store);
Node* ConvertTaggedAtomicIndexToWord32(Node* tagged, Node* context,
Node** number_index);
void ValidateAtomicIndex(Node* index_word, Node* array_length_word,
Node* context);
};
void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray(
Node* tagged, Node* context, Node** out_instance_type,
Node** out_backing_store) {
Label not_float_or_clamped(this), invalid(this);
// Fail if it is not a heap object.
GotoIf(TaggedIsSmi(tagged), &invalid);
// Fail if the array's instance type is not JSTypedArray.
GotoIf(Word32NotEqual(LoadInstanceType(tagged),
Int32Constant(JS_TYPED_ARRAY_TYPE)),
&invalid);
// Fail if the array's JSArrayBuffer is not shared.
Node* array_buffer = LoadObjectField(tagged, JSTypedArray::kBufferOffset);
Node* bitfield = LoadObjectField(array_buffer, JSArrayBuffer::kBitFieldOffset,
MachineType::Uint32());
GotoIfNot(IsSetWord32<JSArrayBuffer::IsShared>(bitfield), &invalid);
// Fail if the array's element type is float32, float64 or clamped.
Node* elements_instance_type =
LoadInstanceType(LoadObjectField(tagged, JSObject::kElementsOffset));
STATIC_ASSERT(FIXED_INT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_INT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_INT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_UINT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_UINT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_UINT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
Branch(Int32LessThan(elements_instance_type,
Int32Constant(FIXED_FLOAT32_ARRAY_TYPE)),
&not_float_or_clamped, &invalid);
Bind(&invalid);
{
CallRuntime(Runtime::kThrowNotIntegerSharedTypedArrayError, context,
tagged);
Unreachable();
}
Bind(&not_float_or_clamped);
*out_instance_type = elements_instance_type;
Node* backing_store =
LoadObjectField(array_buffer, JSArrayBuffer::kBackingStoreOffset);
Node* byte_offset = ChangeUint32ToWord(TruncateTaggedToWord32(
context, LoadObjectField(tagged, JSArrayBufferView::kByteOffsetOffset)));
*out_backing_store =
IntPtrAdd(BitcastTaggedToWord(backing_store), byte_offset);
}
// https://tc39.github.io/ecmascript_sharedmem/shmem.html#Atomics.ValidateAtomicAccess
Node* SharedArrayBufferBuiltinsAssembler::ConvertTaggedAtomicIndexToWord32(
Node* tagged, Node* context, Node** number_index) {
Variable var_result(this, MachineRepresentation::kWord32);
// TODO(jkummerow): Skip ToNumber call when |tagged| is a number already.
// Maybe this can be unified with other tagged-to-index conversions?
// Why does this return an int32, and not an intptr?
// Why is there the additional |number_index| output parameter?
Callable to_number = CodeFactory::ToNumber(isolate());
*number_index = CallStub(to_number, context, tagged);
Label done(this, &var_result);
Label if_numberissmi(this), if_numberisnotsmi(this);
Branch(TaggedIsSmi(*number_index), &if_numberissmi, &if_numberisnotsmi);
Bind(&if_numberissmi);
{
var_result.Bind(SmiToWord32(*number_index));
Goto(&done);
}
Bind(&if_numberisnotsmi);
{
Node* number_index_value = LoadHeapNumberValue(*number_index);
Node* access_index = TruncateFloat64ToWord32(number_index_value);
Node* test_index = ChangeInt32ToFloat64(access_index);
Label if_indexesareequal(this), if_indexesarenotequal(this);
Branch(Float64Equal(number_index_value, test_index), &if_indexesareequal,
&if_indexesarenotequal);
Bind(&if_indexesareequal);
{
var_result.Bind(access_index);
Goto(&done);
}
Bind(&if_indexesarenotequal);
{
CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context);
Unreachable();
}
}
Bind(&done);
return var_result.value();
}
void SharedArrayBufferBuiltinsAssembler::ValidateAtomicIndex(
Node* index_word, Node* array_length_word, Node* context) {
// Check if the index is in bounds. If not, throw RangeError.
Label check_passed(this);
GotoIf(Uint32LessThan(index_word, array_length_word), &check_passed);
CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context);
Unreachable();
Bind(&check_passed);
}
TF_BUILTIN(AtomicsLoad, SharedArrayBufferBuiltinsAssembler) {
Node* array = Parameter(1);
Node* index = Parameter(2);
Node* context = Parameter(3 + 2);
Node* instance_type;
Node* backing_store;
ValidateSharedTypedArray(array, context, &instance_type, &backing_store);
Node* index_integer;
Node* index_word32 =
ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
Node* array_length_word32 = TruncateTaggedToWord32(
context, LoadObjectField(array, JSTypedArray::kLengthOffset));
ValidateAtomicIndex(index_word32, array_length_word32, context);
Node* index_word = ChangeUint32ToWord(index_word32);
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
other(this);
int32_t case_values[] = {
FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE,
FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE,
};
Label* case_labels[] = {
&i8, &u8, &i16, &u16, &i32, &u32,
};
Switch(instance_type, &other, case_values, case_labels,
arraysize(case_labels));
Bind(&i8);
Return(SmiFromWord32(
AtomicLoad(MachineType::Int8(), backing_store, index_word)));
Bind(&u8);
Return(SmiFromWord32(
AtomicLoad(MachineType::Uint8(), backing_store, index_word)));
Bind(&i16);
Return(SmiFromWord32(
AtomicLoad(MachineType::Int16(), backing_store, WordShl(index_word, 1))));
Bind(&u16);
Return(SmiFromWord32(AtomicLoad(MachineType::Uint16(), backing_store,
WordShl(index_word, 1))));
Bind(&i32);
Return(ChangeInt32ToTagged(
AtomicLoad(MachineType::Int32(), backing_store, WordShl(index_word, 2))));
Bind(&u32);
Return(ChangeUint32ToTagged(AtomicLoad(MachineType::Uint32(), backing_store,
WordShl(index_word, 2))));
// This shouldn't happen, we've already validated the type.
Bind(&other);
Unreachable();
}
TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) {
Node* array = Parameter(1);
Node* index = Parameter(2);
Node* value = Parameter(3);
Node* context = Parameter(4 + 2);
Node* instance_type;
Node* backing_store;
ValidateSharedTypedArray(array, context, &instance_type, &backing_store);
Node* index_integer;
Node* index_word32 =
ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
Node* array_length_word32 = TruncateTaggedToWord32(
context, LoadObjectField(array, JSTypedArray::kLengthOffset));
ValidateAtomicIndex(index_word32, array_length_word32, context);
Node* index_word = ChangeUint32ToWord(index_word32);
Node* value_integer = ToInteger(context, value);
Node* value_word32 = TruncateTaggedToWord32(context, value_integer);
Label u8(this), u16(this), u32(this), other(this);
int32_t case_values[] = {
FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE,
FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE,
};
Label* case_labels[] = {
&u8, &u8, &u16, &u16, &u32, &u32,
};
Switch(instance_type, &other, case_values, case_labels,
arraysize(case_labels));
Bind(&u8);
AtomicStore(MachineRepresentation::kWord8, backing_store, index_word,
value_word32);
Return(value_integer);
Bind(&u16);
AtomicStore(MachineRepresentation::kWord16, backing_store,
WordShl(index_word, 1), value_word32);
Return(value_integer);
Bind(&u32);
AtomicStore(MachineRepresentation::kWord32, backing_store,
WordShl(index_word, 2), value_word32);
Return(value_integer);
// This shouldn't happen, we've already validated the type.
Bind(&other);
Unreachable();
}
TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
Node* array = Parameter(1);
Node* index = Parameter(2);
Node* value = Parameter(3);
Node* context = Parameter(4 + 2);
Node* instance_type;
Node* backing_store;
ValidateSharedTypedArray(array, context, &instance_type, &backing_store);
Node* index_integer;
Node* index_word32 =
ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
Node* array_length_word32 = TruncateTaggedToWord32(
context, LoadObjectField(array, JSTypedArray::kLengthOffset));
ValidateAtomicIndex(index_word32, array_length_word32, context);
Node* value_integer = ToInteger(context, value);
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \
V8_TARGET_ARCH_PPC
Return(CallRuntime(Runtime::kAtomicsExchange, context, array, index_integer,
value_integer));
#else
Node* index_word = ChangeUint32ToWord(index_word32);
Node* value_word32 = TruncateTaggedToWord32(context, value_integer);
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
other(this);
int32_t case_values[] = {
FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE,
FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE,
};
Label* case_labels[] = {
&i8, &u8, &i16, &u16, &i32, &u32,
};
Switch(instance_type, &other, case_values, case_labels,
arraysize(case_labels));
Bind(&i8);
Return(SmiFromWord32(AtomicExchange(MachineType::Int8(), backing_store,
index_word, value_word32)));
Bind(&u8);
Return(SmiFromWord32(AtomicExchange(MachineType::Uint8(), backing_store,
index_word, value_word32)));
Bind(&i16);
Return(SmiFromWord32(AtomicExchange(MachineType::Int16(), backing_store,
WordShl(index_word, 1), value_word32)));
Bind(&u16);
Return(SmiFromWord32(AtomicExchange(MachineType::Uint16(), backing_store,
WordShl(index_word, 1), value_word32)));
Bind(&i32);
Return(ChangeInt32ToTagged(AtomicExchange(MachineType::Int32(), backing_store,
WordShl(index_word, 2),
value_word32)));
Bind(&u32);
Return(ChangeUint32ToTagged(
AtomicExchange(MachineType::Uint32(), backing_store,
WordShl(index_word, 2), value_word32)));
// This shouldn't happen, we've already validated the type.
Bind(&other);
Unreachable();
#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64
// || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X
}
} // namespace internal
} // namespace v8

View File

@ -8,7 +8,6 @@
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
#include "src/conversions-inl.h"
#include "src/counters.h"
#include "src/factory.h"
@ -19,24 +18,6 @@
namespace v8 {
namespace internal {
using compiler::Node;
class SharedArrayBufferBuiltinsAssembler : public CodeStubAssembler {
public:
explicit SharedArrayBufferBuiltinsAssembler(
compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void ValidateSharedTypedArray(Node* tagged, Node* context,
Node** out_instance_type,
Node** out_backing_store);
Node* ConvertTaggedAtomicIndexToWord32(Node* tagged, Node* context,
Node** number_index);
void ValidateAtomicIndex(Node* index_word, Node* array_length_word,
Node* context);
};
// ES7 sharedmem 6.3.4.1 get SharedArrayBuffer.prototype.byteLength
BUILTIN(SharedArrayBufferPrototypeGetByteLength) {
HandleScope scope(isolate);
@ -52,300 +33,6 @@ BUILTIN(SharedArrayBufferPrototypeGetByteLength) {
return array_buffer->byte_length();
}
void SharedArrayBufferBuiltinsAssembler::ValidateSharedTypedArray(
Node* tagged, Node* context, Node** out_instance_type,
Node** out_backing_store) {
Label not_float_or_clamped(this), invalid(this);
// Fail if it is not a heap object.
GotoIf(TaggedIsSmi(tagged), &invalid);
// Fail if the array's instance type is not JSTypedArray.
GotoIf(Word32NotEqual(LoadInstanceType(tagged),
Int32Constant(JS_TYPED_ARRAY_TYPE)),
&invalid);
// Fail if the array's JSArrayBuffer is not shared.
Node* array_buffer = LoadObjectField(tagged, JSTypedArray::kBufferOffset);
Node* bitfield = LoadObjectField(array_buffer, JSArrayBuffer::kBitFieldOffset,
MachineType::Uint32());
GotoIfNot(IsSetWord32<JSArrayBuffer::IsShared>(bitfield), &invalid);
// Fail if the array's element type is float32, float64 or clamped.
Node* elements_instance_type =
LoadInstanceType(LoadObjectField(tagged, JSObject::kElementsOffset));
STATIC_ASSERT(FIXED_INT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_INT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_INT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_UINT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_UINT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
STATIC_ASSERT(FIXED_UINT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE);
Branch(Int32LessThan(elements_instance_type,
Int32Constant(FIXED_FLOAT32_ARRAY_TYPE)),
&not_float_or_clamped, &invalid);
Bind(&invalid);
{
CallRuntime(Runtime::kThrowNotIntegerSharedTypedArrayError, context,
tagged);
Unreachable();
}
Bind(&not_float_or_clamped);
*out_instance_type = elements_instance_type;
Node* backing_store =
LoadObjectField(array_buffer, JSArrayBuffer::kBackingStoreOffset);
Node* byte_offset = ChangeUint32ToWord(TruncateTaggedToWord32(
context, LoadObjectField(tagged, JSArrayBufferView::kByteOffsetOffset)));
*out_backing_store =
IntPtrAdd(BitcastTaggedToWord(backing_store), byte_offset);
}
// https://tc39.github.io/ecmascript_sharedmem/shmem.html#Atomics.ValidateAtomicAccess
Node* SharedArrayBufferBuiltinsAssembler::ConvertTaggedAtomicIndexToWord32(
Node* tagged, Node* context, Node** number_index) {
Variable var_result(this, MachineRepresentation::kWord32);
// TODO(jkummerow): Skip ToNumber call when |tagged| is a number already.
// Maybe this can be unified with other tagged-to-index conversions?
// Why does this return an int32, and not an intptr?
// Why is there the additional |number_index| output parameter?
Callable to_number = CodeFactory::ToNumber(isolate());
*number_index = CallStub(to_number, context, tagged);
Label done(this, &var_result);
Label if_numberissmi(this), if_numberisnotsmi(this);
Branch(TaggedIsSmi(*number_index), &if_numberissmi, &if_numberisnotsmi);
Bind(&if_numberissmi);
{
var_result.Bind(SmiToWord32(*number_index));
Goto(&done);
}
Bind(&if_numberisnotsmi);
{
Node* number_index_value = LoadHeapNumberValue(*number_index);
Node* access_index = TruncateFloat64ToWord32(number_index_value);
Node* test_index = ChangeInt32ToFloat64(access_index);
Label if_indexesareequal(this), if_indexesarenotequal(this);
Branch(Float64Equal(number_index_value, test_index), &if_indexesareequal,
&if_indexesarenotequal);
Bind(&if_indexesareequal);
{
var_result.Bind(access_index);
Goto(&done);
}
Bind(&if_indexesarenotequal);
{
CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context);
Unreachable();
}
}
Bind(&done);
return var_result.value();
}
void SharedArrayBufferBuiltinsAssembler::ValidateAtomicIndex(
Node* index_word, Node* array_length_word, Node* context) {
// Check if the index is in bounds. If not, throw RangeError.
Label check_passed(this);
GotoIf(Uint32LessThan(index_word, array_length_word), &check_passed);
CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context);
Unreachable();
Bind(&check_passed);
}
TF_BUILTIN(AtomicsLoad, SharedArrayBufferBuiltinsAssembler) {
Node* array = Parameter(1);
Node* index = Parameter(2);
Node* context = Parameter(3 + 2);
Node* instance_type;
Node* backing_store;
ValidateSharedTypedArray(array, context, &instance_type, &backing_store);
Node* index_integer;
Node* index_word32 =
ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
Node* array_length_word32 = TruncateTaggedToWord32(
context, LoadObjectField(array, JSTypedArray::kLengthOffset));
ValidateAtomicIndex(index_word32, array_length_word32, context);
Node* index_word = ChangeUint32ToWord(index_word32);
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
other(this);
int32_t case_values[] = {
FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE,
FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE,
};
Label* case_labels[] = {
&i8, &u8, &i16, &u16, &i32, &u32,
};
Switch(instance_type, &other, case_values, case_labels,
arraysize(case_labels));
Bind(&i8);
Return(SmiFromWord32(
AtomicLoad(MachineType::Int8(), backing_store, index_word)));
Bind(&u8);
Return(SmiFromWord32(
AtomicLoad(MachineType::Uint8(), backing_store, index_word)));
Bind(&i16);
Return(SmiFromWord32(
AtomicLoad(MachineType::Int16(), backing_store, WordShl(index_word, 1))));
Bind(&u16);
Return(SmiFromWord32(AtomicLoad(MachineType::Uint16(), backing_store,
WordShl(index_word, 1))));
Bind(&i32);
Return(ChangeInt32ToTagged(
AtomicLoad(MachineType::Int32(), backing_store, WordShl(index_word, 2))));
Bind(&u32);
Return(ChangeUint32ToTagged(AtomicLoad(MachineType::Uint32(), backing_store,
WordShl(index_word, 2))));
// This shouldn't happen, we've already validated the type.
Bind(&other);
Unreachable();
}
TF_BUILTIN(AtomicsStore, SharedArrayBufferBuiltinsAssembler) {
Node* array = Parameter(1);
Node* index = Parameter(2);
Node* value = Parameter(3);
Node* context = Parameter(4 + 2);
Node* instance_type;
Node* backing_store;
ValidateSharedTypedArray(array, context, &instance_type, &backing_store);
Node* index_integer;
Node* index_word32 =
ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
Node* array_length_word32 = TruncateTaggedToWord32(
context, LoadObjectField(array, JSTypedArray::kLengthOffset));
ValidateAtomicIndex(index_word32, array_length_word32, context);
Node* index_word = ChangeUint32ToWord(index_word32);
Node* value_integer = ToInteger(context, value);
Node* value_word32 = TruncateTaggedToWord32(context, value_integer);
Label u8(this), u16(this), u32(this), other(this);
int32_t case_values[] = {
FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE,
FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE,
};
Label* case_labels[] = {
&u8, &u8, &u16, &u16, &u32, &u32,
};
Switch(instance_type, &other, case_values, case_labels,
arraysize(case_labels));
Bind(&u8);
AtomicStore(MachineRepresentation::kWord8, backing_store, index_word,
value_word32);
Return(value_integer);
Bind(&u16);
AtomicStore(MachineRepresentation::kWord16, backing_store,
WordShl(index_word, 1), value_word32);
Return(value_integer);
Bind(&u32);
AtomicStore(MachineRepresentation::kWord32, backing_store,
WordShl(index_word, 2), value_word32);
Return(value_integer);
// This shouldn't happen, we've already validated the type.
Bind(&other);
Unreachable();
}
TF_BUILTIN(AtomicsExchange, SharedArrayBufferBuiltinsAssembler) {
Node* array = Parameter(1);
Node* index = Parameter(2);
Node* value = Parameter(3);
Node* context = Parameter(4 + 2);
Node* instance_type;
Node* backing_store;
ValidateSharedTypedArray(array, context, &instance_type, &backing_store);
Node* index_integer;
Node* index_word32 =
ConvertTaggedAtomicIndexToWord32(index, context, &index_integer);
Node* array_length_word32 = TruncateTaggedToWord32(
context, LoadObjectField(array, JSTypedArray::kLengthOffset));
ValidateAtomicIndex(index_word32, array_length_word32, context);
Node* value_integer = ToInteger(context, value);
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || \
V8_TARGET_ARCH_PPC
Return(CallRuntime(Runtime::kAtomicsExchange, context, array, index_integer,
value_integer));
#else
Node* index_word = ChangeUint32ToWord(index_word32);
Node* value_word32 = TruncateTaggedToWord32(context, value_integer);
Label i8(this), u8(this), i16(this), u16(this), i32(this), u32(this),
other(this);
int32_t case_values[] = {
FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE,
FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE,
};
Label* case_labels[] = {
&i8, &u8, &i16, &u16, &i32, &u32,
};
Switch(instance_type, &other, case_values, case_labels,
arraysize(case_labels));
Bind(&i8);
Return(SmiFromWord32(AtomicExchange(MachineType::Int8(), backing_store,
index_word, value_word32)));
Bind(&u8);
Return(SmiFromWord32(AtomicExchange(MachineType::Uint8(), backing_store,
index_word, value_word32)));
Bind(&i16);
Return(SmiFromWord32(AtomicExchange(MachineType::Int16(), backing_store,
WordShl(index_word, 1), value_word32)));
Bind(&u16);
Return(SmiFromWord32(AtomicExchange(MachineType::Uint16(), backing_store,
WordShl(index_word, 1), value_word32)));
Bind(&i32);
Return(ChangeInt32ToTagged(AtomicExchange(MachineType::Int32(), backing_store,
WordShl(index_word, 2),
value_word32)));
Bind(&u32);
Return(ChangeUint32ToTagged(
AtomicExchange(MachineType::Uint32(), backing_store,
WordShl(index_word, 2), value_word32)));
// This shouldn't happen, we've already validated the type.
Bind(&other);
Unreachable();
#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64
// || V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_S390X
}
inline bool AtomicIsLockFree(uint32_t size) {
return size == 1 || size == 2 || size == 4;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,47 @@
// Copyright 2017 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-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
// ES6 section 19.4 Symbol Objects
// ES6 section 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint )
TF_BUILTIN(SymbolPrototypeToPrimitive, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* context = Parameter(4);
Node* result = ToThisValue(context, receiver, PrimitiveType::kSymbol,
"Symbol.prototype [ @@toPrimitive ]");
Return(result);
}
// ES6 section 19.4.3.2 Symbol.prototype.toString ( )
TF_BUILTIN(SymbolPrototypeToString, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Node* value = ToThisValue(context, receiver, PrimitiveType::kSymbol,
"Symbol.prototype.toString");
Node* result = CallRuntime(Runtime::kSymbolDescriptiveString, context, value);
Return(result);
}
// ES6 section 19.4.3.3 Symbol.prototype.valueOf ( )
TF_BUILTIN(SymbolPrototypeValueOf, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Node* result = ToThisValue(context, receiver, PrimitiveType::kSymbol,
"Symbol.prototype.valueOf");
Return(result);
}
} // namespace internal
} // namespace v8

View File

@ -4,7 +4,6 @@
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
#include "src/counters.h"
#include "src/objects-inl.h"
@ -67,36 +66,5 @@ BUILTIN(SymbolKeyFor) {
return result;
}
// ES6 section 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint )
TF_BUILTIN(SymbolPrototypeToPrimitive, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* context = Parameter(4);
Node* result = ToThisValue(context, receiver, PrimitiveType::kSymbol,
"Symbol.prototype [ @@toPrimitive ]");
Return(result);
}
// ES6 section 19.4.3.2 Symbol.prototype.toString ( )
TF_BUILTIN(SymbolPrototypeToString, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Node* value = ToThisValue(context, receiver, PrimitiveType::kSymbol,
"Symbol.prototype.toString");
Node* result = CallRuntime(Runtime::kSymbolDescriptiveString, context, value);
Return(result);
}
// ES6 section 19.4.3.3 Symbol.prototype.valueOf ( )
TF_BUILTIN(SymbolPrototypeValueOf, CodeStubAssembler) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Node* result = ToThisValue(context, receiver, PrimitiveType::kSymbol,
"Symbol.prototype.valueOf");
Return(result);
}
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,583 @@
// Copyright 2017 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-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
// ES6 section 22.2 TypedArray Objects
class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
public:
explicit TypedArrayBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void GenerateTypedArrayPrototypeGetter(const char* method_name,
int object_offset);
template <IterationKind kIterationKind>
void GenerateTypedArrayPrototypeIterationMethod(const char* method_name);
void LoadMapAndElementsSize(Node* const array, Variable* typed_map,
Variable* size);
void CalculateExternalPointer(Node* const backing_store,
Node* const byte_offset,
Variable* external_pointer);
void DoInitialize(Node* const holder, Node* length, Node* const maybe_buffer,
Node* const byte_offset, Node* byte_length,
Node* const initialize, Node* const context);
};
void TypedArrayBuiltinsAssembler::LoadMapAndElementsSize(Node* const array,
Variable* typed_map,
Variable* size) {
Label unreachable(this), done(this);
Label uint8_elements(this), uint8_clamped_elements(this), int8_elements(this),
uint16_elements(this), int16_elements(this), uint32_elements(this),
int32_elements(this), float32_elements(this), float64_elements(this);
Label* elements_kind_labels[] = {
&uint8_elements, &uint8_clamped_elements, &int8_elements,
&uint16_elements, &int16_elements, &uint32_elements,
&int32_elements, &float32_elements, &float64_elements};
int32_t elements_kinds[] = {
UINT8_ELEMENTS, UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
UINT16_ELEMENTS, INT16_ELEMENTS, UINT32_ELEMENTS,
INT32_ELEMENTS, FLOAT32_ELEMENTS, FLOAT64_ELEMENTS};
const size_t kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
1;
DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
Node* array_map = LoadMap(array);
Node* elements_kind = LoadMapElementsKind(array_map);
Switch(elements_kind, &unreachable, elements_kinds, elements_kind_labels,
kTypedElementsKindCount);
for (int i = 0; i < static_cast<int>(kTypedElementsKindCount); i++) {
Bind(elements_kind_labels[i]);
{
ElementsKind kind = static_cast<ElementsKind>(elements_kinds[i]);
ExternalArrayType type =
isolate()->factory()->GetArrayTypeFromElementsKind(kind);
Handle<Map> map(isolate()->heap()->MapForFixedTypedArray(type));
typed_map->Bind(HeapConstant(map));
size->Bind(SmiConstant(static_cast<int>(
isolate()->factory()->GetExternalArrayElementSize(type))));
Goto(&done);
}
}
Bind(&unreachable);
{ Unreachable(); }
Bind(&done);
}
// The byte_offset can be higher than Smi range, in which case to perform the
// pointer arithmetic necessary to calculate external_pointer, converting
// byte_offset to an intptr is more difficult. The max byte_offset is 8 * MaxSmi
// on the particular platform. 32 bit platforms are self-limiting, because we
// can't allocate an array bigger than our 32-bit arithmetic range anyway. 64
// bit platforms could theoretically have an offset up to 2^35 - 1, so we may
// need to convert the float heap number to an intptr.
void TypedArrayBuiltinsAssembler::CalculateExternalPointer(
Node* const backing_store, Node* const byte_offset,
Variable* external_pointer) {
Label offset_is_smi(this), offset_not_smi(this), done(this);
Branch(TaggedIsSmi(byte_offset), &offset_is_smi, &offset_not_smi);
Bind(&offset_is_smi);
{
external_pointer->Bind(IntPtrAdd(backing_store, SmiToWord(byte_offset)));
Goto(&done);
}
Bind(&offset_not_smi);
{
Node* heap_number = LoadHeapNumberValue(byte_offset);
Node* intrptr_value = ChangeFloat64ToUintPtr(heap_number);
external_pointer->Bind(IntPtrAdd(backing_store, intrptr_value));
Goto(&done);
}
Bind(&done);
}
void TypedArrayBuiltinsAssembler::DoInitialize(Node* const holder, Node* length,
Node* const maybe_buffer,
Node* const byte_offset,
Node* byte_length,
Node* const initialize,
Node* const context) {
static const int32_t fta_base_data_offset =
FixedTypedArrayBase::kDataOffset - kHeapObjectTag;
Label setup_holder(this), alloc_array_buffer(this), aligned(this),
allocate_elements(this), attach_buffer(this), done(this);
Variable fixed_typed_map(this, MachineRepresentation::kTagged);
Variable element_size(this, MachineRepresentation::kTagged);
Variable total_size(this, MachineType::PointerRepresentation());
// Make sure length is a Smi. The caller guarantees this is the case.
length = ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero);
CSA_ASSERT(this, TaggedIsSmi(length));
// byte_length can be -0, get rid of it.
byte_length =
ToInteger(context, byte_length, CodeStubAssembler::kTruncateMinusZero);
GotoIfNot(IsNull(maybe_buffer), &setup_holder);
// If the buffer is null, then we need a Smi byte_length. The caller
// guarantees this is the case, because when byte_length >
// TypedArrayMaxSizeInHeap, a buffer is allocated and passed in here.
CSA_ASSERT(this, TaggedIsSmi(byte_length));
Goto(&setup_holder);
Bind(&setup_holder);
{
LoadMapAndElementsSize(holder, &fixed_typed_map, &element_size);
// Setup the holder (JSArrayBufferView).
// - Set the length.
// - Set the byte_offset.
// - Set the byte_length.
// - Set InternalFields to 0.
StoreObjectField(holder, JSTypedArray::kLengthOffset, length);
StoreObjectField(holder, JSArrayBufferView::kByteOffsetOffset, byte_offset);
StoreObjectField(holder, JSArrayBufferView::kByteLengthOffset, byte_length);
for (int offset = JSTypedArray::kSize;
offset < JSTypedArray::kSizeWithInternalFields;
offset += kPointerSize) {
StoreObjectField(holder, offset, SmiConstant(Smi::kZero));
}
Branch(IsNull(maybe_buffer), &alloc_array_buffer, &attach_buffer);
}
Bind(&alloc_array_buffer);
{
// Allocate a new ArrayBuffer and initialize it with empty properties and
// elements.
Node* const native_context = LoadNativeContext(context);
Node* const map =
LoadContextElement(native_context, Context::ARRAY_BUFFER_MAP_INDEX);
Node* empty_fixed_array = LoadRoot(Heap::kEmptyFixedArrayRootIndex);
Node* const buffer = Allocate(JSArrayBuffer::kSizeWithInternalFields);
StoreMapNoWriteBarrier(buffer, map);
StoreObjectFieldNoWriteBarrier(buffer, JSArray::kPropertiesOffset,
empty_fixed_array);
StoreObjectFieldNoWriteBarrier(buffer, JSArray::kElementsOffset,
empty_fixed_array);
// Setup the ArrayBuffer.
// - Set BitField to 0.
// - Set IsExternal and IsNeuterable bits of BitFieldSlot.
// - Set the byte_length field to byte_length.
// - Set backing_store to null/Smi(0).
// - Set all internal fields to Smi(0).
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldSlot,
SmiConstant(Smi::kZero));
int32_t bitfield_value = (1 << JSArrayBuffer::IsExternal::kShift) |
(1 << JSArrayBuffer::IsNeuterable::kShift);
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldOffset,
Int32Constant(bitfield_value),
MachineRepresentation::kWord32);
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kByteLengthOffset,
byte_length);
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBackingStoreOffset,
SmiConstant(Smi::kZero));
for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
int offset = JSArrayBuffer::kSize + i * kPointerSize;
StoreObjectFieldNoWriteBarrier(buffer, offset, SmiConstant(Smi::kZero));
}
StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
// Check the alignment.
GotoIf(SmiEqual(SmiMod(element_size.value(), SmiConstant(kObjectAlignment)),
SmiConstant(0)),
&aligned);
// Fix alignment if needed.
DCHECK_EQ(0, FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask);
Node* aligned_header_size =
IntPtrConstant(FixedTypedArrayBase::kHeaderSize + kObjectAlignmentMask);
Node* size = IntPtrAdd(SmiToWord(byte_length), aligned_header_size);
total_size.Bind(WordAnd(size, IntPtrConstant(~kObjectAlignmentMask)));
Goto(&allocate_elements);
}
Bind(&aligned);
{
Node* header_size = IntPtrConstant(FixedTypedArrayBase::kHeaderSize);
total_size.Bind(IntPtrAdd(SmiToWord(byte_length), header_size));
Goto(&allocate_elements);
}
Bind(&allocate_elements);
{
// Allocate a FixedTypedArray and set the length, base pointer and external
// pointer.
CSA_ASSERT(this, IsRegularHeapObjectSize(total_size.value()));
Node* elements = Allocate(total_size.value());
StoreMapNoWriteBarrier(elements, fixed_typed_map.value());
StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
StoreObjectFieldNoWriteBarrier(
elements, FixedTypedArrayBase::kBasePointerOffset, elements);
StoreObjectFieldNoWriteBarrier(elements,
FixedTypedArrayBase::kExternalPointerOffset,
IntPtrConstant(fta_base_data_offset),
MachineType::PointerRepresentation());
StoreObjectField(holder, JSObject::kElementsOffset, elements);
GotoIf(IsFalse(initialize), &done);
// Initialize the backing store by filling it with 0s.
Node* backing_store = IntPtrAdd(BitcastTaggedToWord(elements),
IntPtrConstant(fta_base_data_offset));
// Call out to memset to perform initialization.
Node* memset =
ExternalConstant(ExternalReference::libc_memset_function(isolate()));
CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
MachineType::IntPtr(), MachineType::UintPtr(), memset,
backing_store, IntPtrConstant(0), SmiToWord(byte_length));
Goto(&done);
}
Bind(&attach_buffer);
{
StoreObjectField(holder, JSArrayBufferView::kBufferOffset, maybe_buffer);
Node* elements = Allocate(FixedTypedArrayBase::kHeaderSize);
StoreMapNoWriteBarrier(elements, fixed_typed_map.value());
StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
StoreObjectFieldNoWriteBarrier(
elements, FixedTypedArrayBase::kBasePointerOffset, SmiConstant(0));
Variable external_pointer(this, MachineType::PointerRepresentation());
Node* backing_store =
LoadObjectField(maybe_buffer, JSArrayBuffer::kBackingStoreOffset,
MachineType::Pointer());
CalculateExternalPointer(backing_store, byte_offset, &external_pointer);
StoreObjectFieldNoWriteBarrier(
elements, FixedTypedArrayBase::kExternalPointerOffset,
external_pointer.value(), MachineType::PointerRepresentation());
StoreObjectField(holder, JSObject::kElementsOffset, elements);
Goto(&done);
}
Bind(&done);
Return(UndefinedConstant());
}
TF_BUILTIN(TypedArrayInitialize, TypedArrayBuiltinsAssembler) {
Node* const holder = Parameter(1);
Node* length = Parameter(2);
Node* const maybe_buffer = Parameter(3);
Node* const byte_offset = Parameter(4);
Node* byte_length = Parameter(5);
Node* const initialize = Parameter(6);
Node* const context = Parameter(9);
DoInitialize(holder, length, maybe_buffer, byte_offset, byte_length,
initialize, context);
}
// ES6 section 22.2.4.2 TypedArray ( length )
TF_BUILTIN(TypedArrayConstructByLength, TypedArrayBuiltinsAssembler) {
// We know that holder cannot be an object if this builtin was called.
Node* holder = Parameter(1);
Node* length = Parameter(2);
Node* element_size = Parameter(3);
Node* context = Parameter(6);
Variable maybe_buffer(this, MachineRepresentation::kTagged);
maybe_buffer.Bind(NullConstant());
Node* byte_offset = SmiConstant(0);
Node* initialize = BooleanConstant(true);
Label external_buffer(this), call_init(this), invalid_length(this);
length = ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero);
// The maximum length of a TypedArray is MaxSmi().
// Note: this is not per spec, but rather a constraint of our current
// representation (which uses smi's).
GotoIf(TaggedIsNotSmi(length), &invalid_length);
GotoIf(SmiLessThan(length, SmiConstant(0)), &invalid_length);
// For byte_length < typed_array_max_size_in_heap, we allocate the buffer on
// the heap. Otherwise we allocate it externally and attach it.
Node* byte_length = SmiMul(length, element_size);
GotoIf(TaggedIsNotSmi(byte_length), &external_buffer);
Branch(SmiLessThanOrEqual(byte_length,
SmiConstant(FLAG_typed_array_max_size_in_heap)),
&call_init, &external_buffer);
Bind(&external_buffer);
{
Node* const buffer_constructor = LoadContextElement(
LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX);
maybe_buffer.Bind(ConstructJS(CodeFactory::Construct(isolate()), context,
buffer_constructor, byte_length));
Goto(&call_init);
}
Bind(&call_init);
{
DoInitialize(holder, length, maybe_buffer.value(), byte_offset, byte_length,
initialize, context);
}
Bind(&invalid_length);
{
CallRuntime(Runtime::kThrowRangeError, context,
SmiConstant(MessageTemplate::kInvalidTypedArrayLength));
Unreachable();
}
}
// ES6 section 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
TF_BUILTIN(TypedArrayConstructByArrayBuffer, TypedArrayBuiltinsAssembler) {
Node* const holder = Parameter(1);
Node* const buffer = Parameter(2);
Node* byte_offset = Parameter(3);
Node* const length = Parameter(4);
Node* const element_size = Parameter(5);
CSA_ASSERT(this, TaggedIsSmi(element_size));
Node* const context = Parameter(8);
Node* const initialize = BooleanConstant(true);
Variable new_byte_length(this, MachineRepresentation::kTagged,
SmiConstant(0));
Label start_offset_error(this), byte_length_error(this),
invalid_offset_error(this);
Label call_init(this), invalid_length(this), length_undefined(this),
length_defined(this);
Callable add = CodeFactory::Add(isolate());
Callable div = CodeFactory::Divide(isolate());
Callable equal = CodeFactory::Equal(isolate());
Callable greater_than = CodeFactory::GreaterThan(isolate());
Callable less_than = CodeFactory::LessThan(isolate());
Callable mod = CodeFactory::Modulus(isolate());
Callable sub = CodeFactory::Subtract(isolate());
byte_offset =
ToInteger(context, byte_offset, CodeStubAssembler::kTruncateMinusZero);
GotoIf(IsTrue(CallStub(less_than, context, byte_offset, SmiConstant(0))),
&invalid_length);
Node* remainder = CallStub(mod, context, byte_offset, element_size);
// Remainder can be a heap number.
GotoIf(IsFalse(CallStub(equal, context, remainder, SmiConstant(0))),
&start_offset_error);
// TODO(petermarshall): Throw on detached typedArray.
Branch(IsUndefined(length), &length_undefined, &length_defined);
Bind(&length_undefined);
{
Node* buffer_byte_length =
LoadObjectField(buffer, JSArrayBuffer::kByteLengthOffset);
Node* remainder = CallStub(mod, context, buffer_byte_length, element_size);
// Remainder can be a heap number.
GotoIf(IsFalse(CallStub(equal, context, remainder, SmiConstant(0))),
&byte_length_error);
new_byte_length.Bind(
CallStub(sub, context, buffer_byte_length, byte_offset));
Branch(IsTrue(CallStub(less_than, context, new_byte_length.value(),
SmiConstant(0))),
&invalid_offset_error, &call_init);
}
Bind(&length_defined);
{
Node* new_length = ToSmiIndex(length, context, &invalid_length);
new_byte_length.Bind(SmiMul(new_length, element_size));
// Reading the byte length must come after the ToIndex operation, which
// could cause the buffer to become detached.
Node* buffer_byte_length =
LoadObjectField(buffer, JSArrayBuffer::kByteLengthOffset);
Node* end = CallStub(add, context, byte_offset, new_byte_length.value());
Branch(IsTrue(CallStub(greater_than, context, end, buffer_byte_length)),
&invalid_length, &call_init);
}
Bind(&call_init);
{
Node* new_length =
CallStub(div, context, new_byte_length.value(), element_size);
// Force the result into a Smi, or throw a range error if it doesn't fit.
new_length = ToSmiIndex(new_length, context, &invalid_length);
DoInitialize(holder, new_length, buffer, byte_offset,
new_byte_length.value(), initialize, context);
}
Bind(&invalid_offset_error);
{
CallRuntime(Runtime::kThrowRangeError, context,
SmiConstant(MessageTemplate::kInvalidOffset), byte_offset);
Unreachable();
}
Bind(&start_offset_error);
{
Node* holder_map = LoadMap(holder);
Node* problem_string = HeapConstant(
factory()->NewStringFromAsciiChecked("start offset", TENURED));
CallRuntime(Runtime::kThrowInvalidTypedArrayAlignment, context, holder_map,
problem_string);
Unreachable();
}
Bind(&byte_length_error);
{
Node* holder_map = LoadMap(holder);
Node* problem_string = HeapConstant(
factory()->NewStringFromAsciiChecked("byte length", TENURED));
CallRuntime(Runtime::kThrowInvalidTypedArrayAlignment, context, holder_map,
problem_string);
Unreachable();
}
Bind(&invalid_length);
{
CallRuntime(Runtime::kThrowRangeError, context,
SmiConstant(MessageTemplate::kInvalidTypedArrayLength));
Unreachable();
}
}
void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeGetter(
const char* method_name, int object_offset) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
// Check if the {receiver} is actually a JSTypedArray.
Label receiver_is_incompatible(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &receiver_is_incompatible);
GotoIfNot(HasInstanceType(receiver, JS_TYPED_ARRAY_TYPE),
&receiver_is_incompatible);
// Check if the {receiver}'s JSArrayBuffer was neutered.
Node* receiver_buffer =
LoadObjectField(receiver, JSTypedArray::kBufferOffset);
Label if_receiverisneutered(this, Label::kDeferred);
GotoIf(IsDetachedBuffer(receiver_buffer), &if_receiverisneutered);
Return(LoadObjectField(receiver, object_offset));
Bind(&if_receiverisneutered);
{
// The {receiver}s buffer was neutered, default to zero.
Return(SmiConstant(0));
}
Bind(&receiver_is_incompatible);
{
// The {receiver} is not a valid JSTypedArray.
CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
HeapConstant(
factory()->NewStringFromAsciiChecked(method_name, TENURED)),
receiver);
Unreachable();
}
}
// ES6 section 22.2.3.2 get %TypedArray%.prototype.byteLength
TF_BUILTIN(TypedArrayPrototypeByteLength, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeGetter("get TypedArray.prototype.byteLength",
JSTypedArray::kByteLengthOffset);
}
// ES6 section 22.2.3.3 get %TypedArray%.prototype.byteOffset
TF_BUILTIN(TypedArrayPrototypeByteOffset, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeGetter("get TypedArray.prototype.byteOffset",
JSTypedArray::kByteOffsetOffset);
}
// ES6 section 22.2.3.18 get %TypedArray%.prototype.length
TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeGetter("get TypedArray.prototype.length",
JSTypedArray::kLengthOffset);
}
template <IterationKind kIterationKind>
void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeIterationMethod(
const char* method_name) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Label throw_bad_receiver(this, Label::kDeferred);
Label throw_typeerror(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &throw_bad_receiver);
Node* map = LoadMap(receiver);
Node* instance_type = LoadMapInstanceType(map);
GotoIf(Word32NotEqual(instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
&throw_bad_receiver);
// Check if the {receiver}'s JSArrayBuffer was neutered.
Node* receiver_buffer =
LoadObjectField(receiver, JSTypedArray::kBufferOffset);
Label if_receiverisneutered(this, Label::kDeferred);
GotoIf(IsDetachedBuffer(receiver_buffer), &if_receiverisneutered);
Return(CreateArrayIterator(receiver, map, instance_type, context,
kIterationKind));
Variable var_message(this, MachineRepresentation::kTagged);
Bind(&throw_bad_receiver);
var_message.Bind(SmiConstant(MessageTemplate::kNotTypedArray));
Goto(&throw_typeerror);
Bind(&if_receiverisneutered);
var_message.Bind(
SmiConstant(Smi::FromInt(MessageTemplate::kDetachedOperation)));
Goto(&throw_typeerror);
Bind(&throw_typeerror);
{
Node* method_arg = HeapConstant(
isolate()->factory()->NewStringFromAsciiChecked(method_name, TENURED));
Node* result = CallRuntime(Runtime::kThrowTypeError, context,
var_message.value(), method_arg);
Return(result);
}
}
TF_BUILTIN(TypedArrayPrototypeValues, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeIterationMethod<IterationKind::kValues>(
"%TypedArray%.prototype.values()");
}
TF_BUILTIN(TypedArrayPrototypeEntries, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeIterationMethod<IterationKind::kEntries>(
"%TypedArray%.prototype.entries()");
}
TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeIterationMethod<IterationKind::kKeys>(
"%TypedArray%.prototype.keys()");
}
} // namespace internal
} // namespace v8

View File

@ -4,7 +4,6 @@
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
#include "src/counters.h"
#include "src/elements.h"
#include "src/objects-inl.h"
@ -12,463 +11,9 @@
namespace v8 {
namespace internal {
class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
public:
explicit TypedArrayBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
void GenerateTypedArrayPrototypeGetter(const char* method_name,
int object_offset);
template <IterationKind kIterationKind>
void GenerateTypedArrayPrototypeIterationMethod(const char* method_name);
void LoadMapAndElementsSize(Node* const array, Variable* typed_map,
Variable* size);
void CalculateExternalPointer(Node* const backing_store,
Node* const byte_offset,
Variable* external_pointer);
void DoInitialize(Node* const holder, Node* length, Node* const maybe_buffer,
Node* const byte_offset, Node* byte_length,
Node* const initialize, Node* const context);
};
void TypedArrayBuiltinsAssembler::LoadMapAndElementsSize(Node* const array,
Variable* typed_map,
Variable* size) {
Label unreachable(this), done(this);
Label uint8_elements(this), uint8_clamped_elements(this), int8_elements(this),
uint16_elements(this), int16_elements(this), uint32_elements(this),
int32_elements(this), float32_elements(this), float64_elements(this);
Label* elements_kind_labels[] = {
&uint8_elements, &uint8_clamped_elements, &int8_elements,
&uint16_elements, &int16_elements, &uint32_elements,
&int32_elements, &float32_elements, &float64_elements};
int32_t elements_kinds[] = {
UINT8_ELEMENTS, UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
UINT16_ELEMENTS, INT16_ELEMENTS, UINT32_ELEMENTS,
INT32_ELEMENTS, FLOAT32_ELEMENTS, FLOAT64_ELEMENTS};
const size_t kTypedElementsKindCount = LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND +
1;
DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
Node* array_map = LoadMap(array);
Node* elements_kind = LoadMapElementsKind(array_map);
Switch(elements_kind, &unreachable, elements_kinds, elements_kind_labels,
kTypedElementsKindCount);
for (int i = 0; i < static_cast<int>(kTypedElementsKindCount); i++) {
Bind(elements_kind_labels[i]);
{
ElementsKind kind = static_cast<ElementsKind>(elements_kinds[i]);
ExternalArrayType type =
isolate()->factory()->GetArrayTypeFromElementsKind(kind);
Handle<Map> map(isolate()->heap()->MapForFixedTypedArray(type));
typed_map->Bind(HeapConstant(map));
size->Bind(SmiConstant(static_cast<int>(
isolate()->factory()->GetExternalArrayElementSize(type))));
Goto(&done);
}
}
Bind(&unreachable);
{ Unreachable(); }
Bind(&done);
}
// The byte_offset can be higher than Smi range, in which case to perform the
// pointer arithmetic necessary to calculate external_pointer, converting
// byte_offset to an intptr is more difficult. The max byte_offset is 8 * MaxSmi
// on the particular platform. 32 bit platforms are self-limiting, because we
// can't allocate an array bigger than our 32-bit arithmetic range anyway. 64
// bit platforms could theoretically have an offset up to 2^35 - 1, so we may
// need to convert the float heap number to an intptr.
void TypedArrayBuiltinsAssembler::CalculateExternalPointer(
Node* const backing_store, Node* const byte_offset,
Variable* external_pointer) {
Label offset_is_smi(this), offset_not_smi(this), done(this);
Branch(TaggedIsSmi(byte_offset), &offset_is_smi, &offset_not_smi);
Bind(&offset_is_smi);
{
external_pointer->Bind(IntPtrAdd(backing_store, SmiToWord(byte_offset)));
Goto(&done);
}
Bind(&offset_not_smi);
{
Node* heap_number = LoadHeapNumberValue(byte_offset);
Node* intrptr_value = ChangeFloat64ToUintPtr(heap_number);
external_pointer->Bind(IntPtrAdd(backing_store, intrptr_value));
Goto(&done);
}
Bind(&done);
}
void TypedArrayBuiltinsAssembler::DoInitialize(Node* const holder, Node* length,
Node* const maybe_buffer,
Node* const byte_offset,
Node* byte_length,
Node* const initialize,
Node* const context) {
static const int32_t fta_base_data_offset =
FixedTypedArrayBase::kDataOffset - kHeapObjectTag;
Label setup_holder(this), alloc_array_buffer(this), aligned(this),
allocate_elements(this), attach_buffer(this), done(this);
Variable fixed_typed_map(this, MachineRepresentation::kTagged);
Variable element_size(this, MachineRepresentation::kTagged);
Variable total_size(this, MachineType::PointerRepresentation());
// Make sure length is a Smi. The caller guarantees this is the case.
length = ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero);
CSA_ASSERT(this, TaggedIsSmi(length));
// byte_length can be -0, get rid of it.
byte_length =
ToInteger(context, byte_length, CodeStubAssembler::kTruncateMinusZero);
GotoIfNot(IsNull(maybe_buffer), &setup_holder);
// If the buffer is null, then we need a Smi byte_length. The caller
// guarantees this is the case, because when byte_length >
// TypedArrayMaxSizeInHeap, a buffer is allocated and passed in here.
CSA_ASSERT(this, TaggedIsSmi(byte_length));
Goto(&setup_holder);
Bind(&setup_holder);
{
LoadMapAndElementsSize(holder, &fixed_typed_map, &element_size);
// Setup the holder (JSArrayBufferView).
// - Set the length.
// - Set the byte_offset.
// - Set the byte_length.
// - Set InternalFields to 0.
StoreObjectField(holder, JSTypedArray::kLengthOffset, length);
StoreObjectField(holder, JSArrayBufferView::kByteOffsetOffset, byte_offset);
StoreObjectField(holder, JSArrayBufferView::kByteLengthOffset, byte_length);
for (int offset = JSTypedArray::kSize;
offset < JSTypedArray::kSizeWithInternalFields;
offset += kPointerSize) {
StoreObjectField(holder, offset, SmiConstant(Smi::kZero));
}
Branch(IsNull(maybe_buffer), &alloc_array_buffer, &attach_buffer);
}
Bind(&alloc_array_buffer);
{
// Allocate a new ArrayBuffer and initialize it with empty properties and
// elements.
Node* const native_context = LoadNativeContext(context);
Node* const map =
LoadContextElement(native_context, Context::ARRAY_BUFFER_MAP_INDEX);
Node* empty_fixed_array = LoadRoot(Heap::kEmptyFixedArrayRootIndex);
Node* const buffer = Allocate(JSArrayBuffer::kSizeWithInternalFields);
StoreMapNoWriteBarrier(buffer, map);
StoreObjectFieldNoWriteBarrier(buffer, JSArray::kPropertiesOffset,
empty_fixed_array);
StoreObjectFieldNoWriteBarrier(buffer, JSArray::kElementsOffset,
empty_fixed_array);
// Setup the ArrayBuffer.
// - Set BitField to 0.
// - Set IsExternal and IsNeuterable bits of BitFieldSlot.
// - Set the byte_length field to byte_length.
// - Set backing_store to null/Smi(0).
// - Set all internal fields to Smi(0).
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldSlot,
SmiConstant(Smi::kZero));
int32_t bitfield_value = (1 << JSArrayBuffer::IsExternal::kShift) |
(1 << JSArrayBuffer::IsNeuterable::kShift);
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBitFieldOffset,
Int32Constant(bitfield_value),
MachineRepresentation::kWord32);
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kByteLengthOffset,
byte_length);
StoreObjectFieldNoWriteBarrier(buffer, JSArrayBuffer::kBackingStoreOffset,
SmiConstant(Smi::kZero));
for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
int offset = JSArrayBuffer::kSize + i * kPointerSize;
StoreObjectFieldNoWriteBarrier(buffer, offset, SmiConstant(Smi::kZero));
}
StoreObjectField(holder, JSArrayBufferView::kBufferOffset, buffer);
// Check the alignment.
GotoIf(SmiEqual(SmiMod(element_size.value(), SmiConstant(kObjectAlignment)),
SmiConstant(0)),
&aligned);
// Fix alignment if needed.
DCHECK_EQ(0, FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask);
Node* aligned_header_size =
IntPtrConstant(FixedTypedArrayBase::kHeaderSize + kObjectAlignmentMask);
Node* size = IntPtrAdd(SmiToWord(byte_length), aligned_header_size);
total_size.Bind(WordAnd(size, IntPtrConstant(~kObjectAlignmentMask)));
Goto(&allocate_elements);
}
Bind(&aligned);
{
Node* header_size = IntPtrConstant(FixedTypedArrayBase::kHeaderSize);
total_size.Bind(IntPtrAdd(SmiToWord(byte_length), header_size));
Goto(&allocate_elements);
}
Bind(&allocate_elements);
{
// Allocate a FixedTypedArray and set the length, base pointer and external
// pointer.
CSA_ASSERT(this, IsRegularHeapObjectSize(total_size.value()));
Node* elements = Allocate(total_size.value());
StoreMapNoWriteBarrier(elements, fixed_typed_map.value());
StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
StoreObjectFieldNoWriteBarrier(
elements, FixedTypedArrayBase::kBasePointerOffset, elements);
StoreObjectFieldNoWriteBarrier(elements,
FixedTypedArrayBase::kExternalPointerOffset,
IntPtrConstant(fta_base_data_offset),
MachineType::PointerRepresentation());
StoreObjectField(holder, JSObject::kElementsOffset, elements);
GotoIf(IsFalse(initialize), &done);
// Initialize the backing store by filling it with 0s.
Node* backing_store = IntPtrAdd(BitcastTaggedToWord(elements),
IntPtrConstant(fta_base_data_offset));
// Call out to memset to perform initialization.
Node* memset =
ExternalConstant(ExternalReference::libc_memset_function(isolate()));
CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
MachineType::IntPtr(), MachineType::UintPtr(), memset,
backing_store, IntPtrConstant(0), SmiToWord(byte_length));
Goto(&done);
}
Bind(&attach_buffer);
{
StoreObjectField(holder, JSArrayBufferView::kBufferOffset, maybe_buffer);
Node* elements = Allocate(FixedTypedArrayBase::kHeaderSize);
StoreMapNoWriteBarrier(elements, fixed_typed_map.value());
StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset, length);
StoreObjectFieldNoWriteBarrier(
elements, FixedTypedArrayBase::kBasePointerOffset, SmiConstant(0));
Variable external_pointer(this, MachineType::PointerRepresentation());
Node* backing_store =
LoadObjectField(maybe_buffer, JSArrayBuffer::kBackingStoreOffset,
MachineType::Pointer());
CalculateExternalPointer(backing_store, byte_offset, &external_pointer);
StoreObjectFieldNoWriteBarrier(
elements, FixedTypedArrayBase::kExternalPointerOffset,
external_pointer.value(), MachineType::PointerRepresentation());
StoreObjectField(holder, JSObject::kElementsOffset, elements);
Goto(&done);
}
Bind(&done);
Return(UndefinedConstant());
}
TF_BUILTIN(TypedArrayInitialize, TypedArrayBuiltinsAssembler) {
Node* const holder = Parameter(1);
Node* length = Parameter(2);
Node* const maybe_buffer = Parameter(3);
Node* const byte_offset = Parameter(4);
Node* byte_length = Parameter(5);
Node* const initialize = Parameter(6);
Node* const context = Parameter(9);
DoInitialize(holder, length, maybe_buffer, byte_offset, byte_length,
initialize, context);
}
// -----------------------------------------------------------------------------
// ES6 section 22.2 TypedArray Objects
// ES6 section 22.2.4.2 TypedArray ( length )
TF_BUILTIN(TypedArrayConstructByLength, TypedArrayBuiltinsAssembler) {
// We know that holder cannot be an object if this builtin was called.
Node* holder = Parameter(1);
Node* length = Parameter(2);
Node* element_size = Parameter(3);
Node* context = Parameter(6);
Variable maybe_buffer(this, MachineRepresentation::kTagged);
maybe_buffer.Bind(NullConstant());
Node* byte_offset = SmiConstant(0);
Node* initialize = BooleanConstant(true);
Label external_buffer(this), call_init(this), invalid_length(this);
length = ToInteger(context, length, CodeStubAssembler::kTruncateMinusZero);
// The maximum length of a TypedArray is MaxSmi().
// Note: this is not per spec, but rather a constraint of our current
// representation (which uses smi's).
GotoIf(TaggedIsNotSmi(length), &invalid_length);
GotoIf(SmiLessThan(length, SmiConstant(0)), &invalid_length);
// For byte_length < typed_array_max_size_in_heap, we allocate the buffer on
// the heap. Otherwise we allocate it externally and attach it.
Node* byte_length = SmiMul(length, element_size);
GotoIf(TaggedIsNotSmi(byte_length), &external_buffer);
Branch(SmiLessThanOrEqual(byte_length,
SmiConstant(FLAG_typed_array_max_size_in_heap)),
&call_init, &external_buffer);
Bind(&external_buffer);
{
Node* const buffer_constructor = LoadContextElement(
LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX);
maybe_buffer.Bind(ConstructJS(CodeFactory::Construct(isolate()), context,
buffer_constructor, byte_length));
Goto(&call_init);
}
Bind(&call_init);
{
DoInitialize(holder, length, maybe_buffer.value(), byte_offset, byte_length,
initialize, context);
}
Bind(&invalid_length);
{
CallRuntime(Runtime::kThrowRangeError, context,
SmiConstant(MessageTemplate::kInvalidTypedArrayLength));
Unreachable();
}
}
// ES6 section 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
TF_BUILTIN(TypedArrayConstructByArrayBuffer, TypedArrayBuiltinsAssembler) {
Node* const holder = Parameter(1);
Node* const buffer = Parameter(2);
Node* byte_offset = Parameter(3);
Node* const length = Parameter(4);
Node* const element_size = Parameter(5);
CSA_ASSERT(this, TaggedIsSmi(element_size));
Node* const context = Parameter(8);
Node* const initialize = BooleanConstant(true);
Variable new_byte_length(this, MachineRepresentation::kTagged,
SmiConstant(0));
Label start_offset_error(this), byte_length_error(this),
invalid_offset_error(this);
Label call_init(this), invalid_length(this), length_undefined(this),
length_defined(this);
Callable add = CodeFactory::Add(isolate());
Callable div = CodeFactory::Divide(isolate());
Callable equal = CodeFactory::Equal(isolate());
Callable greater_than = CodeFactory::GreaterThan(isolate());
Callable less_than = CodeFactory::LessThan(isolate());
Callable mod = CodeFactory::Modulus(isolate());
Callable sub = CodeFactory::Subtract(isolate());
byte_offset =
ToInteger(context, byte_offset, CodeStubAssembler::kTruncateMinusZero);
GotoIf(IsTrue(CallStub(less_than, context, byte_offset, SmiConstant(0))),
&invalid_length);
Node* remainder = CallStub(mod, context, byte_offset, element_size);
// Remainder can be a heap number.
GotoIf(IsFalse(CallStub(equal, context, remainder, SmiConstant(0))),
&start_offset_error);
// TODO(petermarshall): Throw on detached typedArray.
Branch(IsUndefined(length), &length_undefined, &length_defined);
Bind(&length_undefined);
{
Node* buffer_byte_length =
LoadObjectField(buffer, JSArrayBuffer::kByteLengthOffset);
Node* remainder = CallStub(mod, context, buffer_byte_length, element_size);
// Remainder can be a heap number.
GotoIf(IsFalse(CallStub(equal, context, remainder, SmiConstant(0))),
&byte_length_error);
new_byte_length.Bind(
CallStub(sub, context, buffer_byte_length, byte_offset));
Branch(IsTrue(CallStub(less_than, context, new_byte_length.value(),
SmiConstant(0))),
&invalid_offset_error, &call_init);
}
Bind(&length_defined);
{
Node* new_length = ToSmiIndex(length, context, &invalid_length);
new_byte_length.Bind(SmiMul(new_length, element_size));
// Reading the byte length must come after the ToIndex operation, which
// could cause the buffer to become detached.
Node* buffer_byte_length =
LoadObjectField(buffer, JSArrayBuffer::kByteLengthOffset);
Node* end = CallStub(add, context, byte_offset, new_byte_length.value());
Branch(IsTrue(CallStub(greater_than, context, end, buffer_byte_length)),
&invalid_length, &call_init);
}
Bind(&call_init);
{
Node* new_length =
CallStub(div, context, new_byte_length.value(), element_size);
// Force the result into a Smi, or throw a range error if it doesn't fit.
new_length = ToSmiIndex(new_length, context, &invalid_length);
DoInitialize(holder, new_length, buffer, byte_offset,
new_byte_length.value(), initialize, context);
}
Bind(&invalid_offset_error);
{
CallRuntime(Runtime::kThrowRangeError, context,
SmiConstant(MessageTemplate::kInvalidOffset), byte_offset);
Unreachable();
}
Bind(&start_offset_error);
{
Node* holder_map = LoadMap(holder);
Node* problem_string = HeapConstant(
factory()->NewStringFromAsciiChecked("start offset", TENURED));
CallRuntime(Runtime::kThrowInvalidTypedArrayAlignment, context, holder_map,
problem_string);
Unreachable();
}
Bind(&byte_length_error);
{
Node* holder_map = LoadMap(holder);
Node* problem_string = HeapConstant(
factory()->NewStringFromAsciiChecked("byte length", TENURED));
CallRuntime(Runtime::kThrowInvalidTypedArrayAlignment, context, holder_map,
problem_string);
Unreachable();
}
Bind(&invalid_length);
{
CallRuntime(Runtime::kThrowRangeError, context,
SmiConstant(MessageTemplate::kInvalidTypedArrayLength));
Unreachable();
}
}
// ES6 section 22.2.3.1 get %TypedArray%.prototype.buffer
BUILTIN(TypedArrayPrototypeBuffer) {
HandleScope scope(isolate);
@ -476,119 +21,6 @@ BUILTIN(TypedArrayPrototypeBuffer) {
return *typed_array->GetBuffer();
}
void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeGetter(
const char* method_name, int object_offset) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
// Check if the {receiver} is actually a JSTypedArray.
Label receiver_is_incompatible(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &receiver_is_incompatible);
GotoIfNot(HasInstanceType(receiver, JS_TYPED_ARRAY_TYPE),
&receiver_is_incompatible);
// Check if the {receiver}'s JSArrayBuffer was neutered.
Node* receiver_buffer =
LoadObjectField(receiver, JSTypedArray::kBufferOffset);
Label if_receiverisneutered(this, Label::kDeferred);
GotoIf(IsDetachedBuffer(receiver_buffer), &if_receiverisneutered);
Return(LoadObjectField(receiver, object_offset));
Bind(&if_receiverisneutered);
{
// The {receiver}s buffer was neutered, default to zero.
Return(SmiConstant(0));
}
Bind(&receiver_is_incompatible);
{
// The {receiver} is not a valid JSTypedArray.
CallRuntime(Runtime::kThrowIncompatibleMethodReceiver, context,
HeapConstant(
factory()->NewStringFromAsciiChecked(method_name, TENURED)),
receiver);
Unreachable();
}
}
// ES6 section 22.2.3.2 get %TypedArray%.prototype.byteLength
TF_BUILTIN(TypedArrayPrototypeByteLength, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeGetter("get TypedArray.prototype.byteLength",
JSTypedArray::kByteLengthOffset);
}
// ES6 section 22.2.3.3 get %TypedArray%.prototype.byteOffset
TF_BUILTIN(TypedArrayPrototypeByteOffset, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeGetter("get TypedArray.prototype.byteOffset",
JSTypedArray::kByteOffsetOffset);
}
// ES6 section 22.2.3.18 get %TypedArray%.prototype.length
TF_BUILTIN(TypedArrayPrototypeLength, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeGetter("get TypedArray.prototype.length",
JSTypedArray::kLengthOffset);
}
template <IterationKind kIterationKind>
void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeIterationMethod(
const char* method_name) {
Node* receiver = Parameter(0);
Node* context = Parameter(3);
Label throw_bad_receiver(this, Label::kDeferred);
Label throw_typeerror(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &throw_bad_receiver);
Node* map = LoadMap(receiver);
Node* instance_type = LoadMapInstanceType(map);
GotoIf(Word32NotEqual(instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
&throw_bad_receiver);
// Check if the {receiver}'s JSArrayBuffer was neutered.
Node* receiver_buffer =
LoadObjectField(receiver, JSTypedArray::kBufferOffset);
Label if_receiverisneutered(this, Label::kDeferred);
GotoIf(IsDetachedBuffer(receiver_buffer), &if_receiverisneutered);
Return(CreateArrayIterator(receiver, map, instance_type, context,
kIterationKind));
Variable var_message(this, MachineRepresentation::kTagged);
Bind(&throw_bad_receiver);
var_message.Bind(SmiConstant(MessageTemplate::kNotTypedArray));
Goto(&throw_typeerror);
Bind(&if_receiverisneutered);
var_message.Bind(
SmiConstant(Smi::FromInt(MessageTemplate::kDetachedOperation)));
Goto(&throw_typeerror);
Bind(&throw_typeerror);
{
Node* method_arg = HeapConstant(
isolate()->factory()->NewStringFromAsciiChecked(method_name, TENURED));
Node* result = CallRuntime(Runtime::kThrowTypeError, context,
var_message.value(), method_arg);
Return(result);
}
}
TF_BUILTIN(TypedArrayPrototypeValues, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeIterationMethod<IterationKind::kValues>(
"%TypedArray%.prototype.values()");
}
TF_BUILTIN(TypedArrayPrototypeEntries, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeIterationMethod<IterationKind::kEntries>(
"%TypedArray%.prototype.entries()");
}
TF_BUILTIN(TypedArrayPrototypeKeys, TypedArrayBuiltinsAssembler) {
GenerateTypedArrayPrototypeIterationMethod<IterationKind::kKeys>(
"%TypedArray%.prototype.keys()");
}
namespace {
int64_t CapRelativeIndex(Handle<Object> num, int64_t minimum, int64_t maximum) {

View File

@ -0,0 +1,43 @@
// Copyright 2017 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.
#ifndef V8_BUILTINS_BUILTINS_UTILS_GEN_H_
#define V8_BUILTINS_BUILTINS_UTILS_GEN_H_
namespace v8 {
namespace internal {
namespace compiler {
class CodeAssemblerState;
} // namespace compiler
// ----------------------------------------------------------------------------
// Support macro for defining builtins with Turbofan.
// ----------------------------------------------------------------------------
//
// A builtin function is defined by writing:
//
// TF_BUILTIN(name, code_assember_base_class) {
// ...
// }
//
// In the body of the builtin function the arguments can be accessed
// as "Parameter(n)".
#define TF_BUILTIN(Name, AssemblerBase) \
class Name##Assembler : public AssemblerBase { \
public: \
explicit Name##Assembler(compiler::CodeAssemblerState* state) \
: AssemblerBase(state) {} \
void Generate##Name##Impl(); \
}; \
void Builtins::Generate_##Name(compiler::CodeAssemblerState* state) { \
Name##Assembler assembler(state); \
assembler.Generate##Name##Impl(); \
} \
void Name##Assembler::Generate##Name##Impl()
} // namespace internal
} // namespace v8
#endif // V8_BUILTINS_BUILTINS_UTILS_GEN_H_

View File

@ -14,10 +14,6 @@
namespace v8 {
namespace internal {
namespace compiler {
class CodeAssemblerState;
}
// Arguments object passed to C++ builtins.
class BuiltinArguments : public Arguments {
public:
@ -106,31 +102,6 @@ class BuiltinArguments : public Arguments {
MUST_USE_RESULT static Object* Builtin_Impl_##name(BuiltinArguments args, \
Isolate* isolate)
// ----------------------------------------------------------------------------
// Support macro for defining builtins with Turbofan.
// ----------------------------------------------------------------------------
//
// A builtin function is defined by writing:
//
// TF_BUILTIN(name, code_assember_base_class) {
// ...
// }
//
// In the body of the builtin function the arguments can be accessed
// as "Parameter(n)".
#define TF_BUILTIN(Name, AssemblerBase) \
class Name##Assembler : public AssemblerBase { \
public: \
explicit Name##Assembler(compiler::CodeAssemblerState* state) \
: AssemblerBase(state) {} \
void Generate##Name##Impl(); \
}; \
void Builtins::Generate_##Name(compiler::CodeAssemblerState* state) { \
Name##Assembler assembler(state); \
assembler.Generate##Name##Impl(); \
} \
void Name##Assembler::Generate##Name##Impl()
// ----------------------------------------------------------------------------
#define CHECK_RECEIVER(Type, name, method) \

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/code-stub-assembler.h"
#include "src/objects-inl.h"
#include "src/wasm/wasm-opcodes.h"

View File

@ -203,6 +203,77 @@ const char* Builtins::Lookup(byte* pc) {
return NULL;
}
Handle<Code> Builtins::NewFunctionContext(ScopeType scope_type) {
switch (scope_type) {
case ScopeType::EVAL_SCOPE:
return FastNewFunctionContextEval();
case ScopeType::FUNCTION_SCOPE:
return FastNewFunctionContextFunction();
default:
UNREACHABLE();
}
return Handle<Code>::null();
}
Handle<Code> Builtins::NewCloneShallowArray(
AllocationSiteMode allocation_mode) {
switch (allocation_mode) {
case TRACK_ALLOCATION_SITE:
return FastCloneShallowArrayTrack();
case DONT_TRACK_ALLOCATION_SITE:
return FastCloneShallowArrayDontTrack();
default:
UNREACHABLE();
}
return Handle<Code>::null();
}
Handle<Code> Builtins::NewCloneShallowObject(int length) {
switch (length) {
case 0:
return FastCloneShallowObject0();
case 1:
return FastCloneShallowObject1();
case 2:
return FastCloneShallowObject2();
case 3:
return FastCloneShallowObject3();
case 4:
return FastCloneShallowObject4();
case 5:
return FastCloneShallowObject5();
case 6:
return FastCloneShallowObject6();
default:
UNREACHABLE();
}
return Handle<Code>::null();
}
Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) {
switch (hint) {
case ToPrimitiveHint::kDefault:
return NonPrimitiveToPrimitive_Default();
case ToPrimitiveHint::kNumber:
return NonPrimitiveToPrimitive_Number();
case ToPrimitiveHint::kString:
return NonPrimitiveToPrimitive_String();
}
UNREACHABLE();
return Handle<Code>::null();
}
Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) {
switch (hint) {
case OrdinaryToPrimitiveHint::kNumber:
return OrdinaryToPrimitive_Number();
case OrdinaryToPrimitiveHint::kString:
return OrdinaryToPrimitive_String();
}
UNREACHABLE();
return Handle<Code>::null();
}
// static
const char* Builtins::name(int index) {
switch (index) {

View File

@ -471,49 +471,64 @@
'bootstrapper.cc',
'bootstrapper.h',
'builtins/builtins-api.cc',
'builtins/builtins-arguments.cc',
'builtins/builtins-arguments-gen.cc',
'builtins/builtins-arguments.h',
'builtins/builtins-arraybuffer.cc',
'builtins/builtins-array.cc',
'builtins/builtins-async-iterator.cc',
'builtins/builtins-async-function.cc',
'builtins/builtins-async.cc',
'builtins/builtins-array-gen.cc',
'builtins/builtins-async-function-gen.cc',
'builtins/builtins-async-iterator-gen.cc',
'builtins/builtins-async-gen.cc',
'builtins/builtins-async.h',
'builtins/builtins-boolean.cc',
'builtins/builtins-boolean-gen.cc',
'builtins/builtins-call.cc',
'builtins/builtins-callsite.cc',
'builtins/builtins-conversion.cc',
'builtins/builtins-constructor.cc',
'builtins/builtins-constructor-gen.cc',
'builtins/builtins-constructor.h',
'builtins/builtins-conversion-gen.cc',
'builtins/builtins-dataview.cc',
'builtins/builtins-date.cc',
'builtins/builtins-date-gen.cc',
'builtins/builtins-debug.cc',
'builtins/builtins-error.cc',
'builtins/builtins-forin.cc',
'builtins/builtins-forin-gen.cc',
'builtins/builtins-forin.h',
'builtins/builtins-function.cc',
'builtins/builtins-generator.cc',
'builtins/builtins-function-gen.cc',
'builtins/builtins-generator-gen.cc',
'builtins/builtins-global.cc',
'builtins/builtins-handler.cc',
'builtins/builtins-ic.cc',
'builtins/builtins-global-gen.cc',
'builtins/builtins-handler-gen.cc',
'builtins/builtins-ic-gen.cc',
'builtins/builtins-internal.cc',
'builtins/builtins-internal-gen.cc',
'builtins/builtins-interpreter.cc',
'builtins/builtins-json.cc',
'builtins/builtins-math.cc',
'builtins/builtins-math-gen.cc',
'builtins/builtins-number.cc',
'builtins/builtins-number-gen.cc',
'builtins/builtins-object.cc',
'builtins/builtins-promise.cc',
'builtins/builtins-object-gen.cc',
'builtins/builtins-promise-gen.cc',
'builtins/builtins-promise.h',
'builtins/builtins-proxy.cc',
'builtins/builtins-reflect.cc',
'builtins/builtins-regexp.cc',
'builtins/builtins-regexp.h',
'builtins/builtins-regexp-gen.cc',
'builtins/builtins-regexp-gen.h',
'builtins/builtins-sharedarraybuffer.cc',
'builtins/builtins-sharedarraybuffer-gen.cc',
'builtins/builtins-string.cc',
'builtins/builtins-string-gen.cc',
'builtins/builtins-symbol.cc',
'builtins/builtins-symbol-gen.cc',
'builtins/builtins-typedarray.cc',
'builtins/builtins-typedarray-gen.cc',
'builtins/builtins-utils.h',
'builtins/builtins-wasm.cc',
'builtins/builtins-utils-gen.h',
'builtins/builtins-wasm-gen.cc',
'builtins/builtins.cc',
'builtins/builtins.h',
'cached-powers.cc',