blob: b947399a4752cf732a62c716f046f203b297c193 [file] [log] [blame]
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000029#include "accessors.h"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000030
31#include "contexts.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "execution.h"
34#include "factory.h"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000035#include "frames-inl.h"
36#include "isolate.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000037#include "list-inl.h"
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000038#include "property-details.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
kasperl@chromium.org71affb52009-05-26 05:44:31 +000040namespace v8 {
41namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042
43
44template <class C>
45static C* FindInPrototypeChain(Object* obj, bool* found_it) {
46 ASSERT(!*found_it);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000047 Heap* heap = HEAP;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048 while (!Is<C>(obj)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000049 if (obj == heap->null_value()) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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.
lrn@chromium.org303ada72010-10-27 09:33:13 +000058MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059 UNREACHABLE();
60 return NULL;
61}
62
63
64Object* Accessors::IllegalGetAccessor(Object* object, void*) {
65 UNREACHABLE();
66 return object;
67}
68
69
lrn@chromium.org303ada72010-10-27 09:33:13 +000070MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
lrn@chromium.org303ada72010-10-27 09:33:13 +000082MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000095 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();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099 if (wrapper->map() == number_map) return wrapper->value();
100 return value;
101}
102
103
lrn@chromium.org303ada72010-10-27 09:33:13 +0000104MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000105 Isolate* isolate = object->GetIsolate();
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000106
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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115 value = FlattenNumber(value);
116
117 // Need to call methods that may trigger GC.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000118 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000119
120 // Protect raw pointers.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000121 Handle<JSObject> object_handle(object, isolate);
122 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000130 if (uint32_v->Number() == number_v->Number()) {
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000131 return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132 }
lrn@chromium.org7516f052011-03-30 08:52:27 +0000133 return isolate->Throw(
134 *isolate->factory()->NewRangeError("invalid_array_length",
135 HandleVector<Object>(NULL, 0)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136}
137
138
139const AccessorDescriptor Accessors::ArrayLength = {
140 ArrayGetLength,
141 ArraySetLength,
142 0
143};
144
145
146//
147// Accessors::StringLength
148//
149
150
lrn@chromium.org303ada72010-10-27 09:33:13 +0000151MaybeObject* Accessors::StringGetLength(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
lrn@chromium.org303ada72010-10-27 09:33:13 +0000173MaybeObject* Accessors::ScriptGetSource(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191MaybeObject* Accessors::ScriptGetName(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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//
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000205// Accessors::ScriptId
206//
207
208
lrn@chromium.org303ada72010-10-27 09:33:13 +0000209MaybeObject* Accessors::ScriptGetId(Object* object, void*) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +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//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000223// Accessors::ScriptLineOffset
224//
225
226
lrn@chromium.org303ada72010-10-27 09:33:13 +0000227MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
lrn@chromium.org303ada72010-10-27 09:33:13 +0000245MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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//
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000259// Accessors::ScriptData
260//
261
262
lrn@chromium.org303ada72010-10-27 09:33:13 +0000263MaybeObject* Accessors::ScriptGetData(Object* object, void*) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +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//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000277// Accessors::ScriptType
278//
279
280
lrn@chromium.org303ada72010-10-27 09:33:13 +0000281MaybeObject* Accessors::ScriptGetType(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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//
ager@chromium.orge2902be2009-06-08 12:21:35 +0000295// Accessors::ScriptCompilationType
296//
297
298
lrn@chromium.org303ada72010-10-27 09:33:13 +0000299MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
ager@chromium.orge2902be2009-06-08 12:21:35 +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//
iposva@chromium.org245aa852009-02-10 00:49:54 +0000313// Accessors::ScriptGetLineEnds
314//
315
316
lrn@chromium.org303ada72010-10-27 09:33:13 +0000317MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000318 JSValue* wrapper = JSValue::cast(object);
319 Isolate* isolate = wrapper->GetIsolate();
320 HandleScope scope(isolate);
321 Handle<Script> script(Script::cast(wrapper->value()), isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000322 InitScriptLineEnds(script);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000323 ASSERT(script->line_ends()->IsFixedArray());
324 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000325 // We do not want anyone to modify this array from JS.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000326 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);
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000330 return *js_array;
iposva@chromium.org245aa852009-02-10 00:49:54 +0000331}
332
333
334const AccessorDescriptor Accessors::ScriptLineEnds = {
335 ScriptGetLineEnds,
336 IllegalSetter,
337 0
338};
339
340
341//
ager@chromium.org9085a012009-05-11 19:22:57 +0000342// Accessors::ScriptGetContextData
343//
344
345
lrn@chromium.org303ada72010-10-27 09:33:13 +0000346MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000347 Object* script = JSValue::cast(object)->value();
348 return Script::cast(script)->context_data();
ager@chromium.org9085a012009-05-11 19:22:57 +0000349}
350
351
352const AccessorDescriptor Accessors::ScriptContextData = {
353 ScriptGetContextData,
354 IllegalSetter,
355 0
356};
357
358
359//
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000360// Accessors::ScriptGetEvalFromScript
ager@chromium.orge2902be2009-06-08 12:21:35 +0000361//
362
363
lrn@chromium.org303ada72010-10-27 09:33:13 +0000364MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
ager@chromium.orge2902be2009-06-08 12:21:35 +0000365 Object* script = JSValue::cast(object)->value();
sgjesse@chromium.org98180592009-12-02 08:17:28 +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 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000375 return HEAP->undefined_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +0000376}
377
378
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000379const AccessorDescriptor Accessors::ScriptEvalFromScript = {
380 ScriptGetEvalFromScript,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000381 IllegalSetter,
382 0
383};
384
385
386//
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000387// Accessors::ScriptGetEvalFromScriptPosition
ager@chromium.orge2902be2009-06-08 12:21:35 +0000388//
389
390
lrn@chromium.org303ada72010-10-27 09:33:13 +0000391MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
ager@chromium.orge2902be2009-06-08 12:21:35 +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) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000398 return HEAP->undefined_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +0000399 }
400
401 // Get the function from where eval was called and find the source position
402 // from the instruction offset.
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000403 Handle<Code> code(SharedFunctionInfo::cast(
404 script->eval_from_shared())->code());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000405 return Smi::FromInt(code->SourcePosition(code->instruction_start() +
406 script->eval_from_instructions_offset()->value()));
407}
408
409
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000410const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
411 ScriptGetEvalFromScriptPosition,
412 IllegalSetter,
413 0
414};
415
416
417//
418// Accessors::ScriptGetEvalFromFunctionName
419//
420
421
lrn@chromium.org303ada72010-10-27 09:33:13 +0000422MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
sgjesse@chromium.org98180592009-12-02 08:17:28 +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,
ager@chromium.orge2902be2009-06-08 12:21:35 +0000439 IllegalSetter,
440 0
441};
442
443
444//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445// Accessors::FunctionPrototype
446//
447
448
lrn@chromium.org303ada72010-10-27 09:33:13 +0000449MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000450 Heap* heap = Isolate::Current()->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000451 bool found_it = false;
452 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000453 if (!found_it) return heap->undefined_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000454 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462 if (!function->has_prototype()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000463 Object* prototype;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000464 { MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000465 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 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000471 }
472 return function->prototype();
473}
474
475
lrn@chromium.org303ada72010-10-27 09:33:13 +0000476MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
477 Object* value,
478 void*) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000479 Heap* heap = object->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000480 bool found_it = false;
481 JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000482 if (!found_it) return heap->undefined_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000483 if (!function->should_have_prototype()) {
484 // Since we hit this accessor, object will have no prototype property.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000485 return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000486 value,
487 NONE);
488 }
489
lrn@chromium.org303ada72010-10-27 09:33:13 +0000490 Object* prototype;
491 { MaybeObject* maybe_prototype = function->SetPrototype(value);
492 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
493 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
lrn@chromium.org303ada72010-10-27 09:33:13 +0000511MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000516 if (!function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000520 Handle<JSFunction> handle(function);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000521 if (!JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) {
522 return Failure::Exception();
523 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000524 return Smi::FromInt(handle->shared()->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
lrn@chromium.org303ada72010-10-27 09:33:13 +0000543MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544 bool found_it = false;
545 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 if (!found_it) return HEAP->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000562
563static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
564 JavaScriptFrame* frame,
565 Handle<JSFunction> inlined_function,
566 int inlined_frame_index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 Factory* factory = Isolate::Current()->factory();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000568 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();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000574 Handle<JSObject> arguments =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 factory->NewArgumentsObject(inlined_function, args_count);
576 Handle<FixedArray> array = factory->NewFixedArray(args_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000577 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);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000582 args_slots.Dispose();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000583
584 // Return the freshly allocated arguments object.
585 return *arguments;
586}
587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588
lrn@chromium.org303ada72010-10-27 09:33:13 +0000589MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000590 Isolate* isolate = Isolate::Current();
591 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000592 bool found_it = false;
593 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000594 if (!found_it) return isolate->heap()->undefined_value();
595 Handle<JSFunction> function(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000597 if (function->shared()->native()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000598 // Find the top invocation of the function by traversing frames.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000599 List<JSFunction*> functions(2);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000600 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000601 JavaScriptFrame* frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000602 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;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000606
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000607 if (i > 0) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000608 // 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.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000612 return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000613 }
614
615 if (!frame->is_optimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000616 // If there is an arguments variable in the stack, we return that.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000617 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
618 int index = scope_info->StackSlotIndex(
619 isolate->heap()->arguments_symbol());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000620 if (index >= 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 Handle<Object> arguments(frame->GetExpression(index), isolate);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000622 if (!arguments->IsArgumentsMarker()) return *arguments;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000623 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000624 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000625
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.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000634 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
636 function, length);
637 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000638
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;
ager@chromium.org3e875802009-06-29 08:26:34 +0000646 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000647 functions.Rewind(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648 }
649
650 // No frame corresponding to the given function found. Return null.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000651 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652}
653
654
655const AccessorDescriptor Accessors::FunctionArguments = {
656 FunctionGetArguments,
657 ReadOnlySetAccessor,
658 0
659};
660
661
662//
663// Accessors::FunctionCaller
664//
665
666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000667static MaybeObject* CheckNonStrictCallerOrThrow(
668 Isolate* isolate,
669 JSFunction* caller) {
670 DisableAssertNoAllocation enable_allocation;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000671 if (!caller->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000672 return isolate->Throw(
673 *isolate->factory()->NewTypeError("strict_caller",
674 HandleVector<Object>(NULL, 0)));
675 }
676 return caller;
677}
678
679
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000680class FrameFunctionIterator {
681 public:
682 FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise)
683 : frame_iterator_(isolate),
684 functions_(2),
685 index_(0) {
686 GetFunctions();
687 }
688 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 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000709
ricow@chromium.org4668a2c2011-08-29 10:41:00 +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
lrn@chromium.org303ada72010-10-27 09:33:13 +0000726MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000727 Isolate* isolate = Isolate::Current();
728 HandleScope scope(isolate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000729 AssertNoAllocation no_alloc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000730 bool found_it = false;
731 JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000732 if (!found_it) return isolate->heap()->undefined_value();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000733 if (holder->shared()->native()) return isolate->heap()->null_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000734 Handle<JSFunction> function(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735
ricow@chromium.org4668a2c2011-08-29 10:41:00 +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();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000742 }
743
ricow@chromium.org4668a2c2011-08-29 10:41:00 +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 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000758 // 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 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000764 return CheckNonStrictCallerOrThrow(isolate, caller);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000765}
766
767
768const AccessorDescriptor Accessors::FunctionCaller = {
769 FunctionGetCaller,
770 ReadOnlySetAccessor,
771 0
772};
773
774
775//
776// Accessors::ObjectPrototype
777//
778
779
lrn@chromium.org303ada72010-10-27 09:33:13 +0000780MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
lrn@chromium.org303ada72010-10-27 09:33:13 +0000790MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver,
791 Object* value,
792 void*) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000793 const bool skip_hidden_prototypes = true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000794 // To be consistent with other Set functions, return the value.
ager@chromium.org5c838252010-02-19 08:53:10 +0000795 return receiver->SetPrototype(value, skip_hidden_prototypes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000796}
797
798
799const AccessorDescriptor Accessors::ObjectPrototype = {
800 ObjectGetPrototype,
801 ObjectSetPrototype,
802 0
803};
804
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000805
806//
807// Accessors::MakeModuleExport
808//
809
810static v8::Handle<v8::Value> ModuleGetExport(
811 v8::Local<v8::String> property,
812 const v8::AccessorInfo& info) {
813 JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder()));
814 Context* context = Context::cast(instance->context());
815 ASSERT(context->IsModuleContext());
816 int slot = info.Data()->Int32Value();
817 Object* value = context->get(slot);
818 if (value->IsTheHole()) {
819 Handle<String> name = v8::Utils::OpenHandle(*property);
820 Isolate* isolate = instance->GetIsolate();
821 isolate->ScheduleThrow(
822 *isolate->factory()->NewReferenceError("not_defined",
823 HandleVector(&name, 1)));
824 return v8::Handle<v8::Value>();
825 }
826 return v8::Utils::ToLocal(Handle<Object>(value));
827}
828
829
830static void ModuleSetExport(
831 v8::Local<v8::String> property,
832 v8::Local<v8::Value> value,
833 const v8::AccessorInfo& info) {
834 JSModule* instance = JSModule::cast(*v8::Utils::OpenHandle(*info.Holder()));
835 Context* context = Context::cast(instance->context());
836 ASSERT(context->IsModuleContext());
837 int slot = info.Data()->Int32Value();
838 Object* old_value = context->get(slot);
839 if (old_value->IsTheHole()) {
840 Handle<String> name = v8::Utils::OpenHandle(*property);
841 Isolate* isolate = instance->GetIsolate();
842 isolate->ScheduleThrow(
843 *isolate->factory()->NewReferenceError("not_defined",
844 HandleVector(&name, 1)));
845 return;
846 }
847 context->set(slot, *v8::Utils::OpenHandle(*value));
848}
849
850
851Handle<AccessorInfo> Accessors::MakeModuleExport(
852 Handle<String> name,
853 int index,
854 PropertyAttributes attributes) {
855 Factory* factory = name->GetIsolate()->factory();
856 Handle<AccessorInfo> info = factory->NewAccessorInfo();
857 info->set_property_attributes(attributes);
858 info->set_all_can_read(true);
859 info->set_all_can_write(true);
860 info->set_name(*name);
861 info->set_data(Smi::FromInt(index));
862 Handle<Object> getter = v8::FromCData(&ModuleGetExport);
863 Handle<Object> setter = v8::FromCData(&ModuleSetExport);
864 info->set_getter(*getter);
865 if (!(attributes & ReadOnly)) info->set_setter(*setter);
866 return info;
867}
868
869
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870} } // namespace v8::internal