blob: 8048738b28e487b40971a7e302176a6248c7395c [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
Ben Murdoch85b71792012-04-11 18:30:58 +010029#include "accessors.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010030
31#include "contexts.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010032#include "deoptimizer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000033#include "execution.h"
34#include "factory.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010035#include "frames-inl.h"
36#include "isolate.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000037#include "list-inl.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010038#include "property-details.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039
40namespace v8 {
41namespace internal {
42
43
44template <class C>
45static C* FindInPrototypeChain(Object* obj, bool* found_it) {
46 ASSERT(!*found_it);
Steve Block44f0eee2011-05-26 01:26:41 +010047 Heap* heap = HEAP;
Steve Blocka7e24c12009-10-30 11:49:00 +000048 while (!Is<C>(obj)) {
Steve Block44f0eee2011-05-26 01:26:41 +010049 if (obj == heap->null_value()) return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +000050 obj = obj->GetPrototype();
51 }
52 *found_it = true;
53 return C::cast(obj);
54}
55
56
57// Entry point that never should be called.
John Reck59135872010-11-02 12:39:01 -070058MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000059 UNREACHABLE();
60 return NULL;
61}
62
63
64Object* Accessors::IllegalGetAccessor(Object* object, void*) {
65 UNREACHABLE();
66 return object;
67}
68
69
John Reck59135872010-11-02 12:39:01 -070070MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000071 // According to ECMA-262, section 8.6.2.2, page 28, setting
72 // read-only properties must be silently ignored.
73 return value;
74}
75
76
77//
78// Accessors::ArrayLength
79//
80
81
John Reck59135872010-11-02 12:39:01 -070082MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +000083 // Traverse the prototype chain until we reach an array.
84 bool found_it = false;
85 JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
86 if (!found_it) return Smi::FromInt(0);
87 return holder->length();
88}
89
90
91// The helper function will 'flatten' Number objects.
92Object* Accessors::FlattenNumber(Object* value) {
93 if (value->IsNumber() || !value->IsJSValue()) return value;
94 JSValue* wrapper = JSValue::cast(value);
Steve Block44f0eee2011-05-26 01:26:41 +010095 ASSERT(Isolate::Current()->context()->global_context()->number_function()->
96 has_initial_map());
97 Map* number_map = Isolate::Current()->context()->global_context()->
98 number_function()->initial_map();
Steve Blocka7e24c12009-10-30 11:49:00 +000099 if (wrapper->map() == number_map) return wrapper->value();
100 return value;
101}
102
103
John Reck59135872010-11-02 12:39:01 -0700104MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100105 Isolate* isolate = object->GetIsolate();
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100106
107 // This means one of the object's prototypes is a JSArray and the
108 // object does not have a 'length' property. Calling SetProperty
109 // causes an infinite loop.
110 if (!object->IsJSArray()) {
111 return object->SetLocalPropertyIgnoreAttributes(
112 isolate->heap()->length_symbol(), value, NONE);
113 }
114
Steve Blocka7e24c12009-10-30 11:49:00 +0000115 value = FlattenNumber(value);
116
117 // Need to call methods that may trigger GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100118 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000119
120 // Protect raw pointers.
Steve Block44f0eee2011-05-26 01:26:41 +0100121 Handle<JSObject> object_handle(object, isolate);
122 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000123
124 bool has_exception;
125 Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
126 if (has_exception) return Failure::Exception();
127 Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
128 if (has_exception) return Failure::Exception();
129
Steve Blocka7e24c12009-10-30 11:49:00 +0000130 if (uint32_v->Number() == number_v->Number()) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +0100131 return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v);
Steve Blocka7e24c12009-10-30 11:49:00 +0000132 }
Steve Block44f0eee2011-05-26 01:26:41 +0100133 return isolate->Throw(
134 *isolate->factory()->NewRangeError("invalid_array_length",
135 HandleVector<Object>(NULL, 0)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000136}
137
138
139const AccessorDescriptor Accessors::ArrayLength = {
140 ArrayGetLength,
141 ArraySetLength,
142 0
143};
144
145
146//
147// Accessors::StringLength
148//
149
150
John Reck59135872010-11-02 12:39:01 -0700151MaybeObject* Accessors::StringGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000152 Object* value = object;
153 if (object->IsJSValue()) value = JSValue::cast(object)->value();
154 if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
155 // If object is not a string we return 0 to be compatible with WebKit.
156 // Note: Firefox returns the length of ToString(object).
157 return Smi::FromInt(0);
158}
159
160
161const AccessorDescriptor Accessors::StringLength = {
162 StringGetLength,
163 IllegalSetter,
164 0
165};
166
167
168//
169// Accessors::ScriptSource
170//
171
172
John Reck59135872010-11-02 12:39:01 -0700173MaybeObject* Accessors::ScriptGetSource(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000174 Object* script = JSValue::cast(object)->value();
175 return Script::cast(script)->source();
176}
177
178
179const AccessorDescriptor Accessors::ScriptSource = {
180 ScriptGetSource,
181 IllegalSetter,
182 0
183};
184
185
186//
187// Accessors::ScriptName
188//
189
190
John Reck59135872010-11-02 12:39:01 -0700191MaybeObject* Accessors::ScriptGetName(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000192 Object* script = JSValue::cast(object)->value();
193 return Script::cast(script)->name();
194}
195
196
197const AccessorDescriptor Accessors::ScriptName = {
198 ScriptGetName,
199 IllegalSetter,
200 0
201};
202
203
204//
205// Accessors::ScriptId
206//
207
208
John Reck59135872010-11-02 12:39:01 -0700209MaybeObject* Accessors::ScriptGetId(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 Object* script = JSValue::cast(object)->value();
211 return Script::cast(script)->id();
212}
213
214
215const AccessorDescriptor Accessors::ScriptId = {
216 ScriptGetId,
217 IllegalSetter,
218 0
219};
220
221
222//
223// Accessors::ScriptLineOffset
224//
225
226
John Reck59135872010-11-02 12:39:01 -0700227MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 Object* script = JSValue::cast(object)->value();
229 return Script::cast(script)->line_offset();
230}
231
232
233const AccessorDescriptor Accessors::ScriptLineOffset = {
234 ScriptGetLineOffset,
235 IllegalSetter,
236 0
237};
238
239
240//
241// Accessors::ScriptColumnOffset
242//
243
244
John Reck59135872010-11-02 12:39:01 -0700245MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000246 Object* script = JSValue::cast(object)->value();
247 return Script::cast(script)->column_offset();
248}
249
250
251const AccessorDescriptor Accessors::ScriptColumnOffset = {
252 ScriptGetColumnOffset,
253 IllegalSetter,
254 0
255};
256
257
258//
259// Accessors::ScriptData
260//
261
262
John Reck59135872010-11-02 12:39:01 -0700263MaybeObject* Accessors::ScriptGetData(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000264 Object* script = JSValue::cast(object)->value();
265 return Script::cast(script)->data();
266}
267
268
269const AccessorDescriptor Accessors::ScriptData = {
270 ScriptGetData,
271 IllegalSetter,
272 0
273};
274
275
276//
277// Accessors::ScriptType
278//
279
280
John Reck59135872010-11-02 12:39:01 -0700281MaybeObject* Accessors::ScriptGetType(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000282 Object* script = JSValue::cast(object)->value();
283 return Script::cast(script)->type();
284}
285
286
287const AccessorDescriptor Accessors::ScriptType = {
288 ScriptGetType,
289 IllegalSetter,
290 0
291};
292
293
294//
295// Accessors::ScriptCompilationType
296//
297
298
John Reck59135872010-11-02 12:39:01 -0700299MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000300 Object* script = JSValue::cast(object)->value();
301 return Script::cast(script)->compilation_type();
302}
303
304
305const AccessorDescriptor Accessors::ScriptCompilationType = {
306 ScriptGetCompilationType,
307 IllegalSetter,
308 0
309};
310
311
312//
313// Accessors::ScriptGetLineEnds
314//
315
316
John Reck59135872010-11-02 12:39:01 -0700317MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100318 JSValue* wrapper = JSValue::cast(object);
319 Isolate* isolate = wrapper->GetIsolate();
320 HandleScope scope(isolate);
321 Handle<Script> script(Script::cast(wrapper->value()), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000322 InitScriptLineEnds(script);
Steve Blockd0582a62009-12-15 09:54:21 +0000323 ASSERT(script->line_ends()->IsFixedArray());
324 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800325 // We do not want anyone to modify this array from JS.
Steve Block44f0eee2011-05-26 01:26:41 +0100326 ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
327 line_ends->map() == isolate->heap()->fixed_cow_array_map());
328 Handle<JSArray> js_array =
329 isolate->factory()->NewJSArrayWithElements(line_ends);
Steve Blockd0582a62009-12-15 09:54:21 +0000330 return *js_array;
Steve Blocka7e24c12009-10-30 11:49:00 +0000331}
332
333
334const AccessorDescriptor Accessors::ScriptLineEnds = {
335 ScriptGetLineEnds,
336 IllegalSetter,
337 0
338};
339
340
341//
342// Accessors::ScriptGetContextData
343//
344
345
John Reck59135872010-11-02 12:39:01 -0700346MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000347 Object* script = JSValue::cast(object)->value();
348 return Script::cast(script)->context_data();
349}
350
351
352const AccessorDescriptor Accessors::ScriptContextData = {
353 ScriptGetContextData,
354 IllegalSetter,
355 0
356};
357
358
359//
Steve Blockd0582a62009-12-15 09:54:21 +0000360// Accessors::ScriptGetEvalFromScript
Steve Blocka7e24c12009-10-30 11:49:00 +0000361//
362
363
John Reck59135872010-11-02 12:39:01 -0700364MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000365 Object* script = JSValue::cast(object)->value();
Steve Blockd0582a62009-12-15 09:54:21 +0000366 if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
367 Handle<SharedFunctionInfo> eval_from_shared(
368 SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
369
370 if (eval_from_shared->script()->IsScript()) {
371 Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
372 return *GetScriptWrapper(eval_from_script);
373 }
374 }
Steve Block44f0eee2011-05-26 01:26:41 +0100375 return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000376}
377
378
Steve Blockd0582a62009-12-15 09:54:21 +0000379const AccessorDescriptor Accessors::ScriptEvalFromScript = {
380 ScriptGetEvalFromScript,
Steve Blocka7e24c12009-10-30 11:49:00 +0000381 IllegalSetter,
382 0
383};
384
385
386//
Steve Blockd0582a62009-12-15 09:54:21 +0000387// Accessors::ScriptGetEvalFromScriptPosition
Steve Blocka7e24c12009-10-30 11:49:00 +0000388//
389
390
John Reck59135872010-11-02 12:39:01 -0700391MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000392 HandleScope scope;
393 Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
394
395 // If this is not a script compiled through eval there is no eval position.
396 int compilation_type = Smi::cast(script->compilation_type())->value();
397 if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100398 return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000399 }
400
401 // Get the function from where eval was called and find the source position
402 // from the instruction offset.
Steve Blockd0582a62009-12-15 09:54:21 +0000403 Handle<Code> code(SharedFunctionInfo::cast(
404 script->eval_from_shared())->code());
Steve Blocka7e24c12009-10-30 11:49:00 +0000405 return Smi::FromInt(code->SourcePosition(code->instruction_start() +
406 script->eval_from_instructions_offset()->value()));
407}
408
409
Steve Blockd0582a62009-12-15 09:54:21 +0000410const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
411 ScriptGetEvalFromScriptPosition,
412 IllegalSetter,
413 0
414};
415
416
417//
418// Accessors::ScriptGetEvalFromFunctionName
419//
420
421
John Reck59135872010-11-02 12:39:01 -0700422MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
Steve Blockd0582a62009-12-15 09:54:21 +0000423 Object* script = JSValue::cast(object)->value();
424 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
425 Script::cast(script)->eval_from_shared()));
426
427
428 // Find the name of the function calling eval.
429 if (!shared->name()->IsUndefined()) {
430 return shared->name();
431 } else {
432 return shared->inferred_name();
433 }
434}
435
436
437const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
438 ScriptGetEvalFromFunctionName,
Steve Blocka7e24c12009-10-30 11:49:00 +0000439 IllegalSetter,
440 0
441};
442
443
444//
445// Accessors::FunctionPrototype
446//
447
448
John Reck59135872010-11-02 12:39:01 -0700449MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100450 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000451 bool found_it = false;
452 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100453 if (!found_it) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100454 while (!function->should_have_prototype()) {
455 found_it = false;
456 function = FindInPrototypeChain<JSFunction>(object->GetPrototype(),
457 &found_it);
458 // There has to be one because we hit the getter.
459 ASSERT(found_it);
460 }
461
Steve Blocka7e24c12009-10-30 11:49:00 +0000462 if (!function->has_prototype()) {
John Reck59135872010-11-02 12:39:01 -0700463 Object* prototype;
Steve Block44f0eee2011-05-26 01:26:41 +0100464 { MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function);
John Reck59135872010-11-02 12:39:01 -0700465 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
466 }
467 Object* result;
468 { MaybeObject* maybe_result = function->SetPrototype(prototype);
469 if (!maybe_result->ToObject(&result)) return maybe_result;
470 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000471 }
472 return function->prototype();
473}
474
475
John Reck59135872010-11-02 12:39:01 -0700476MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
477 Object* value,
478 void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100479 Heap* heap = object->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000480 bool found_it = false;
481 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100482 if (!found_it) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100483 if (!function->should_have_prototype()) {
484 // Since we hit this accessor, object will have no prototype property.
Steve Block44f0eee2011-05-26 01:26:41 +0100485 return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100486 value,
487 NONE);
488 }
489
John Reck59135872010-11-02 12:39:01 -0700490 Object* prototype;
491 { MaybeObject* maybe_prototype = function->SetPrototype(value);
492 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
493 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000494 ASSERT(function->prototype() == value);
495 return function;
496}
497
498
499const AccessorDescriptor Accessors::FunctionPrototype = {
500 FunctionGetPrototype,
501 FunctionSetPrototype,
502 0
503};
504
505
506//
507// Accessors::FunctionLength
508//
509
510
John Reck59135872010-11-02 12:39:01 -0700511MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000512 bool found_it = false;
513 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
514 if (!found_it) return Smi::FromInt(0);
515 // Check if already compiled.
Iain Merrick75681382010-08-19 15:07:18 +0100516 if (!function->shared()->is_compiled()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000517 // If the function isn't compiled yet, the length is not computed
518 // correctly yet. Compile it now and return the right length.
519 HandleScope scope;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100520 Handle<JSFunction> handle(function);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100521 if (!JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) {
522 return Failure::Exception();
523 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100524 return Smi::FromInt(handle->shared()->length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000525 } else {
526 return Smi::FromInt(function->shared()->length());
527 }
528}
529
530
531const AccessorDescriptor Accessors::FunctionLength = {
532 FunctionGetLength,
533 ReadOnlySetAccessor,
534 0
535};
536
537
538//
539// Accessors::FunctionName
540//
541
542
John Reck59135872010-11-02 12:39:01 -0700543MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000544 bool found_it = false;
545 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100546 if (!found_it) return HEAP->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000547 return holder->shared()->name();
548}
549
550
551const AccessorDescriptor Accessors::FunctionName = {
552 FunctionGetName,
553 ReadOnlySetAccessor,
554 0
555};
556
557
558//
559// Accessors::FunctionArguments
560//
561
Ben Murdochb0fe1622011-05-05 13:52:32 +0100562
563static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
564 JavaScriptFrame* frame,
565 Handle<JSFunction> inlined_function,
566 int inlined_frame_index) {
Steve Block44f0eee2011-05-26 01:26:41 +0100567 Factory* factory = Isolate::Current()->factory();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100568 Vector<SlotRef> args_slots =
569 SlotRef::ComputeSlotMappingForArguments(
570 frame,
571 inlined_frame_index,
572 inlined_function->shared()->formal_parameter_count());
573 int args_count = args_slots.length();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100574 Handle<JSObject> arguments =
Steve Block44f0eee2011-05-26 01:26:41 +0100575 factory->NewArgumentsObject(inlined_function, args_count);
576 Handle<FixedArray> array = factory->NewFixedArray(args_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100577 for (int i = 0; i < args_count; ++i) {
578 Handle<Object> value = args_slots[i].GetValue();
579 array->set(i, *value);
580 }
581 arguments->set_elements(*array);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100582 args_slots.Dispose();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100583
584 // Return the freshly allocated arguments object.
585 return *arguments;
586}
587
Steve Blocka7e24c12009-10-30 11:49:00 +0000588
John Reck59135872010-11-02 12:39:01 -0700589MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100590 Isolate* isolate = Isolate::Current();
591 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000592 bool found_it = false;
593 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100594 if (!found_it) return isolate->heap()->undefined_value();
595 Handle<JSFunction> function(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000596
Ben Murdoch589d6972011-11-30 16:04:58 +0000597 if (function->shared()->native()) return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000598 // Find the top invocation of the function by traversing frames.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100599 List<JSFunction*> functions(2);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100600 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 JavaScriptFrame* frame = it.frame();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100602 frame->GetFunctions(&functions);
603 for (int i = functions.length() - 1; i >= 0; i--) {
604 // Skip all frames that aren't invocations of the given function.
605 if (functions[i] != *function) continue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000606
Ben Murdochb0fe1622011-05-05 13:52:32 +0100607 if (i > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +0100608 // The function in question was inlined. Inlined functions have the
609 // correct number of arguments and no allocated arguments object, so
610 // we can construct a fresh one by interpreting the function's
611 // deoptimization input data.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100612 return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
Steve Block1e0659c2011-05-24 12:43:12 +0100613 }
614
615 if (!frame->is_optimized()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100616 // If there is an arguments variable in the stack, we return that.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100617 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
618 int index = scope_info->StackSlotIndex(
619 isolate->heap()->arguments_symbol());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100620 if (index >= 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100621 Handle<Object> arguments(frame->GetExpression(index), isolate);
Ben Murdoch086aeea2011-05-13 15:57:08 +0100622 if (!arguments->IsArgumentsMarker()) return *arguments;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100623 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100624 }
Steve Block1e0659c2011-05-24 12:43:12 +0100625
626 // If there is no arguments variable in the stack or we have an
627 // optimized frame, we find the frame that holds the actual arguments
628 // passed to the function.
629 it.AdvanceToArgumentsFrame();
630 frame = it.frame();
631
632 // Get the number of arguments and construct an arguments object
633 // mirror for the right frame.
Steve Block44f0eee2011-05-26 01:26:41 +0100634 const int length = frame->ComputeParametersCount();
635 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
636 function, length);
637 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
Steve Block1e0659c2011-05-24 12:43:12 +0100638
639 // Copy the parameters to the arguments object.
640 ASSERT(array->length() == length);
641 for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
642 arguments->set_elements(*array);
643
644 // Return the freshly allocated arguments object.
645 return *arguments;
Steve Blocka7e24c12009-10-30 11:49:00 +0000646 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100647 functions.Rewind(0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000648 }
649
650 // No frame corresponding to the given function found. Return null.
Steve Block44f0eee2011-05-26 01:26:41 +0100651 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000652}
653
654
655const AccessorDescriptor Accessors::FunctionArguments = {
656 FunctionGetArguments,
657 ReadOnlySetAccessor,
658 0
659};
660
661
662//
663// Accessors::FunctionCaller
664//
665
666
Steve Block44f0eee2011-05-26 01:26:41 +0100667static MaybeObject* CheckNonStrictCallerOrThrow(
668 Isolate* isolate,
669 JSFunction* caller) {
670 DisableAssertNoAllocation enable_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100671 if (!caller->shared()->is_classic_mode()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100672 return isolate->Throw(
673 *isolate->factory()->NewTypeError("strict_caller",
674 HandleVector<Object>(NULL, 0)));
675 }
676 return caller;
677}
678
679
Ben Murdoch257744e2011-11-30 15:57:28 +0000680class FrameFunctionIterator {
681 public:
682 FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise)
683 : frame_iterator_(isolate),
684 functions_(2),
685 index_(0) {
686 GetFunctions();
687 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000688 JSFunction* next() {
689 if (functions_.length() == 0) return NULL;
690 JSFunction* next_function = functions_[index_];
691 index_--;
692 if (index_ < 0) {
693 GetFunctions();
694 }
695 return next_function;
696 }
697
698 // Iterate through functions until the first occurence of 'function'.
699 // Returns true if 'function' is found, and false if the iterator ends
700 // without finding it.
701 bool Find(JSFunction* function) {
702 JSFunction* next_function;
703 do {
704 next_function = next();
705 if (next_function == function) return true;
706 } while (next_function != NULL);
707 return false;
708 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000709
Ben Murdoch257744e2011-11-30 15:57:28 +0000710 private:
711 void GetFunctions() {
712 functions_.Rewind(0);
713 if (frame_iterator_.done()) return;
714 JavaScriptFrame* frame = frame_iterator_.frame();
715 frame->GetFunctions(&functions_);
716 ASSERT(functions_.length() > 0);
717 frame_iterator_.Advance();
718 index_ = functions_.length() - 1;
719 }
720 JavaScriptFrameIterator frame_iterator_;
721 List<JSFunction*> functions_;
722 int index_;
723};
724
725
John Reck59135872010-11-02 12:39:01 -0700726MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
Steve Block44f0eee2011-05-26 01:26:41 +0100727 Isolate* isolate = Isolate::Current();
728 HandleScope scope(isolate);
John Reck59135872010-11-02 12:39:01 -0700729 AssertNoAllocation no_alloc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000730 bool found_it = false;
731 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
Steve Block44f0eee2011-05-26 01:26:41 +0100732 if (!found_it) return isolate->heap()->undefined_value();
Ben Murdoch589d6972011-11-30 16:04:58 +0000733 if (holder->shared()->native()) return isolate->heap()->null_value();
Steve Block44f0eee2011-05-26 01:26:41 +0100734 Handle<JSFunction> function(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000735
Ben Murdoch257744e2011-11-30 15:57:28 +0000736 FrameFunctionIterator it(isolate, no_alloc);
737
738 // Find the function from the frames.
739 if (!it.Find(*function)) {
740 // No frame corresponding to the given function found. Return null.
741 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000742 }
743
Ben Murdoch257744e2011-11-30 15:57:28 +0000744 // Find previously called non-toplevel function.
745 JSFunction* caller;
746 do {
747 caller = it.next();
748 if (caller == NULL) return isolate->heap()->null_value();
749 } while (caller->shared()->is_toplevel());
750
751 // If caller is a built-in function and caller's caller is also built-in,
752 // use that instead.
753 JSFunction* potential_caller = caller;
754 while (potential_caller != NULL && potential_caller->IsBuiltin()) {
755 caller = potential_caller;
756 potential_caller = it.next();
757 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100758 // If caller is bound, return null. This is compatible with JSC, and
759 // allows us to make bound functions use the strict function map
760 // and its associated throwing caller and arguments.
761 if (caller->shared()->bound()) {
762 return isolate->heap()->null_value();
763 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000764 return CheckNonStrictCallerOrThrow(isolate, caller);
Steve Blocka7e24c12009-10-30 11:49:00 +0000765}
766
767
768const AccessorDescriptor Accessors::FunctionCaller = {
769 FunctionGetCaller,
770 ReadOnlySetAccessor,
771 0
772};
773
774
775//
776// Accessors::ObjectPrototype
777//
778
779
John Reck59135872010-11-02 12:39:01 -0700780MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000781 Object* current = receiver->GetPrototype();
782 while (current->IsJSObject() &&
783 JSObject::cast(current)->map()->is_hidden_prototype()) {
784 current = current->GetPrototype();
785 }
786 return current;
787}
788
789
John Reck59135872010-11-02 12:39:01 -0700790MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver,
791 Object* value,
792 void*) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000793 const bool skip_hidden_prototypes = true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000794 // To be consistent with other Set functions, return the value.
Andrei Popescu402d9372010-02-26 13:31:12 +0000795 return receiver->SetPrototype(value, skip_hidden_prototypes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000796}
797
798
799const AccessorDescriptor Accessors::ObjectPrototype = {
800 ObjectGetPrototype,
801 ObjectSetPrototype,
802 0
803};
804
805} } // namespace v8::internal