111
107
// formal parameter count expected by the function.
113
109
// The live registers are:
114
// o rdi: the JS function object being called (ie, ourselves)
110
// o rdi: the JS function object being called (i.e. ourselves)
115
111
// o rsi: our context
116
112
// o rbp: our caller's frame pointer
117
113
// o rsp: stack pointer (pointing to return address)
119
115
// The function builds a JS frame. Please see JavaScriptFrameConstants in
120
116
// frames-x64.h for its layout.
121
void FullCodeGenerator::Generate(CompilationInfo* info) {
122
ASSERT(info_ == NULL);
124
scope_ = info->scope();
117
void FullCodeGenerator::Generate() {
118
CompilationInfo* info = info_;
120
isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
121
profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell(
122
Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget)));
125
123
SetFunctionPosition(function());
126
124
Comment cmnt(masm_, "[ function compiled by full code generator");
126
ProfileEntryHookStub::MaybeCallEntryHook(masm_);
129
129
if (strlen(FLAG_stop_at) > 0 &&
130
130
info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
226
232
// function, receiver address, parameter count.
227
233
// The stub will rewrite receiver and parameter count if the previous
228
234
// stack frame was an arguments adapter frame.
229
ArgumentsAccessStub stub(
230
is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT
231
: ArgumentsAccessStub::NEW_NON_STRICT_SLOW);
235
ArgumentsAccessStub::Type type;
236
if (!is_classic_mode()) {
237
type = ArgumentsAccessStub::NEW_STRICT;
238
} else if (function()->has_duplicate_parameters()) {
239
type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
241
type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
243
ArgumentsAccessStub stub(type);
232
244
__ CallStub(&stub);
234
246
SetVar(arguments, rax, rbx, rdx);
245
257
scope()->VisitIllegalRedeclaration(this);
248
PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
260
PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
249
261
{ Comment cmnt(masm_, "[ Declarations");
250
262
// For named function expressions, declare the function name as a
252
264
if (scope()->is_function_scope() && scope()->function() != NULL) {
254
EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored);
265
VariableDeclaration* function = scope()->function();
266
ASSERT(function->proxy()->var()->mode() == CONST ||
267
function->proxy()->var()->mode() == CONST_HARMONY);
268
ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
269
VisitVariableDeclaration(function);
256
271
VisitDeclarations(scope()->declarations());
259
274
{ Comment cmnt(masm_, "[ Stack check");
260
PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
275
PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
262
277
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
263
278
__ j(above_equal, &ok, Label::kNear);
290
void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
305
void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
306
__ movq(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
307
__ SmiAddConstant(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
308
Smi::FromInt(-delta));
312
void FullCodeGenerator::EmitProfilingCounterReset() {
313
int reset_value = FLAG_interrupt_budget;
314
if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) {
315
// Self-optimization is a one-off thing; if it fails, don't try again.
316
reset_value = Smi::kMaxValue;
318
__ movq(rbx, profiling_counter_, RelocInfo::EMBEDDED_OBJECT);
319
__ movq(kScratchRegister,
320
reinterpret_cast<uint64_t>(Smi::FromInt(reset_value)),
322
__ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
327
void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt,
328
Label* back_edge_target) {
291
329
Comment cmnt(masm_, "[ Stack check");
293
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
294
__ j(above_equal, &ok, Label::kNear);
332
if (FLAG_count_based_interrupts) {
334
if (FLAG_weighted_back_edges) {
335
ASSERT(back_edge_target->is_bound());
336
int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
337
weight = Min(kMaxBackEdgeWeight,
338
Max(1, distance / kBackEdgeDistanceUnit));
340
EmitProfilingCounterDecrement(weight);
341
__ j(positive, &ok, Label::kNear);
345
__ CompareRoot(rsp, Heap::kStackLimitRootIndex);
346
__ j(above_equal, &ok, Label::kNear);
297
351
// Record a mapping of this PC offset to the OSR id. This is used to find
298
352
// the AST id from the unoptimized code in order to use it as a key into
299
353
// the deoptimization input data found in the optimized code.
326
384
__ CallRuntime(Runtime::kTraceExit, 1);
386
if (FLAG_interrupt_at_exit || FLAG_self_optimization) {
387
// Pretend that the exit is a backwards jump to the entry.
389
if (info_->ShouldSelfOptimize()) {
390
weight = FLAG_interrupt_budget / FLAG_self_opt_count;
391
} else if (FLAG_weighted_back_edges) {
392
int distance = masm_->pc_offset();
393
weight = Min(kMaxBackEdgeWeight,
394
Max(1, distance / kBackEdgeDistanceUnit));
396
EmitProfilingCounterDecrement(weight);
398
__ j(positive, &ok, Label::kNear);
400
if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) {
401
__ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
402
__ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1);
408
EmitProfilingCounterReset();
329
412
// Add a label for checking the size of the code used for returning.
330
413
Label check_exit_codesize;
675
void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy,
677
FunctionLiteral* function,
761
void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
762
// The variable in the declaration always resides in the current function
764
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
765
if (generate_debug_code_) {
766
// Check that we're not inside a with or catch context.
767
__ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
768
__ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
769
__ Check(not_equal, "Declaration in with context.");
770
__ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
771
__ Check(not_equal, "Declaration in catch context.");
776
void FullCodeGenerator::VisitVariableDeclaration(
777
VariableDeclaration* declaration) {
679
778
// If it was not possible to allocate the variable at compile time, we
680
779
// need to "declare" it at runtime to make sure it actually exists in the
681
780
// local context.
781
VariableProxy* proxy = declaration->proxy();
782
VariableMode mode = declaration->mode();
682
783
Variable* variable = proxy->var();
784
bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
683
785
switch (variable->location()) {
684
786
case Variable::UNALLOCATED:
787
globals_->Add(variable->name(), zone());
788
globals_->Add(variable->binding_needs_init()
789
? isolate()->factory()->the_hole_value()
790
: isolate()->factory()->undefined_value(),
688
794
case Variable::PARAMETER:
689
795
case Variable::LOCAL:
690
if (function != NULL) {
691
Comment cmnt(masm_, "[ Declaration");
692
VisitForAccumulatorValue(function);
693
__ movq(StackOperand(variable), result_register());
694
} else if (mode == Variable::CONST || mode == Variable::LET) {
695
Comment cmnt(masm_, "[ Declaration");
797
Comment cmnt(masm_, "[ VariableDeclaration");
696
798
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
697
799
__ movq(StackOperand(variable), kScratchRegister);
701
803
case Variable::CONTEXT:
702
// The variable in the decl always resides in the current function
704
ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
705
if (FLAG_debug_code) {
706
// Check that we're not inside a with or catch context.
707
__ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset));
708
__ CompareRoot(rbx, Heap::kWithContextMapRootIndex);
709
__ Check(not_equal, "Declaration in with context.");
710
__ CompareRoot(rbx, Heap::kCatchContextMapRootIndex);
711
__ Check(not_equal, "Declaration in catch context.");
713
if (function != NULL) {
714
Comment cmnt(masm_, "[ Declaration");
715
VisitForAccumulatorValue(function);
716
__ movq(ContextOperand(rsi, variable->index()), result_register());
717
int offset = Context::SlotOffset(variable->index());
719
__ RecordWrite(rbx, offset, result_register(), rcx);
720
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
721
} else if (mode == Variable::CONST || mode == Variable::LET) {
722
Comment cmnt(masm_, "[ Declaration");
805
Comment cmnt(masm_, "[ VariableDeclaration");
806
EmitDebugCheckDeclarationContext(variable);
723
807
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
724
808
__ movq(ContextOperand(rsi, variable->index()), kScratchRegister);
725
809
// No write barrier since the hole value is in old space.
730
814
case Variable::LOOKUP: {
731
Comment cmnt(masm_, "[ Declaration");
815
Comment cmnt(masm_, "[ VariableDeclaration");
733
817
__ Push(variable->name());
734
// Declaration nodes are always introduced in one of three modes.
735
ASSERT(mode == Variable::VAR ||
736
mode == Variable::CONST ||
737
mode == Variable::LET);
738
PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
818
// Declaration nodes are always introduced in one of four modes.
819
ASSERT(IsDeclaredVariableMode(mode));
820
PropertyAttributes attr =
821
IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
739
822
__ Push(Smi::FromInt(attr));
740
823
// Push initial value, if any.
741
824
// Note: For variables we must not push an initial value (such as
742
825
// 'undefined') because we may have a (legal) redeclaration and we
743
826
// must not destroy the current value.
744
if (function != NULL) {
745
VisitForStackValue(function);
746
} else if (mode == Variable::CONST || mode == Variable::LET) {
747
828
__ PushRoot(Heap::kTheHoleValueRootIndex);
749
830
__ Push(Smi::FromInt(0)); // Indicates no initial value.
758
void FullCodeGenerator::VisitDeclaration(Declaration* decl) { }
839
void FullCodeGenerator::VisitFunctionDeclaration(
840
FunctionDeclaration* declaration) {
841
VariableProxy* proxy = declaration->proxy();
842
Variable* variable = proxy->var();
843
switch (variable->location()) {
844
case Variable::UNALLOCATED: {
845
globals_->Add(variable->name(), zone());
846
Handle<SharedFunctionInfo> function =
847
Compiler::BuildFunctionInfo(declaration->fun(), script());
848
// Check for stack-overflow exception.
849
if (function.is_null()) return SetStackOverflow();
850
globals_->Add(function, zone());
854
case Variable::PARAMETER:
855
case Variable::LOCAL: {
856
Comment cmnt(masm_, "[ FunctionDeclaration");
857
VisitForAccumulatorValue(declaration->fun());
858
__ movq(StackOperand(variable), result_register());
862
case Variable::CONTEXT: {
863
Comment cmnt(masm_, "[ FunctionDeclaration");
864
EmitDebugCheckDeclarationContext(variable);
865
VisitForAccumulatorValue(declaration->fun());
866
__ movq(ContextOperand(rsi, variable->index()), result_register());
867
int offset = Context::SlotOffset(variable->index());
868
// We know that we have written a function, which is not a smi.
869
__ RecordWriteContextSlot(rsi,
876
PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
880
case Variable::LOOKUP: {
881
Comment cmnt(masm_, "[ FunctionDeclaration");
883
__ Push(variable->name());
884
__ Push(Smi::FromInt(NONE));
885
VisitForStackValue(declaration->fun());
886
__ CallRuntime(Runtime::kDeclareContextSlot, 4);
893
void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
894
VariableProxy* proxy = declaration->proxy();
895
Variable* variable = proxy->var();
896
Handle<JSModule> instance = declaration->module()->interface()->Instance();
897
ASSERT(!instance.is_null());
899
switch (variable->location()) {
900
case Variable::UNALLOCATED: {
901
Comment cmnt(masm_, "[ ModuleDeclaration");
902
globals_->Add(variable->name(), zone());
903
globals_->Add(instance, zone());
904
Visit(declaration->module());
908
case Variable::CONTEXT: {
909
Comment cmnt(masm_, "[ ModuleDeclaration");
910
EmitDebugCheckDeclarationContext(variable);
911
__ Move(ContextOperand(rsi, variable->index()), instance);
912
Visit(declaration->module());
916
case Variable::PARAMETER:
917
case Variable::LOCAL:
918
case Variable::LOOKUP:
924
void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
925
VariableProxy* proxy = declaration->proxy();
926
Variable* variable = proxy->var();
927
switch (variable->location()) {
928
case Variable::UNALLOCATED:
932
case Variable::CONTEXT: {
933
Comment cmnt(masm_, "[ ImportDeclaration");
934
EmitDebugCheckDeclarationContext(variable);
939
case Variable::PARAMETER:
940
case Variable::LOCAL:
941
case Variable::LOOKUP:
947
void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
761
952
void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
882
1075
__ bind(&done_convert);
1078
// Check for proxies.
1080
STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1081
__ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
1082
__ j(below_equal, &call_runtime);
885
1084
// Check cache validity in generated code. This is a fast case for
886
1085
// the JSObject::IsSimpleEnum cache validity checks. If we cannot
887
1086
// guarantee cache validity, call the runtime system to check cache
888
1087
// validity or get the property names in a fixed array.
889
Label next, call_runtime;
890
Register empty_fixed_array_value = r8;
891
__ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
892
Register empty_descriptor_array_value = r9;
893
__ LoadRoot(empty_descriptor_array_value,
894
Heap::kEmptyDescriptorArrayRootIndex);
898
// Check that there are no elements. Register rcx contains the
899
// current JS object we've reached through the prototype chain.
900
__ cmpq(empty_fixed_array_value,
901
FieldOperand(rcx, JSObject::kElementsOffset));
902
__ j(not_equal, &call_runtime);
904
// Check that instance descriptors are not empty so that we can
905
// check for an enum cache. Leave the map in rbx for the subsequent
907
__ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
908
__ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOrBitField3Offset));
909
__ JumpIfSmi(rdx, &call_runtime);
911
// Check that there is an enum cache in the non-empty instance
912
// descriptors (rdx). This is the case if the next enumeration
913
// index field does not contain a smi.
914
__ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset));
915
__ JumpIfSmi(rdx, &call_runtime);
917
// For all objects but the receiver, check that the cache is empty.
918
Label check_prototype;
920
__ j(equal, &check_prototype, Label::kNear);
921
__ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset));
922
__ cmpq(rdx, empty_fixed_array_value);
923
__ j(not_equal, &call_runtime);
925
// Load the prototype from the map and loop if non-null.
926
__ bind(&check_prototype);
927
__ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
928
__ cmpq(rcx, null_value);
929
__ j(not_equal, &next);
1088
__ CheckEnumCache(null_value, &call_runtime);
931
1090
// The enum cache is valid. Load the map of the object being
932
1091
// iterated over and use the cache for the iteration.
945
1104
Label fixed_array;
946
1105
__ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
947
1106
Heap::kMetaMapRootIndex);
948
__ j(not_equal, &fixed_array, Label::kNear);
1107
__ j(not_equal, &fixed_array);
950
1109
// We got a map in register rax. Get the enumeration cache from it.
951
1110
__ bind(&use_cache);
1112
Label no_descriptors;
1114
__ EnumLength(rdx, rax);
1115
__ Cmp(rdx, Smi::FromInt(0));
1116
__ j(equal, &no_descriptors);
952
1118
__ LoadInstanceDescriptors(rax, rcx);
953
__ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
954
__ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1119
__ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheOffset));
1120
__ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
956
// Setup the four remaining stack slots.
1122
// Set up the four remaining stack slots.
957
1123
__ push(rax); // Map.
958
__ push(rdx); // Enumeration cache.
959
__ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset));
960
__ push(rax); // Enumeration cache length (as smi).
1124
__ push(rcx); // Enumeration cache.
1125
__ push(rdx); // Number of valid entries for the map in the enum cache.
961
1126
__ Push(Smi::FromInt(0)); // Initial index.
1129
__ bind(&no_descriptors);
1130
__ addq(rsp, Immediate(kPointerSize));
964
1133
// We got a fixed array in register rax. Iterate through that.
965
1135
__ bind(&fixed_array);
966
__ Push(Smi::FromInt(0)); // Map (0) - force slow check.
1137
Handle<JSGlobalPropertyCell> cell =
1138
isolate()->factory()->NewJSGlobalPropertyCell(
1140
Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker)));
1141
RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell);
1142
__ LoadHeapObject(rbx, cell);
1143
__ Move(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset),
1144
Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker));
1146
__ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check
1147
__ movq(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object
1148
STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1149
__ CmpObjectType(rcx, LAST_JS_PROXY_TYPE, rcx);
1150
__ j(above, &non_proxy);
1151
__ Move(rbx, Smi::FromInt(0)); // Zero indicates proxy
1152
__ bind(&non_proxy);
1153
__ push(rbx); // Smi
1154
__ push(rax); // Array
968
1155
__ movq(rax, FieldOperand(rax, FixedArray::kLengthOffset));
969
1156
__ push(rax); // Fixed array length (as smi).
970
1157
__ Push(Smi::FromInt(0)); // Initial index.
972
1159
// Generate code for doing the condition check.
1160
PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
974
1162
__ movq(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index.
975
1163
__ cmpq(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length.
984
1172
FixedArray::kHeaderSize));
986
// Get the expected map from the stack or a zero map in the
1174
// Get the expected map from the stack or a smi in the
987
1175
// permanent slow case into register rdx.
988
1176
__ movq(rdx, Operand(rsp, 3 * kPointerSize));
990
1178
// Check if the expected map still matches that of the enumerable.
991
// If not, we have to filter the key.
1179
// If not, we may have to filter the key.
992
1180
Label update_each;
993
1181
__ movq(rcx, Operand(rsp, 4 * kPointerSize));
994
1182
__ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset));
995
1183
__ j(equal, &update_each, Label::kNear);
1185
// For proxies, no filtering is done.
1186
// TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1187
__ Cmp(rdx, Smi::FromInt(0));
1188
__ j(equal, &update_each, Label::kNear);
997
1190
// Convert the entry to a string or null if it isn't a property
998
1191
// anymore. If the property has been removed while iterating, we
999
1192
// just skip it.
1168
1362
// introducing variables. In those cases, we do not want to
1169
1363
// perform a runtime call for all variables in the scope
1170
1364
// containing the eval.
1171
if (var->mode() == Variable::DYNAMIC_GLOBAL) {
1365
if (var->mode() == DYNAMIC_GLOBAL) {
1172
1366
EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
1174
} else if (var->mode() == Variable::DYNAMIC_LOCAL) {
1368
} else if (var->mode() == DYNAMIC_LOCAL) {
1175
1369
Variable* local = var->local_if_not_shadowed();
1176
1370
__ movq(rax, ContextSlotOperandCheckExtensions(local, slow));
1177
if (local->mode() == Variable::CONST) {
1371
if (local->mode() == CONST ||
1372
local->mode() == CONST_HARMONY ||
1373
local->mode() == LET) {
1178
1374
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1179
1375
__ j(not_equal, done);
1180
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1376
if (local->mode() == CONST) {
1377
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1378
} else { // LET || CONST_HARMONY
1379
__ Push(var->name());
1380
__ CallRuntime(Runtime::kThrowReferenceError, 1);
1208
1409
case Variable::LOCAL:
1209
1410
case Variable::CONTEXT: {
1210
1411
Comment cmnt(masm_, var->IsContextSlot() ? "Context slot" : "Stack slot");
1211
if (var->mode() != Variable::LET && var->mode() != Variable::CONST) {
1212
context()->Plug(var);
1214
// Let and const need a read barrier.
1217
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1218
__ j(not_equal, &done, Label::kNear);
1219
if (var->mode() == Variable::LET) {
1220
__ Push(var->name());
1221
__ CallRuntime(Runtime::kThrowReferenceError, 1);
1222
} else { // Variable::CONST
1223
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1226
context()->Plug(rax);
1412
if (var->binding_needs_init()) {
1413
// var->scope() may be NULL when the proxy is located in eval code and
1414
// refers to a potential outside binding. Currently those bindings are
1415
// always looked up dynamically, i.e. in that case
1416
// var->location() == LOOKUP.
1418
ASSERT(var->scope() != NULL);
1420
// Check if the binding really needs an initialization check. The check
1421
// can be skipped in the following situation: we have a LET or CONST
1422
// binding in harmony mode, both the Variable and the VariableProxy have
1423
// the same declaration scope (i.e. they are both in global code, in the
1424
// same function or in the same eval code) and the VariableProxy is in
1425
// the source physically located after the initializer of the variable.
1427
// We cannot skip any initialization checks for CONST in non-harmony
1428
// mode because const variables may be declared but never initialized:
1429
// if (false) { const x; }; var y = x;
1431
// The condition on the declaration scopes is a conservative check for
1432
// nested functions that access a binding and are called before the
1433
// binding is initialized:
1434
// function() { f(); let x = 1; function f() { x = 2; } }
1436
bool skip_init_check;
1437
if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1438
skip_init_check = false;
1440
// Check that we always have valid source position.
1441
ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
1442
ASSERT(proxy->position() != RelocInfo::kNoPosition);
1443
skip_init_check = var->mode() != CONST &&
1444
var->initializer_position() < proxy->position();
1447
if (!skip_init_check) {
1448
// Let and const need a read barrier.
1451
__ CompareRoot(rax, Heap::kTheHoleValueRootIndex);
1452
__ j(not_equal, &done, Label::kNear);
1453
if (var->mode() == LET || var->mode() == CONST_HARMONY) {
1454
// Throw a reference error when using an uninitialized let/const
1455
// binding in harmony mode.
1456
__ Push(var->name());
1457
__ CallRuntime(Runtime::kThrowReferenceError, 1);
1459
// Uninitalized const bindings outside of harmony mode are unholed.
1460
ASSERT(var->mode() == CONST);
1461
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
1464
context()->Plug(rax);
1468
context()->Plug(var);
1544
void FullCodeGenerator::EmitAccessor(Expression* expression) {
1545
if (expression == NULL) {
1546
__ PushRoot(Heap::kNullValueRootIndex);
1548
VisitForStackValue(expression);
1303
1553
void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1304
1554
Comment cmnt(masm_, "[ ObjectLiteral");
1555
Handle<FixedArray> constant_properties = expr->constant_properties();
1305
1556
__ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1306
1557
__ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
1307
1558
__ Push(Smi::FromInt(expr->literal_index()));
1308
__ Push(expr->constant_properties());
1559
__ Push(constant_properties);
1309
1560
int flags = expr->fast_elements()
1310
1561
? ObjectLiteral::kFastElements
1311
1562
: ObjectLiteral::kNoFlags;
1350
1607
VisitForAccumulatorValue(value);
1351
1608
__ Move(rcx, key->handle());
1352
1609
__ movq(rdx, Operand(rsp, 0));
1353
Handle<Code> ic = is_strict_mode()
1354
? isolate()->builtins()->StoreIC_Initialize_Strict()
1355
: isolate()->builtins()->StoreIC_Initialize();
1356
__ call(ic, RelocInfo::CODE_TARGET, key->id());
1610
Handle<Code> ic = is_classic_mode()
1611
? isolate()->builtins()->StoreIC_Initialize()
1612
: isolate()->builtins()->StoreIC_Initialize_Strict();
1613
CallIC(ic, RelocInfo::CODE_TARGET, key->LiteralFeedbackId());
1357
1614
PrepareForBailoutForId(key->id(), NO_REGISTERS);
1359
1616
VisitForEffect(value);
1632
case ObjectLiteral::Property::GETTER:
1633
accessor_table.lookup(key)->second->getter = value;
1375
1635
case ObjectLiteral::Property::SETTER:
1376
case ObjectLiteral::Property::GETTER:
1377
__ push(Operand(rsp, 0)); // Duplicate receiver.
1378
VisitForStackValue(key);
1379
__ Push(property->kind() == ObjectLiteral::Property::SETTER ?
1382
VisitForStackValue(value);
1383
__ CallRuntime(Runtime::kDefineAccessor, 4);
1636
accessor_table.lookup(key)->second->setter = value;
1641
// Emit code to define accessors, using only a single call to the runtime for
1642
// each pair of corresponding getters and setters.
1643
for (AccessorTable::Iterator it = accessor_table.begin();
1644
it != accessor_table.end();
1646
__ push(Operand(rsp, 0)); // Duplicate receiver.
1647
VisitForStackValue(it->first);
1648
EmitAccessor(it->second->getter);
1649
EmitAccessor(it->second->setter);
1650
__ Push(Smi::FromInt(NONE));
1651
__ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
1388
1654
if (expr->has_function()) {
1389
1655
ASSERT(result_saved);
1390
1656
__ push(Operand(rsp, 0));
1405
1671
ZoneList<Expression*>* subexprs = expr->values();
1406
1672
int length = subexprs->length();
1673
Handle<FixedArray> constant_elements = expr->constant_elements();
1674
ASSERT_EQ(2, constant_elements->length());
1675
ElementsKind constant_elements_kind =
1676
static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
1677
bool has_constant_fast_elements =
1678
IsFastObjectElementsKind(constant_elements_kind);
1679
Handle<FixedArrayBase> constant_elements_values(
1680
FixedArrayBase::cast(constant_elements->get(1)));
1408
1682
__ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
1409
1683
__ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
1410
1684
__ Push(Smi::FromInt(expr->literal_index()));
1411
__ Push(expr->constant_elements());
1412
if (expr->constant_elements()->map() ==
1413
isolate()->heap()->fixed_cow_array_map()) {
1414
FastCloneShallowArrayStub stub(
1415
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1685
__ Push(constant_elements);
1686
Heap* heap = isolate()->heap();
1687
if (has_constant_fast_elements &&
1688
constant_elements_values->map() == heap->fixed_cow_array_map()) {
1689
// If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
1690
// change, so it's possible to specialize the stub in advance.
1417
1691
__ IncrementCounter(isolate()->counters()->cow_arrays_created_stub(), 1);
1692
FastCloneShallowArrayStub stub(
1693
FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
1418
1696
} else if (expr->depth() > 1) {
1419
1697
__ CallRuntime(Runtime::kCreateArrayLiteral, 3);
1420
1698
} else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
1421
1699
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
1423
FastCloneShallowArrayStub stub(
1424
FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
1701
ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
1702
FLAG_smi_only_arrays);
1703
// If the elements are already FAST_*_ELEMENTS, the boilerplate cannot
1704
// change, so it's possible to specialize the stub in advance.
1705
FastCloneShallowArrayStub::Mode mode = has_constant_fast_elements
1706
? FastCloneShallowArrayStub::CLONE_ELEMENTS
1707
: FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
1708
FastCloneShallowArrayStub stub(mode, length);
1425
1709
__ CallStub(&stub);
1445
1729
VisitForAccumulatorValue(subexpr);
1447
// Store the subexpression value in the array's elements.
1448
__ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
1449
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
1450
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1451
__ movq(FieldOperand(rbx, offset), result_register());
1453
// Update the write barrier for the array store.
1454
__ RecordWrite(rbx, offset, result_register(), rcx);
1731
if (IsFastObjectElementsKind(constant_elements_kind)) {
1732
// Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
1733
// cannot transition and don't need to call the runtime stub.
1734
int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1735
__ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
1736
__ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
1737
// Store the subexpression value in the array's elements.
1738
__ movq(FieldOperand(rbx, offset), result_register());
1739
// Update the write barrier for the array store.
1740
__ RecordWriteField(rbx, offset, result_register(), rcx,
1742
EMIT_REMEMBERED_SET,
1745
// Store the subexpression value in the array's elements.
1746
__ movq(rbx, Operand(rsp, 0)); // Copy of array literal.
1747
__ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset));
1748
__ Move(rcx, Smi::FromInt(i));
1749
__ Move(rdx, Smi::FromInt(expr->literal_index()));
1750
StoreArrayLiteralElementStub stub;
1456
1754
PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
1582
1880
Literal* key = prop->key()->AsLiteral();
1583
1881
__ Move(rcx, key->handle());
1584
1882
Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
1585
__ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
1883
CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId());
1589
1887
void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1590
1888
SetSourcePosition(prop->position());
1591
1889
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
1592
__ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
1890
CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId());
1661
1960
BinaryOpStub stub(op, mode);
1662
1961
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
1663
__ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
1962
CallIC(stub.GetCode(), RelocInfo::CODE_TARGET,
1963
expr->BinaryOperationFeedbackId());
1664
1964
patch_site.EmitPatchInfo();
1665
1965
context()->Plug(rax);
1669
void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
1969
void FullCodeGenerator::EmitAssignment(Expression* expr) {
1670
1970
// Invalid left-hand sides are rewritten to have a 'throw
1671
1971
// ReferenceError' on the left-hand side.
1672
1972
if (!expr->IsValidLeftHandSide()) {
1729
2028
// Global var, const, or let.
1730
2029
__ Move(rcx, var->name());
1731
2030
__ movq(rdx, GlobalObjectOperand());
1732
Handle<Code> ic = is_strict_mode()
1733
? isolate()->builtins()->StoreIC_Initialize_Strict()
1734
: isolate()->builtins()->StoreIC_Initialize();
1735
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
2031
Handle<Code> ic = is_classic_mode()
2032
? isolate()->builtins()->StoreIC_Initialize()
2033
: isolate()->builtins()->StoreIC_Initialize_Strict();
2034
CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
1736
2035
} else if (op == Token::INIT_CONST) {
1737
2036
// Const initializers need a write barrier.
1738
2037
ASSERT(!var->IsParameter()); // No const parameters.
1777
2076
__ movq(location, rax);
1778
2077
if (var->IsContextSlot()) {
1779
2078
__ movq(rdx, rax);
1780
__ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx);
2079
__ RecordWriteContextSlot(
2080
rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs);
1784
} else if (var->mode() != Variable::CONST) {
1785
// Assignment to var or initializing assignment to let.
2084
} else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
2085
// Assignment to var or initializing assignment to let/const
1786
2087
if (var->IsStackAllocated() || var->IsContextSlot()) {
1787
2088
MemOperand location = VarOperand(var, rcx);
1788
if (FLAG_debug_code && op == Token::INIT_LET) {
2089
if (generate_debug_code_ && op == Token::INIT_LET) {
1789
2090
// Check for an uninitialized let binding.
1790
2091
__ movq(rdx, location);
1791
2092
__ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
1816
2118
ASSERT(prop != NULL);
1817
2119
ASSERT(prop->key()->AsLiteral() != NULL);
1819
// If the assignment starts a block of assignments to the same object,
1820
// change to slow case to avoid the quadratic behavior of repeatedly
1821
// adding fast properties.
1822
if (expr->starts_initialization_block()) {
1823
__ push(result_register());
1824
__ push(Operand(rsp, kPointerSize)); // Receiver is now under value.
1825
__ CallRuntime(Runtime::kToSlowProperties, 1);
1826
__ pop(result_register());
1829
2121
// Record source code position before IC call.
1830
2122
SetSourcePosition(expr->position());
1831
2123
__ Move(rcx, prop->key()->AsLiteral()->handle());
1832
if (expr->ends_initialization_block()) {
1833
__ movq(rdx, Operand(rsp, 0));
1837
Handle<Code> ic = is_strict_mode()
1838
? isolate()->builtins()->StoreIC_Initialize_Strict()
1839
: isolate()->builtins()->StoreIC_Initialize();
1840
__ call(ic, RelocInfo::CODE_TARGET, expr->id());
2125
Handle<Code> ic = is_classic_mode()
2126
? isolate()->builtins()->StoreIC_Initialize()
2127
: isolate()->builtins()->StoreIC_Initialize_Strict();
2128
CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
1842
// If the assignment ends an initialization block, revert to fast case.
1843
if (expr->ends_initialization_block()) {
1844
__ push(rax); // Result of assignment, saved even if not needed.
1845
__ push(Operand(rsp, kPointerSize)); // Receiver is under value.
1846
__ CallRuntime(Runtime::kToFastProperties, 1);
1850
2130
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1851
2131
context()->Plug(rax);
1855
2135
void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1856
2136
// Assignment to a property, using a keyed store IC.
1858
// If the assignment starts a block of assignments to the same object,
1859
// change to slow case to avoid the quadratic behavior of repeatedly
1860
// adding fast properties.
1861
if (expr->starts_initialization_block()) {
1862
__ push(result_register());
1863
// Receiver is now under the key and value.
1864
__ push(Operand(rsp, 2 * kPointerSize));
1865
__ CallRuntime(Runtime::kToSlowProperties, 1);
1866
__ pop(result_register());
1870
if (expr->ends_initialization_block()) {
1871
__ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later.
1875
2140
// Record source code position before IC call.
1876
2141
SetSourcePosition(expr->position());
1877
Handle<Code> ic = is_strict_mode()
1878
? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1879
: isolate()->builtins()->KeyedStoreIC_Initialize();
1880
__ call(ic, RelocInfo::CODE_TARGET, expr->id());
1882
// If the assignment ends an initialization block, revert to fast case.
1883
if (expr->ends_initialization_block()) {
1885
__ push(rax); // Result of assignment, saved even if not needed.
1887
__ CallRuntime(Runtime::kToFastProperties, 1);
2142
Handle<Code> ic = is_classic_mode()
2143
? isolate()->builtins()->KeyedStoreIC_Initialize()
2144
: isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
2145
CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
1891
2147
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1892
2148
context()->Plug(rax);
1981
2246
// Record source position for debugger.
1982
2247
SetSourcePosition(expr->position());
2249
// Record call targets in unoptimized code.
2250
flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
2251
Handle<Object> uninitialized =
2252
TypeFeedbackCells::UninitializedSentinel(isolate());
2253
Handle<JSGlobalPropertyCell> cell =
2254
isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
2255
RecordTypeFeedbackCell(expr->CallFeedbackId(), cell);
1983
2258
CallFunctionStub stub(arg_count, flags);
2259
__ movq(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
2260
__ CallStub(&stub, expr->CallFeedbackId());
1985
2261
RecordJSReturnSite(expr);
1986
2262
// Restore context register.
1987
2263
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
2002
2277
// Push the receiver of the enclosing function and do runtime call.
2003
2278
__ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize));
2005
// Push the strict mode flag. In harmony mode every eval call
2006
// is a strict mode eval call.
2007
StrictModeFlag strict_mode = strict_mode_flag();
2008
if (FLAG_harmony_block_scoping) {
2009
strict_mode = kStrictMode;
2011
__ Push(Smi::FromInt(strict_mode));
2013
__ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2014
? Runtime::kResolvePossiblyDirectEvalNoLookup
2015
: Runtime::kResolvePossiblyDirectEval, 4);
2280
// Push the language mode.
2281
__ Push(Smi::FromInt(language_mode()));
2283
// Push the start position of the scope the calls resides in.
2284
__ Push(Smi::FromInt(scope()->start_position()));
2286
// Do the runtime call.
2287
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
2043
2315
VisitForStackValue(args->at(i));
2046
// If we know that eval can only be shadowed by eval-introduced
2047
// variables we attempt to load the global eval function directly in
2048
// generated code. If we succeed, there is no need to perform a
2049
// context lookup in the runtime system.
2051
Variable* var = proxy->var();
2052
if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) {
2054
EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow);
2055
// Push the function and resolve eval.
2057
EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2062
2318
// Push a copy of the function (found below the arguments) and resolve
2064
2320
__ push(Operand(rsp, (arg_count + 1) * kPointerSize));
2065
EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
2321
EmitResolvePossiblyDirectEval(arg_count);
2068
2323
// The runtime call returns a pair of values in rax (function) and
2069
2324
// rdx (receiver). Touch up the stack with the right values.
2175
2431
__ Set(rax, arg_count);
2176
2432
__ movq(rdi, Operand(rsp, arg_count * kPointerSize));
2178
Handle<Code> construct_builtin =
2179
isolate()->builtins()->JSConstructCall();
2180
__ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
2434
// Record call targets in unoptimized code, but not in the snapshot.
2435
Handle<Object> uninitialized =
2436
TypeFeedbackCells::UninitializedSentinel(isolate());
2437
Handle<JSGlobalPropertyCell> cell =
2438
isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
2439
RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell);
2442
CallConstructStub stub(RECORD_CALL_TARGET);
2443
__ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
2444
PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
2181
2445
context()->Plug(rax);
2185
void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
2449
void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2450
ZoneList<Expression*>* args = expr->arguments();
2186
2451
ASSERT(args->length() == 1);
2188
2453
VisitForAccumulatorValue(args->at(0));
2246
2513
__ cmpq(rbx, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2247
2514
__ j(below, if_false);
2248
2515
__ cmpq(rbx, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
2249
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2516
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2250
2517
Split(below_equal, if_true, if_false, fall_through);
2252
2519
context()->Plug(if_true, if_false);
2256
void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2523
void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
2524
ZoneList<Expression*>* args = expr->arguments();
2257
2525
ASSERT(args->length() == 1);
2259
2527
VisitForAccumulatorValue(args->at(0));
2268
2536
__ JumpIfSmi(rax, if_false);
2269
2537
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx);
2270
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2538
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2271
2539
Split(above_equal, if_true, if_false, fall_through);
2273
2541
context()->Plug(if_true, if_false);
2277
void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2545
void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
2546
ZoneList<Expression*>* args = expr->arguments();
2278
2547
ASSERT(args->length() == 1);
2280
2549
VisitForAccumulatorValue(args->at(0));
2326
2596
__ j(equal, if_false);
2328
2598
// Look for valueOf symbol in the descriptor array, and indicate false if
2329
// found. The type is not checked, so if it is a transition it is a false
2599
// found. Since we omit an enumeration index check, if it is added via a
2600
// transition that shares its descriptor array, this is a false positive.
2601
Label entry, loop, done;
2603
// Skip loop if no descriptors are valid.
2604
__ NumberOfOwnDescriptors(rcx, rbx);
2605
__ cmpq(rcx, Immediate(0));
2331
2608
__ LoadInstanceDescriptors(rbx, rbx);
2332
__ movq(rcx, FieldOperand(rbx, FixedArray::kLengthOffset));
2333
// rbx: descriptor array
2334
// rcx: length of descriptor array
2609
// rbx: descriptor array.
2610
// rcx: valid entries in the descriptor array.
2335
2611
// Calculate the end of the descriptor array.
2612
__ imul(rcx, rcx, Immediate(DescriptorArray::kDescriptorSize));
2336
2613
SmiIndex index = masm_->SmiToIndex(rdx, rcx, kPointerSizeLog2);
2339
rbx, index.reg, index.scale, FixedArray::kHeaderSize));
2616
rbx, index.reg, index.scale, DescriptorArray::kFirstOffset));
2340
2617
// Calculate location of the first key name.
2342
Immediate(FixedArray::kHeaderSize +
2343
DescriptorArray::kFirstIndex * kPointerSize));
2618
__ addq(rbx, Immediate(DescriptorArray::kFirstOffset));
2344
2619
// Loop through all the keys in the descriptor array. If one of these is the
2345
2620
// symbol valueOf the result is false.
2347
2621
__ jmp(&entry);
2348
2622
__ bind(&loop);
2349
2623
__ movq(rdx, FieldOperand(rbx, 0));
2350
2624
__ Cmp(rdx, FACTORY->value_of_symbol());
2351
2625
__ j(equal, if_false);
2352
__ addq(rbx, Immediate(kPointerSize));
2626
__ addq(rbx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
2353
2627
__ bind(&entry);
2354
2628
__ cmpq(rbx, rcx);
2355
2629
__ j(not_equal, &loop);
2357
2632
// Reload map as register rbx was used as temporary above.
2358
2633
__ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
2360
// If a valueOf property is not found on the object check that it's
2635
// If a valueOf property is not found on the object check that its
2361
2636
// prototype is the un-modified String prototype. If not result is false.
2362
2637
__ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset));
2363
2638
__ testq(rcx, Immediate(kSmiTagMask));
2364
2639
__ j(zero, if_false);
2365
2640
__ movq(rcx, FieldOperand(rcx, HeapObject::kMapOffset));
2366
__ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
2367
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalContextOffset));
2641
__ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
2642
__ movq(rdx, FieldOperand(rdx, GlobalObject::kNativeContextOffset));
2369
2644
ContextOperand(rdx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2370
2645
__ j(not_equal, if_false);
2394
2670
__ JumpIfSmi(rax, if_false);
2395
2671
__ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2396
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2672
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2397
2673
Split(equal, if_true, if_false, fall_through);
2399
2675
context()->Plug(if_true, if_false);
2403
void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2679
void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2680
ZoneList<Expression*>* args = expr->arguments();
2404
2681
ASSERT(args->length() == 1);
2406
2683
VisitForAccumulatorValue(args->at(0));
2415
2692
__ JumpIfSmi(rax, if_false);
2416
2693
__ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
2417
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2694
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2418
2695
Split(equal, if_true, if_false, fall_through);
2420
2697
context()->Plug(if_true, if_false);
2424
void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2701
void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2702
ZoneList<Expression*>* args = expr->arguments();
2425
2703
ASSERT(args->length() == 1);
2427
2705
VisitForAccumulatorValue(args->at(0));
2467
2745
__ bind(&check_frame_marker);
2468
2746
__ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset),
2469
2747
Smi::FromInt(StackFrame::CONSTRUCT));
2470
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2748
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2471
2749
Split(equal, if_true, if_false, fall_through);
2473
2751
context()->Plug(if_true, if_false);
2477
void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2755
void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
2756
ZoneList<Expression*>* args = expr->arguments();
2478
2757
ASSERT(args->length() == 2);
2480
2759
// Load the two objects into registers and perform the comparison.
2546
2827
// Check that the object is a JS object but take special care of JS
2547
2828
// functions to make sure they have 'Function' as their class.
2829
// Assume that there are only two callable types, and one of them is at
2830
// either end of the type range for JS object types. Saves extra comparisons.
2831
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2548
2832
__ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax);
2549
2833
// Map is now in rax.
2550
2834
__ j(below, &null);
2552
// As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and
2553
// FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
2554
// LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
2555
STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
2556
STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
2557
LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
2558
__ CmpInstanceType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
2559
__ j(above_equal, &function);
2561
// Check if the constructor in the map is a function.
2835
STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2836
FIRST_SPEC_OBJECT_TYPE + 1);
2837
__ j(equal, &function);
2839
__ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE);
2840
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2841
LAST_SPEC_OBJECT_TYPE - 1);
2842
__ j(equal, &function);
2843
// Assume that there is no larger type.
2844
STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
2846
// Check if the constructor in the map is a JS function.
2562
2847
__ movq(rax, FieldOperand(rax, Map::kConstructorOffset));
2563
2848
__ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2564
2849
__ j(not_equal, &non_function_constructor);
2698
void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2992
void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
2993
ZoneList<Expression*>* args = expr->arguments();
2994
ASSERT(args->length() == 2);
2995
ASSERT_NE(NULL, args->at(1)->AsLiteral());
2996
Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->handle()));
2998
VisitForAccumulatorValue(args->at(0)); // Load the object.
3000
Label runtime, done, not_date_object;
3001
Register object = rax;
3002
Register result = rax;
3003
Register scratch = rcx;
3005
__ JumpIfSmi(object, ¬_date_object);
3006
__ CmpObjectType(object, JS_DATE_TYPE, scratch);
3007
__ j(not_equal, ¬_date_object);
3009
if (index->value() == 0) {
3010
__ movq(result, FieldOperand(object, JSDate::kValueOffset));
3013
if (index->value() < JSDate::kFirstUncachedField) {
3014
ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
3015
__ movq(scratch, stamp);
3016
__ cmpq(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
3017
__ j(not_equal, &runtime, Label::kNear);
3018
__ movq(result, FieldOperand(object, JSDate::kValueOffset +
3019
kPointerSize * index->value()));
3023
__ PrepareCallCFunction(2);
3025
__ movq(rcx, object);
3026
__ movq(rdx, index, RelocInfo::NONE);
3028
__ movq(rdi, object);
3029
__ movq(rsi, index, RelocInfo::NONE);
3031
__ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
3032
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3036
__ bind(¬_date_object);
3037
__ CallRuntime(Runtime::kThrowNotDateError, 0);
3039
context()->Plug(rax);
3043
void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
2699
3044
// Load the arguments on the stack and call the runtime function.
3045
ZoneList<Expression*>* args = expr->arguments();
2700
3046
ASSERT(args->length() == 2);
2701
3047
VisitForStackValue(args->at(0));
2702
3048
VisitForStackValue(args->at(1));
3049
MathPowStub stub(MathPowStub::ON_STACK);
2704
3050
__ CallStub(&stub);
2705
3051
context()->Plug(rax);
2709
void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
3055
void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3056
ZoneList<Expression*>* args = expr->arguments();
2710
3057
ASSERT(args->length() == 2);
2712
3059
VisitForStackValue(args->at(0)); // Load the object.
2897
void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
3247
void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
2898
3248
// Load the argument on the stack and call the stub.
2899
3249
TranscendentalCacheStub stub(TranscendentalCache::COS,
2900
3250
TranscendentalCacheStub::TAGGED);
2901
ASSERT(args->length() == 1);
2902
VisitForStackValue(args->at(0));
2904
context()->Plug(rax);
2908
void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
3251
ZoneList<Expression*>* args = expr->arguments();
3252
ASSERT(args->length() == 1);
3253
VisitForStackValue(args->at(0));
3255
context()->Plug(rax);
3259
void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
3260
// Load the argument on the stack and call the stub.
3261
TranscendentalCacheStub stub(TranscendentalCache::TAN,
3262
TranscendentalCacheStub::TAGGED);
3263
ZoneList<Expression*>* args = expr->arguments();
3264
ASSERT(args->length() == 1);
3265
VisitForStackValue(args->at(0));
3267
context()->Plug(rax);
3271
void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
2909
3272
// Load the argument on the stack and call the stub.
2910
3273
TranscendentalCacheStub stub(TranscendentalCache::LOG,
2911
3274
TranscendentalCacheStub::TAGGED);
3275
ZoneList<Expression*>* args = expr->arguments();
2912
3276
ASSERT(args->length() == 1);
2913
3277
VisitForStackValue(args->at(0));
2914
3278
__ CallStub(&stub);
2935
3301
VisitForAccumulatorValue(args->last()); // Function.
3303
Label runtime, done;
3304
// Check for non-function argument (including proxy).
3305
__ JumpIfSmi(rax, &runtime);
3306
__ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
3307
__ j(not_equal, &runtime);
2937
3309
// InvokeFunction requires the function in rdi. Move it in there.
2938
3310
__ movq(rdi, result_register());
2939
3311
ParameterCount count(arg_count);
2940
3312
__ InvokeFunction(rdi, count, CALL_FUNCTION,
2941
3313
NullCallWrapper(), CALL_AS_METHOD);
2942
3314
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3319
__ CallRuntime(Runtime::kCall, args->length());
2943
3322
context()->Plug(rax);
2947
void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
3326
void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
2948
3327
RegExpConstructResultStub stub;
3328
ZoneList<Expression*>* args = expr->arguments();
2949
3329
ASSERT(args->length() == 3);
2950
3330
VisitForStackValue(args->at(0));
2951
3331
VisitForStackValue(args->at(1));
2958
void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2959
ASSERT(args->length() == 3);
2960
VisitForStackValue(args->at(0));
2961
VisitForStackValue(args->at(1));
2962
VisitForStackValue(args->at(2));
2965
Register object = rax;
2966
Register index_1 = rbx;
2967
Register index_2 = rcx;
2968
Register elements = rdi;
2969
Register temp = rdx;
2970
__ movq(object, Operand(rsp, 2 * kPointerSize));
2971
// Fetch the map and check if array is in fast case.
2972
// Check that object doesn't require security checks and
2973
// has no indexed interceptor.
2974
__ CmpObjectType(object, JS_ARRAY_TYPE, temp);
2975
__ j(not_equal, &slow_case);
2976
__ testb(FieldOperand(temp, Map::kBitFieldOffset),
2977
Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
2978
__ j(not_zero, &slow_case);
2980
// Check the object's elements are in fast case and writable.
2981
__ movq(elements, FieldOperand(object, JSObject::kElementsOffset));
2982
__ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
2983
Heap::kFixedArrayMapRootIndex);
2984
__ j(not_equal, &slow_case);
2986
// Check that both indices are smis.
2987
__ movq(index_1, Operand(rsp, 1 * kPointerSize));
2988
__ movq(index_2, Operand(rsp, 0 * kPointerSize));
2989
__ JumpIfNotBothSmi(index_1, index_2, &slow_case);
2991
// Check that both indices are valid.
2992
// The JSArray length field is a smi since the array is in fast case mode.
2993
__ movq(temp, FieldOperand(object, JSArray::kLengthOffset));
2994
__ SmiCompare(temp, index_1);
2995
__ j(below_equal, &slow_case);
2996
__ SmiCompare(temp, index_2);
2997
__ j(below_equal, &slow_case);
2999
__ SmiToInteger32(index_1, index_1);
3000
__ SmiToInteger32(index_2, index_2);
3001
// Bring addresses into index1 and index2.
3002
__ lea(index_1, FieldOperand(elements, index_1, times_pointer_size,
3003
FixedArray::kHeaderSize));
3004
__ lea(index_2, FieldOperand(elements, index_2, times_pointer_size,
3005
FixedArray::kHeaderSize));
3007
// Swap elements. Use object and temp as scratch registers.
3008
__ movq(object, Operand(index_1, 0));
3009
__ movq(temp, Operand(index_2, 0));
3010
__ movq(Operand(index_2, 0), object);
3011
__ movq(Operand(index_1, 0), temp);
3014
__ InNewSpace(elements, temp, equal, &new_space);
3016
__ movq(object, elements);
3017
__ RecordWriteHelper(object, index_1, temp);
3018
__ RecordWriteHelper(elements, index_2, temp);
3020
__ bind(&new_space);
3021
// We are done. Drop elements from the stack, and return undefined.
3022
__ addq(rsp, Immediate(3 * kPointerSize));
3023
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3026
__ bind(&slow_case);
3027
__ CallRuntime(Runtime::kSwapElements, 3);
3030
context()->Plug(rax);
3034
void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
3338
void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3339
ZoneList<Expression*>* args = expr->arguments();
3035
3340
ASSERT_EQ(2, args->length());
3037
3342
ASSERT_NE(NULL, args->at(0)->AsLiteral());
3038
3343
int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3040
3345
Handle<FixedArray> jsfunction_result_caches(
3041
isolate()->global_context()->jsfunction_result_caches());
3346
isolate()->native_context()->jsfunction_result_caches());
3042
3347
if (jsfunction_result_caches->length() <= cache_id) {
3043
3348
__ Abort("Attempt to use undefined cache.");
3044
3349
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
3166
void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
3472
void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
3167
3473
Label bailout, return_result, done, one_char_separator, long_separator,
3168
3474
non_trivial_array, not_size_one_array, loop,
3169
3475
loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
3476
ZoneList<Expression*>* args = expr->arguments();
3170
3477
ASSERT(args->length() == 2);
3171
3478
// We will leave the separator on the stack until the end of the function.
3172
3479
VisitForStackValue(args->at(1));
3496
3803
if (property != NULL) {
3497
3804
VisitForStackValue(property->obj());
3498
3805
VisitForStackValue(property->key());
3499
__ Push(Smi::FromInt(strict_mode_flag()));
3806
StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE)
3807
? kNonStrictMode : kStrictMode;
3808
__ Push(Smi::FromInt(strict_mode_flag));
3500
3809
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3501
3810
context()->Plug(rax);
3502
3811
} else if (proxy != NULL) {
3503
3812
Variable* var = proxy->var();
3504
3813
// Delete of an unqualified identifier is disallowed in strict mode
3505
3814
// but "delete this" is allowed.
3506
ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
3815
ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
3507
3816
if (var->IsUnallocated()) {
3508
3817
__ push(GlobalObjectOperand());
3509
3818
__ Push(var->name());
3545
3854
// Unary NOT has no side effects so it's only necessary to visit the
3546
3855
// subexpression. Match the optimizing compiler by not branching.
3547
3856
VisitForEffect(expr->expression());
3857
} else if (context()->IsTest()) {
3858
const TestContext* test = TestContext::cast(context());
3859
// The labels are swapped for the recursive call.
3860
VisitForControl(expr->expression(),
3861
test->false_label(),
3863
test->fall_through());
3864
context()->Plug(test->true_label(), test->false_label());
3549
Label materialize_true, materialize_false;
3550
Label* if_true = NULL;
3551
Label* if_false = NULL;
3552
Label* fall_through = NULL;
3553
// Notice that the labels are swapped.
3554
context()->PrepareTest(&materialize_true, &materialize_false,
3555
&if_false, &if_true, &fall_through);
3556
if (context()->IsTest()) ForwardBailoutToChild(expr);
3557
VisitForControl(expr->expression(), if_true, if_false, fall_through);
3558
context()->Plug(if_false, if_true); // Labels swapped.
3866
// We handle value contexts explicitly rather than simply visiting
3867
// for control and plugging the control flow into the context,
3868
// because we need to prepare a pair of extra administrative AST ids
3869
// for the optimizing compiler.
3870
ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
3871
Label materialize_true, materialize_false, done;
3872
VisitForControl(expr->expression(),
3876
__ bind(&materialize_true);
3877
PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
3878
if (context()->IsAccumulatorValue()) {
3879
__ LoadRoot(rax, Heap::kTrueValueRootIndex);
3881
__ PushRoot(Heap::kTrueValueRootIndex);
3883
__ jmp(&done, Label::kNear);
3884
__ bind(&materialize_false);
3885
PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
3886
if (context()->IsAccumulatorValue()) {
3887
__ LoadRoot(rax, Heap::kFalseValueRootIndex);
3889
__ PushRoot(Heap::kFalseValueRootIndex);
3760
4094
case NAMED_PROPERTY: {
3761
4095
__ Move(rcx, prop->key()->AsLiteral()->handle());
3763
Handle<Code> ic = is_strict_mode()
3764
? isolate()->builtins()->StoreIC_Initialize_Strict()
3765
: isolate()->builtins()->StoreIC_Initialize();
3766
__ call(ic, RelocInfo::CODE_TARGET, expr->id());
4097
Handle<Code> ic = is_classic_mode()
4098
? isolate()->builtins()->StoreIC_Initialize()
4099
: isolate()->builtins()->StoreIC_Initialize_Strict();
4100
CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId());
3767
4101
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3768
4102
if (expr->is_postfix()) {
3769
4103
if (!context()->IsEffect()) {
3827
4161
context()->Plug(rax);
3829
4163
// This expression cannot throw a reference error at the top level.
3830
VisitInCurrentContext(expr);
4164
VisitInDuplicateContext(expr);
3835
4169
void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
3836
Handle<String> check,
3839
Label* fall_through) {
4170
Expression* sub_expr,
4171
Handle<String> check) {
4172
Label materialize_true, materialize_false;
4173
Label* if_true = NULL;
4174
Label* if_false = NULL;
4175
Label* fall_through = NULL;
4176
context()->PrepareTest(&materialize_true, &materialize_false,
4177
&if_true, &if_false, &fall_through);
3840
4179
{ AccumulatorValueContext context(this);
3841
VisitForTypeofValue(expr);
4180
VisitForTypeofValue(sub_expr);
3843
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4182
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3845
4184
if (check->Equals(isolate()->heap()->number_symbol())) {
3846
4185
__ JumpIfSmi(rax, if_true);
3875
4214
Split(not_zero, if_true, if_false, fall_through);
3876
4215
} else if (check->Equals(isolate()->heap()->function_symbol())) {
3877
4216
__ JumpIfSmi(rax, if_false);
3878
STATIC_ASSERT(LAST_CALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE);
3879
__ CmpObjectType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, rdx);
3880
Split(above_equal, if_true, if_false, fall_through);
4217
STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4218
__ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx);
4219
__ j(equal, if_true);
4220
__ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE);
4221
Split(equal, if_true, if_false, fall_through);
3881
4222
} else if (check->Equals(isolate()->heap()->object_symbol())) {
3882
4223
__ JumpIfSmi(rax, if_false);
3883
4224
if (!FLAG_harmony_typeof) {
3923
4257
context()->PrepareTest(&materialize_true, &materialize_false,
3924
4258
&if_true, &if_false, &fall_through);
3926
// First we try a fast inlined version of the compare when one of
3927
// the operands is a literal.
3928
if (TryLiteralCompare(expr, if_true, if_false, fall_through)) {
3929
context()->Plug(if_true, if_false);
3933
4260
Token::Value op = expr->op();
3934
4261
VisitForStackValue(expr->left());
3936
4263
case Token::IN:
3937
4264
VisitForStackValue(expr->right());
3938
4265
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
3939
PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
4266
PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3940
4267
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
3941
4268
Split(equal, if_true, if_false, fall_through);
4002
4321
// Record position and call the compare IC.
4003
4322
SetSourcePosition(expr->position());
4004
4323
Handle<Code> ic = CompareIC::GetUninitialized(op);
4005
__ call(ic, RelocInfo::CODE_TARGET, expr->id());
4324
CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId());
4006
4325
patch_site.EmitPatchInfo();
4008
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4327
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4009
4328
__ testq(rax, rax);
4010
4329
Split(cc, if_true, if_false, fall_through);
4026
4346
context()->PrepareTest(&materialize_true, &materialize_false,
4027
4347
&if_true, &if_false, &fall_through);
4029
VisitForAccumulatorValue(expr->expression());
4030
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4031
__ CompareRoot(rax, Heap::kNullValueRootIndex);
4032
if (expr->is_strict()) {
4349
VisitForAccumulatorValue(sub_expr);
4350
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4351
Heap::RootListIndex nil_value = nil == kNullValue ?
4352
Heap::kNullValueRootIndex :
4353
Heap::kUndefinedValueRootIndex;
4354
__ CompareRoot(rax, nil_value);
4355
if (expr->op() == Token::EQ_STRICT) {
4033
4356
Split(equal, if_true, if_false, fall_through);
4358
Heap::RootListIndex other_nil_value = nil == kNullValue ?
4359
Heap::kUndefinedValueRootIndex :
4360
Heap::kNullValueRootIndex;
4035
4361
__ j(equal, if_true);
4036
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
4362
__ CompareRoot(rax, other_nil_value);
4037
4363
__ j(equal, if_true);
4038
4364
__ JumpIfSmi(rax, if_false);
4039
4365
// It can be an undetectable object.
4106
4433
__ subq(rdx, rcx);
4107
4434
__ Integer32ToSmi(rdx, rdx);
4109
4437
// Store result register while executing finally block.
4110
4438
__ push(result_register());
4440
// Store pending message while executing finally block.
4441
ExternalReference pending_message_obj =
4442
ExternalReference::address_of_pending_message_obj(isolate());
4443
__ Load(rdx, pending_message_obj);
4446
ExternalReference has_pending_message =
4447
ExternalReference::address_of_has_pending_message(isolate());
4448
__ Load(rdx, has_pending_message);
4449
__ Integer32ToSmi(rdx, rdx);
4452
ExternalReference pending_message_script =
4453
ExternalReference::address_of_pending_message_script(isolate());
4454
__ Load(rdx, pending_message_script);
4114
4459
void FullCodeGenerator::ExitFinallyBlock() {
4115
4460
ASSERT(!result_register().is(rdx));
4116
4461
ASSERT(!result_register().is(rcx));
4462
// Restore pending message from stack.
4464
ExternalReference pending_message_script =
4465
ExternalReference::address_of_pending_message_script(isolate());
4466
__ Store(pending_message_script, rdx);
4469
__ SmiToInteger32(rdx, rdx);
4470
ExternalReference has_pending_message =
4471
ExternalReference::address_of_has_pending_message(isolate());
4472
__ Store(has_pending_message, rdx);
4475
ExternalReference pending_message_obj =
4476
ExternalReference::address_of_pending_message_obj(isolate());
4477
__ Store(pending_message_obj, rdx);
4479
// Restore result register from stack.
4117
4480
__ pop(result_register());
4118
4482
// Uncook return address.
4120
4484
__ SmiToInteger32(rdx, rdx);