blob: d9c5bedc8ba216c5792bd9faed371f235bf174f5 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +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 <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072#define CONVERT_ARG_CHECKED(Type, name, index) \
73 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000074 Type* name = Type::cast(args[index]);
75
76#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000083#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
84 RUNTIME_ASSERT(args[index]->IsBoolean()); \
85 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000086
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000109// Cast the given argument to PropertyDetails and store its value in a
110// variable with the given name. If the argument is not a Smi call
111// IllegalOperation and return.
112#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
113 RUNTIME_ASSERT(args[index]->IsSmi()); \
114 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
115
116
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000117// Assert that the given argument has a valid value for a StrictModeFlag
118// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000119#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
120 RUNTIME_ASSERT(args[index]->IsSmi()); \
121 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
122 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000123 StrictModeFlag name = \
124 static_cast<StrictModeFlag>(args.smi_at(index));
125
126
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000127// Assert that the given argument has a valid value for a LanguageMode
128// and store it in a LanguageMode variable with the given name.
129#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
130 ASSERT(args[index]->IsSmi()); \
131 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
132 args.smi_at(index) == STRICT_MODE || \
133 args.smi_at(index) == EXTENDED_MODE); \
134 LanguageMode name = \
135 static_cast<LanguageMode>(args.smi_at(index));
136
137
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
139 JSObject* boilerplate) {
140 StackLimitCheck check(isolate);
141 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 if (!maybe_result->ToObject(&result)) return maybe_result;
147 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 JSObject* copy = JSObject::cast(result);
149
150 // Deep copy local properties.
151 if (copy->HasFastProperties()) {
152 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 for (int i = 0; i < properties->length(); i++) {
154 Object* value = properties->get(i);
155 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 if (!maybe_result->ToObject(&result)) return maybe_result;
159 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000161 }
162 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000163 int nof = copy->map()->inobject_properties();
164 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 Object* value = copy->InObjectPropertyAt(i);
166 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000167 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000171 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 }
173 }
174 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000175 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000176 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000177 if (!maybe_result->ToObject(&result)) return maybe_result;
178 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000179 FixedArray* names = FixedArray::cast(result);
180 copy->GetLocalPropertyNames(names, 0);
181 for (int i = 0; i < names->length(); i++) {
182 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000183 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000186 // Only deep copy fields from the object literal expression.
187 // In particular, don't try to copy the length attribute of
188 // an array.
189 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000190 Object* value =
191 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000192 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000193 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 if (!maybe_result->ToObject(&result)) return maybe_result;
196 }
197 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000198 // Creating object copy for literals. No strict mode needed.
199 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000200 if (!maybe_result->ToObject(&result)) return maybe_result;
201 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000202 }
203 }
204 }
205
206 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000207 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000208 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000210 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000211 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000212 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 if (elements->map() == heap->fixed_cow_array_map()) {
214 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000215#ifdef DEBUG
216 for (int i = 0; i < elements->length(); i++) {
217 ASSERT(!elements->get(i)->IsJSObject());
218 }
219#endif
220 } else {
221 for (int i = 0; i < elements->length(); i++) {
222 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000223 ASSERT(value->IsSmi() ||
224 value->IsTheHole() ||
225 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000226 if (value->IsJSObject()) {
227 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
229 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000230 if (!maybe_result->ToObject(&result)) return maybe_result;
231 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000232 elements->set(i, result);
233 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000234 }
235 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000236 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000237 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000238 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000239 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000240 int capacity = element_dictionary->Capacity();
241 for (int i = 0; i < capacity; i++) {
242 Object* k = element_dictionary->KeyAt(i);
243 if (element_dictionary->IsKey(k)) {
244 Object* value = element_dictionary->ValueAt(i);
245 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000246 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000247 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
248 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000249 if (!maybe_result->ToObject(&result)) return maybe_result;
250 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000251 element_dictionary->ValueAtPut(i, result);
252 }
253 }
254 }
255 break;
256 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000257 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000258 UNIMPLEMENTED();
259 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000260 case EXTERNAL_PIXEL_ELEMENTS:
261 case EXTERNAL_BYTE_ELEMENTS:
262 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
263 case EXTERNAL_SHORT_ELEMENTS:
264 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
265 case EXTERNAL_INT_ELEMENTS:
266 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
267 case EXTERNAL_FLOAT_ELEMENTS:
268 case EXTERNAL_DOUBLE_ELEMENTS:
269 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000270 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000271 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000272 }
273 return copy;
274}
275
276
ager@chromium.org236ad962008-09-25 09:45:57 +0000277static Handle<Map> ComputeObjectLiteralMap(
278 Handle<Context> context,
279 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000282 int properties_length = constant_properties->length();
283 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000284 // Check that there are only symbols and array indices among keys.
285 int number_of_symbol_keys = 0;
286 for (int p = 0; p != properties_length; p += 2) {
287 Object* key = constant_properties->get(p);
288 uint32_t element_index = 0;
289 if (key->IsSymbol()) {
290 number_of_symbol_keys++;
291 } else if (key->ToArrayIndex(&element_index)) {
292 // An index key does not require space in the property backing store.
293 number_of_properties--;
294 } else {
295 // Bail out as a non-symbol non-index key makes caching impossible.
296 // ASSERT to make sure that the if condition after the loop is false.
297 ASSERT(number_of_symbol_keys != number_of_properties);
298 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000300 }
301 // If we only have symbols and array indices among keys then we can
302 // use the map cache in the global context.
303 const int kMaxKeys = 10;
304 if ((number_of_symbol_keys == number_of_properties) &&
305 (number_of_symbol_keys < kMaxKeys)) {
306 // Create the fixed array with the key.
307 Handle<FixedArray> keys =
308 isolate->factory()->NewFixedArray(number_of_symbol_keys);
309 if (number_of_symbol_keys > 0) {
310 int index = 0;
311 for (int p = 0; p < properties_length; p += 2) {
312 Object* key = constant_properties->get(p);
313 if (key->IsSymbol()) {
314 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000315 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000316 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000317 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000318 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000319 *is_result_from_cache = true;
320 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000321 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000322 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000323 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000324 Handle<Map>(context->object_function()->initial_map()),
325 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000326}
327
328
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
332 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000333
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000334
335static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000336 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000337 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000338 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000339 bool should_have_fast_elements,
340 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000341 // Get the global context from the literals array. This is the
342 // context in which the function was created and we use the object
343 // function from this context to create the object literal. We do
344 // not use the object function from the current global context
345 // because this might be the object function from another context
346 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000347 Handle<Context> context =
348 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000350 // In case we have function literals, we want the object to be in
351 // slow properties mode for now. We don't go in the map cache because
352 // maps with constant functions can't be shared if the functions are
353 // not the same (which is the common case).
354 bool is_result_from_cache = false;
355 Handle<Map> map = has_function_literal
356 ? Handle<Map>(context->object_function()->initial_map())
357 : ComputeObjectLiteralMap(context,
358 constant_properties,
359 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000362
363 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000364 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000365
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 // Add the constant properties to the boilerplate.
367 int length = constant_properties->length();
368 bool should_transform =
369 !is_result_from_cache && boilerplate->HasFastProperties();
370 if (should_transform || has_function_literal) {
371 // Normalize the properties of object to avoid n^2 behavior
372 // when extending the object multiple properties. Indicate the number of
373 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000374 JSObject::NormalizeProperties(
375 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 }
377
378 for (int index = 0; index < length; index +=2) {
379 Handle<Object> key(constant_properties->get(index+0), isolate);
380 Handle<Object> value(constant_properties->get(index+1), isolate);
381 if (value->IsFixedArray()) {
382 // The value contains the constant_properties of a
383 // simple object or array literal.
384 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
385 value = CreateLiteralBoilerplate(isolate, literals, array);
386 if (value.is_null()) return value;
387 }
388 Handle<Object> result;
389 uint32_t element_index = 0;
390 if (key->IsSymbol()) {
391 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
392 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000393 result = JSObject::SetOwnElement(
394 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 Handle<String> name(String::cast(*key));
397 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000398 result = JSObject::SetLocalPropertyIgnoreAttributes(
399 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401 } else if (key->ToArrayIndex(&element_index)) {
402 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000403 result = JSObject::SetOwnElement(
404 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 } else {
406 // Non-uint32 number.
407 ASSERT(key->IsNumber());
408 double num = key->Number();
409 char arr[100];
410 Vector<char> buffer(arr, ARRAY_SIZE(arr));
411 const char* str = DoubleToCString(num, buffer);
412 Handle<String> name =
413 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000414 result = JSObject::SetLocalPropertyIgnoreAttributes(
415 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 // If setting the property on the boilerplate throws an
418 // exception, the exception is converted to an empty handle in
419 // the handle based operations. In that case, we need to
420 // convert back to an exception.
421 if (result.is_null()) return result;
422 }
423
424 // Transform to fast properties if necessary. For object literals with
425 // containing function literals we defer this operation until after all
426 // computed properties have been assigned so that we can generate
427 // constant function properties.
428 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000429 JSObject::TransformToFastProperties(
430 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431 }
432
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000433 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000434}
435
436
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000437MaybeObject* TransitionElements(Handle<Object> object,
438 ElementsKind to_kind,
439 Isolate* isolate) {
440 HandleScope scope(isolate);
441 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
442 ElementsKind from_kind =
443 Handle<JSObject>::cast(object)->map()->elements_kind();
444 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
445 Handle<Object> result = JSObject::TransitionElementsKind(
446 Handle<JSObject>::cast(object), to_kind);
447 if (result.is_null()) return isolate->ThrowIllegalOperation();
448 return *result;
449 }
450 return isolate->ThrowIllegalOperation();
451}
452
453
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000454static const int kSmiOnlyLiteralMinimumLength = 1024;
455
456
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000457Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000458 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000459 Handle<FixedArray> literals,
460 Handle<FixedArray> elements) {
461 // Create the JSArray.
462 Handle<JSFunction> constructor(
463 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 Handle<JSArray> object =
465 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000467 ElementsKind constant_elements_kind =
468 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
469 Handle<FixedArrayBase> constant_elements_values(
470 FixedArrayBase::cast(elements->get(1)));
471
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000472 Context* global_context = isolate->context()->global_context();
473 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
474 object->set_map(Map::cast(global_context->smi_js_array_map()));
475 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 object->set_map(Map::cast(global_context->double_js_array_map()));
477 } else {
478 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000479 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000480
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000481 Handle<FixedArrayBase> copied_elements_values;
482 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
483 ASSERT(FLAG_smi_only_arrays);
484 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
485 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000486 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000487 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
488 constant_elements_kind == FAST_ELEMENTS);
489 const bool is_cow =
490 (constant_elements_values->map() ==
491 isolate->heap()->fixed_cow_array_map());
492 if (is_cow) {
493 copied_elements_values = constant_elements_values;
494#if DEBUG
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(copied_elements_values);
497 for (int i = 0; i < fixed_array_values->length(); i++) {
498 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
499 }
500#endif
501 } else {
502 Handle<FixedArray> fixed_array_values =
503 Handle<FixedArray>::cast(constant_elements_values);
504 Handle<FixedArray> fixed_array_values_copy =
505 isolate->factory()->CopyFixedArray(fixed_array_values);
506 copied_elements_values = fixed_array_values_copy;
507 for (int i = 0; i < fixed_array_values->length(); i++) {
508 Object* current = fixed_array_values->get(i);
509 if (current->IsFixedArray()) {
510 // The value contains the constant_properties of a
511 // simple object or array literal.
512 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
513 Handle<Object> result =
514 CreateLiteralBoilerplate(isolate, literals, fa);
515 if (result.is_null()) return result;
516 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000517 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000518 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000519 }
520 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000521 object->set_elements(*copied_elements_values);
522 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000523
524 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
525 // on or the object is larger than the threshold.
526 if (!FLAG_smi_only_arrays &&
527 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
528 if (object->GetElementsKind() != FAST_ELEMENTS) {
529 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
530 }
531 }
532
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000533 return object;
534}
535
536
537static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 Handle<FixedArray> literals,
540 Handle<FixedArray> array) {
541 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000542 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000543 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000544 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return CreateObjectLiteralBoilerplate(isolate,
546 literals,
547 elements,
548 true,
549 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000550 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 return CreateObjectLiteralBoilerplate(isolate,
552 literals,
553 elements,
554 false,
555 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000556 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000557 return Runtime::CreateArrayLiteralBoilerplate(
558 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000559 default:
560 UNREACHABLE();
561 return Handle<Object>::null();
562 }
563}
564
565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000566RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000568 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000569 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000570 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000571 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000572 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000573 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
574 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateObjectLiteralBoilerplate(isolate,
580 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000581 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 should_have_fast_elements,
583 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584 if (boilerplate.is_null()) return Failure::Exception();
585 // Update the functions literal and return the boilerplate.
586 literals->set(literals_index, *boilerplate);
587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000594 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000595 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000596 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000597 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000598 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
600 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601
602 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 Handle<Object> boilerplate(literals->get(literals_index), isolate);
604 if (*boilerplate == isolate->heap()->undefined_value()) {
605 boilerplate = CreateObjectLiteralBoilerplate(isolate,
606 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000607 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 should_have_fast_elements,
609 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000610 if (boilerplate.is_null()) return Failure::Exception();
611 // Update the functions literal and return the boilerplate.
612 literals->set(literals_index, *boilerplate);
613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000615}
616
617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000620 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000621 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000622 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000623 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624
625 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Handle<Object> boilerplate(literals->get(literals_index), isolate);
627 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000628 boilerplate =
629 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000630 if (boilerplate.is_null()) return Failure::Exception();
631 // Update the functions literal and return the boilerplate.
632 literals->set(literals_index, *boilerplate);
633 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000634 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000635}
636
637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000638RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000640 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000641 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000642 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000643 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000644
645 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000646 Handle<Object> boilerplate(literals->get(literals_index), isolate);
647 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000648 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000649 boilerplate =
650 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000651 if (boilerplate.is_null()) return Failure::Exception();
652 // Update the functions literal and return the boilerplate.
653 literals->set(literals_index, *boilerplate);
654 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000655 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000656 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000657 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000658 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000659 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000660}
661
662
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000663RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
664 ASSERT(args.length() == 2);
665 Object* handler = args[0];
666 Object* prototype = args[1];
667 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000668 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000669 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
670}
671
672
lrn@chromium.org34e60782011-09-15 07:25:40 +0000673RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
674 ASSERT(args.length() == 4);
675 Object* handler = args[0];
676 Object* call_trap = args[1];
677 Object* construct_trap = args[2];
678 Object* prototype = args[3];
679 Object* used_prototype =
680 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
681 return isolate->heap()->AllocateJSFunctionProxy(
682 handler, call_trap, construct_trap, used_prototype);
683}
684
685
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000686RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
687 ASSERT(args.length() == 1);
688 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000689 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000690}
691
692
lrn@chromium.org34e60782011-09-15 07:25:40 +0000693RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
694 ASSERT(args.length() == 1);
695 Object* obj = args[0];
696 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
697}
698
699
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000700RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
701 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000702 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000703 return proxy->handler();
704}
705
706
lrn@chromium.org34e60782011-09-15 07:25:40 +0000707RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
708 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000709 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000710 return proxy->call_trap();
711}
712
713
714RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
715 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000716 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000717 return proxy->construct_trap();
718}
719
720
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000721RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
722 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000723 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000724 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000725 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000726}
727
728
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000729RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
730 HandleScope scope(isolate);
731 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000732 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000733 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
734 holder->set_table(*table);
735 return *holder;
736}
737
738
739RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
740 HandleScope scope(isolate);
741 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000742 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000743 Handle<Object> key(args[1]);
744 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
745 table = ObjectHashSetAdd(table, key);
746 holder->set_table(*table);
747 return isolate->heap()->undefined_symbol();
748}
749
750
751RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
752 HandleScope scope(isolate);
753 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000754 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000755 Handle<Object> key(args[1]);
756 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
757 return isolate->heap()->ToBoolean(table->Contains(*key));
758}
759
760
761RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
762 HandleScope scope(isolate);
763 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000764 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000765 Handle<Object> key(args[1]);
766 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
767 table = ObjectHashSetRemove(table, key);
768 holder->set_table(*table);
769 return isolate->heap()->undefined_symbol();
770}
771
772
773RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
774 HandleScope scope(isolate);
775 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000776 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000777 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
778 holder->set_table(*table);
779 return *holder;
780}
781
782
783RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
784 HandleScope scope(isolate);
785 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000786 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000787 Handle<Object> key(args[1]);
788 return ObjectHashTable::cast(holder->table())->Lookup(*key);
789}
790
791
792RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
793 HandleScope scope(isolate);
794 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000795 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000796 Handle<Object> key(args[1]);
797 Handle<Object> value(args[2]);
798 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
799 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
800 holder->set_table(*new_table);
801 return *value;
802}
803
804
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000805RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
806 HandleScope scope(isolate);
807 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000808 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000809 ASSERT(weakmap->map()->inobject_properties() == 0);
810 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
811 weakmap->set_table(*table);
812 weakmap->set_next(Smi::FromInt(0));
813 return *weakmap;
814}
815
816
817RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
818 NoHandleAllocation ha;
819 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000820 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
821 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000823}
824
825
826RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
827 HandleScope scope(isolate);
828 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000829 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
830 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000831 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000832 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000833 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
834 weakmap->set_table(*new_table);
835 return *value;
836}
837
838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000839RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 NoHandleAllocation ha;
841 ASSERT(args.length() == 1);
842 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000843 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000844 return JSObject::cast(obj)->class_name();
845}
846
ager@chromium.org7c537e22008-10-16 08:43:32 +0000847
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000848RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
849 NoHandleAllocation ha;
850 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000851 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000852 Object* obj = input_obj;
853 // We don't expect access checks to be needed on JSProxy objects.
854 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000855 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000856 if (obj->IsAccessCheckNeeded() &&
857 !isolate->MayNamedAccess(JSObject::cast(obj),
858 isolate->heap()->Proto_symbol(),
859 v8::ACCESS_GET)) {
860 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
861 return isolate->heap()->undefined_value();
862 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000863 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000864 } while (obj->IsJSObject() &&
865 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000866 return obj;
867}
868
869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000870RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 NoHandleAllocation ha;
872 ASSERT(args.length() == 2);
873 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
874 Object* O = args[0];
875 Object* V = args[1];
876 while (true) {
877 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000878 if (prototype->IsNull()) return isolate->heap()->false_value();
879 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 V = prototype;
881 }
882}
883
884
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000885// Recursively traverses hidden prototypes if property is not found
886static void GetOwnPropertyImplementation(JSObject* obj,
887 String* name,
888 LookupResult* result) {
889 obj->LocalLookupRealNamedProperty(name, result);
890
891 if (!result->IsProperty()) {
892 Object* proto = obj->GetPrototype();
893 if (proto->IsJSObject() &&
894 JSObject::cast(proto)->map()->is_hidden_prototype())
895 GetOwnPropertyImplementation(JSObject::cast(proto),
896 name, result);
897 }
898}
899
900
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000901static bool CheckAccessException(LookupResult* result,
902 v8::AccessType access_type) {
903 if (result->type() == CALLBACKS) {
904 Object* callback = result->GetCallbackObject();
905 if (callback->IsAccessorInfo()) {
906 AccessorInfo* info = AccessorInfo::cast(callback);
907 bool can_access =
908 (access_type == v8::ACCESS_HAS &&
909 (info->all_can_read() || info->all_can_write())) ||
910 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
911 (access_type == v8::ACCESS_SET && info->all_can_write());
912 return can_access;
913 }
914 }
915
916 return false;
917}
918
919
920static bool CheckAccess(JSObject* obj,
921 String* name,
922 LookupResult* result,
923 v8::AccessType access_type) {
924 ASSERT(result->IsProperty());
925
926 JSObject* holder = result->holder();
927 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000929 while (true) {
930 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 // Access check callback denied the access, but some properties
933 // can have a special permissions which override callbacks descision
934 // (currently see v8::AccessControl).
935 break;
936 }
937
938 if (current == holder) {
939 return true;
940 }
941
942 current = JSObject::cast(current->GetPrototype());
943 }
944
945 // API callbacks can have per callback access exceptions.
946 switch (result->type()) {
947 case CALLBACKS: {
948 if (CheckAccessException(result, access_type)) {
949 return true;
950 }
951 break;
952 }
953 case INTERCEPTOR: {
954 // If the object has an interceptor, try real named properties.
955 // Overwrite the result to fetch the correct property later.
956 holder->LookupRealNamedProperty(name, result);
957 if (result->IsProperty()) {
958 if (CheckAccessException(result, access_type)) {
959 return true;
960 }
961 }
962 break;
963 }
964 default:
965 break;
966 }
967
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000969 return false;
970}
971
972
973// TODO(1095): we should traverse hidden prototype hierachy as well.
974static bool CheckElementAccess(JSObject* obj,
975 uint32_t index,
976 v8::AccessType access_type) {
977 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000978 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000979 return false;
980 }
981
982 return true;
983}
984
985
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000986// Enumerator used as indices into the array returned from GetOwnProperty
987enum PropertyDescriptorIndices {
988 IS_ACCESSOR_INDEX,
989 VALUE_INDEX,
990 GETTER_INDEX,
991 SETTER_INDEX,
992 WRITABLE_INDEX,
993 ENUMERABLE_INDEX,
994 CONFIGURABLE_INDEX,
995 DESCRIPTOR_SIZE
996};
997
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000998// Returns an array with the property description:
999// if args[1] is not a property on args[0]
1000// returns undefined
1001// if args[1] is a data property on args[0]
1002// [false, value, Writeable, Enumerable, Configurable]
1003// if args[1] is an accessor on args[0]
1004// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001005RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001006 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001007 Heap* heap = isolate->heap();
1008 HandleScope scope(isolate);
1009 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1010 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001011 LookupResult result(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001012 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1013 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001014
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001015 // This could be an element.
1016 uint32_t index;
1017 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001018 switch (obj->HasLocalElement(index)) {
1019 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001021
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001022 case JSObject::STRING_CHARACTER_ELEMENT: {
1023 // Special handling of string objects according to ECMAScript 5
1024 // 15.5.5.2. Note that this might be a string object with elements
1025 // other than the actual string value. This is covered by the
1026 // subsequent cases.
1027 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1028 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001029 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001031 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001032 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(WRITABLE_INDEX, heap->false_value());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001034 elms->set(ENUMERABLE_INDEX, heap->true_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001036 return *desc;
1037 }
1038
1039 case JSObject::INTERCEPTED_ELEMENT:
1040 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001041 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001042 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001043 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001044 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001045 elms->set(WRITABLE_INDEX, heap->true_value());
1046 elms->set(ENUMERABLE_INDEX, heap->true_value());
1047 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001048 return *desc;
1049 }
1050
1051 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001052 Handle<JSObject> holder = obj;
1053 if (obj->IsJSGlobalProxy()) {
1054 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001055 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001056 ASSERT(proto->IsJSGlobalObject());
1057 holder = Handle<JSObject>(JSObject::cast(proto));
1058 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001059 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001060 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001061 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001062 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001063 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001064 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001065 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001066 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001067 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001068 PropertyDetails details = dictionary->DetailsAt(entry);
1069 switch (details.type()) {
1070 case CALLBACKS: {
1071 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001072 AccessorPair* accessors =
1073 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001075 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001076 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001077 }
1078 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001079 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001080 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001081 break;
1082 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001083 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001085 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001086 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001087 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001088 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001091 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001092 default:
1093 UNREACHABLE();
1094 break;
1095 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001096 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1097 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001098 return *desc;
1099 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001100 }
1101 }
1102
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001103 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001104 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001105
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001106 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001107 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001108 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001109
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001110 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001111 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001112 }
1113
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1115 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001116
1117 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001118 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001119
1120 if (is_js_accessor) {
1121 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001122 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001123
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001124 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001125 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001126 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001127 }
1128 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001129 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001130 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001131 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001132 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1133 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001134
1135 PropertyAttributes attrs;
1136 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001137 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001138 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1139 if (!maybe_value->ToObject(&value)) return maybe_value;
1140 }
1141 elms->set(VALUE_INDEX, value);
1142 }
1143
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001144 return *desc;
1145}
1146
1147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001148RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001149 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001150 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001151 return obj->PreventExtensions();
1152}
1153
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001155RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001156 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001157 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001158 if (obj->IsJSGlobalProxy()) {
1159 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001161 ASSERT(proto->IsJSGlobalObject());
1162 obj = JSObject::cast(proto);
1163 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001164 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001165}
1166
1167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001168RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001169 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001171 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1172 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1173 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001174 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1175 if (result.is_null()) return Failure::Exception();
1176 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177}
1178
1179
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001180RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001181 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001183 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001184 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185}
1186
1187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001188RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 ASSERT(args.length() == 1);
1190 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001191 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001196RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001198 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1199 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001200 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1201 InstanceType type = templ->map()->instance_type();
1202 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1203 type == OBJECT_TEMPLATE_INFO_TYPE);
1204 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001205 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001206 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1207 } else {
1208 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1209 }
1210 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211}
1212
1213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001214RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001215 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001216 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001217 Map* old_map = object->map();
1218 bool needs_access_checks = old_map->is_access_check_needed();
1219 if (needs_access_checks) {
1220 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001221 Object* new_map;
1222 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1223 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1224 }
ager@chromium.org32912102009-01-16 10:38:43 +00001225
1226 Map::cast(new_map)->set_is_access_check_needed(false);
1227 object->set_map(Map::cast(new_map));
1228 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001229 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001230}
1231
1232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001233RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001234 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001235 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001236 Map* old_map = object->map();
1237 if (!old_map->is_access_check_needed()) {
1238 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001239 Object* new_map;
1240 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1241 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1242 }
ager@chromium.org32912102009-01-16 10:38:43 +00001243
1244 Map::cast(new_map)->set_is_access_check_needed(true);
1245 object->set_map(Map::cast(new_map));
1246 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001248}
1249
1250
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001251static Failure* ThrowRedeclarationError(Isolate* isolate,
1252 const char* type,
1253 Handle<String> name) {
1254 HandleScope scope(isolate);
1255 Handle<Object> type_handle =
1256 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 Handle<Object> args[2] = { type_handle, name };
1258 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1260 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261}
1262
1263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001264RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001265 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001266 HandleScope scope(isolate);
1267 Handle<GlobalObject> global = Handle<GlobalObject>(
1268 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269
ager@chromium.org3811b432009-10-28 14:53:37 +00001270 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001271 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001272 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 // Traverse the name/value pairs and set the properties.
1275 int length = pairs->length();
1276 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001279 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280
1281 // We have to declare a global const property. To capture we only
1282 // assign to it when evaluating the assignment for "const x =
1283 // <expr>" the initial value is the hole.
1284 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001285 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 if (value->IsUndefined() || is_const_property) {
1287 // Lookup the property in the global object, and don't set the
1288 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001289 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290 global->Lookup(*name, &lookup);
1291 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001292 // We found an existing property. Unless it was an interceptor
1293 // that claims the property is absent, skip this declaration.
1294 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295 continue;
1296 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001297 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1298 if (attributes != ABSENT) {
1299 continue;
1300 }
1301 // Fall-through and introduce the absent property by using
1302 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 }
1304 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001305 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001306 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001307 Handle<SharedFunctionInfo> shared =
1308 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1311 context,
1312 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313 value = function;
1314 }
1315
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001316 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 global->LocalLookup(*name, &lookup);
1318
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001319 // Compute the property attributes. According to ECMA-262, section
1320 // 13, page 71, the property must be read-only and
1321 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1322 // property as read-only, so we don't either.
1323 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001324 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001325 attr |= DONT_DELETE;
1326 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001327 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001328 if (is_const_property || (is_native && is_function_declaration)) {
1329 attr |= READ_ONLY;
1330 }
1331
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001332 // Safari does not allow the invocation of callback setters for
1333 // function declarations. To mimic this behavior, we do not allow
1334 // the invocation of setters for function values. This makes a
1335 // difference for global functions with the same names as event
1336 // handlers such as "function onload() {}". Firefox does call the
1337 // onload setter in those case and Safari does not. We follow
1338 // Safari for compatibility.
1339 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001340 // Do not change DONT_DELETE to false from true.
1341 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001342 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001343 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001344 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1345
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001346 RETURN_IF_EMPTY_HANDLE(
1347 isolate,
1348 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1349 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001351 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1352 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1353 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001354 RETURN_IF_EMPTY_HANDLE(
1355 isolate,
1356 JSReceiver::SetProperty(global, name, value,
1357 static_cast<PropertyAttributes>(attr),
1358 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 }
1360 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001362 ASSERT(!isolate->has_pending_exception());
1363 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364}
1365
1366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001367RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001368 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001369 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001371 // Declarations are always made in a function or global context. In the
1372 // case of eval code, the context passed is the context of the caller,
1373 // which may be some nested context and not the declaration context.
1374 RUNTIME_ASSERT(args[0]->IsContext());
1375 Handle<Context> context(Context::cast(args[0])->declaration_context());
1376
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001378 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001379 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001380 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382 int index;
1383 PropertyAttributes attributes;
1384 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001385 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001386 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001387 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388
1389 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001390 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1392 // Functions are not read-only.
1393 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1394 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001395 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396 }
1397
1398 // Initialize it if necessary.
1399 if (*initial_value != NULL) {
1400 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 ASSERT(holder.is_identical_to(context));
1402 if (((attributes & READ_ONLY) == 0) ||
1403 context->get(index)->IsTheHole()) {
1404 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405 }
1406 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // Slow case: The property is in the context extension object of a
1408 // function context or the global object of a global context.
1409 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001410 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001411 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001412 JSReceiver::SetProperty(object, name, initial_value, mode,
1413 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001414 }
1415 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001416
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001418 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001419 // "declared" in the function context's extension context or as a
1420 // property of the the global object.
1421 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001422 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001423 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001424 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001425 // Context extension objects are allocated lazily.
1426 ASSERT(context->IsFunctionContext());
1427 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001429 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001430 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001431 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001432
ager@chromium.org7c537e22008-10-16 08:43:32 +00001433 // Declare the property by setting it to the initial value if provided,
1434 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1435 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001437 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001438 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001439 // Declaring a const context slot is a conflicting declaration if
1440 // there is a callback with that name in a prototype. It is
1441 // allowed to introduce const variables in
1442 // JSContextExtensionObjects. They are treated specially in
1443 // SetProperty and no setters are invoked for those since they are
1444 // not real JSObjects.
1445 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001446 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001447 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001448 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001449 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001450 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001451 }
1452 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001453 RETURN_IF_EMPTY_HANDLE(
1454 isolate,
1455 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001456 }
1457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459}
1460
1461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001462RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001464 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001465 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001466 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467
1468 // Determine if we need to assign to the variable if it already
1469 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001470 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1471 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001473 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001474 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001475 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001476 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1477 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1478 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479
1480 // According to ECMA-262, section 12.2, page 62, the property must
1481 // not be deletable.
1482 PropertyAttributes attributes = DONT_DELETE;
1483
1484 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001485 // there, there is a property with this name in the prototype chain.
1486 // We follow Safari and Firefox behavior and only set the property
1487 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001488 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001489 // Note that objects can have hidden prototypes, so we need to traverse
1490 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001491 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001492 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001493 while (object->IsJSObject() &&
1494 JSObject::cast(object)->map()->is_hidden_prototype()) {
1495 JSObject* raw_holder = JSObject::cast(object);
1496 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001497 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001498 HandleScope handle_scope(isolate);
1499 Handle<JSObject> holder(raw_holder);
1500 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1501 // Update the raw pointer in case it's changed due to GC.
1502 raw_holder = *holder;
1503 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1504 // Found an interceptor that's not read only.
1505 if (assign) {
1506 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001507 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 } else {
1509 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001510 }
1511 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001512 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001513 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 }
1515
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001517 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001518 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001519 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001520 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001521 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001522}
1523
1524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001525RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526 // All constants are declared with an initial value. The name
1527 // of the constant is the first argument and the initial value
1528 // is the second.
1529 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001530 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 Handle<Object> value = args.at<Object>(1);
1532
1533 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535
1536 // According to ECMA-262, section 12.2, page 62, the property must
1537 // not be deletable. Since it's a const, it must be READ_ONLY too.
1538 PropertyAttributes attributes =
1539 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1540
1541 // Lookup the property locally in the global object. If it isn't
1542 // there, we add the property and take special precautions to always
1543 // add it as a local property even in case of callbacks in the
1544 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001545 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001546 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547 global->LocalLookup(*name, &lookup);
1548 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001549 return global->SetLocalPropertyIgnoreAttributes(*name,
1550 *value,
1551 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552 }
1553
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001556 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 HandleScope handle_scope(isolate);
1558 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001560 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 // property through an interceptor and only do it if it's
1562 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001563 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001564 RETURN_IF_EMPTY_HANDLE(
1565 isolate,
1566 JSReceiver::SetProperty(global, name, value, attributes,
1567 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 return *value;
1569 }
1570
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001571 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 // constant. For now, we determine this by checking if the
1573 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001574 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575 PropertyType type = lookup.type();
1576 if (type == FIELD) {
1577 FixedArray* properties = global->properties();
1578 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001579 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 properties->set(index, *value);
1581 }
1582 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001583 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1584 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001585 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586 }
1587 } else {
1588 // Ignore re-initialization of constants that have already been
1589 // assigned a function value.
1590 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1591 }
1592
1593 // Use the set value as the result of the operation.
1594 return *value;
1595}
1596
1597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001598RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001599 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600 ASSERT(args.length() == 3);
1601
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001602 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001605 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001606 RUNTIME_ASSERT(args[1]->IsContext());
1607 Handle<Context> context(Context::cast(args[1])->declaration_context());
1608
1609 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001610
1611 int index;
1612 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001613 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001614 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001615 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001616 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001619 ASSERT(holder->IsContext());
1620 // Property was found in a context. Perform the assignment if we
1621 // found some non-constant or an uninitialized constant.
1622 Handle<Context> context = Handle<Context>::cast(holder);
1623 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1624 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625 }
1626 return *value;
1627 }
1628
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001629 // The property could not be found, we introduce it as a property of the
1630 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001631 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001632 Handle<JSObject> global = Handle<JSObject>(
1633 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001634 // Strict mode not needed (const disallowed in strict mode).
1635 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001636 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001637 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001638 return *value;
1639 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001641 // The property was present in some function's context extension object,
1642 // as a property on the subject of a with, or as a property of the global
1643 // object.
1644 //
1645 // In most situations, eval-introduced consts should still be present in
1646 // the context extension object. However, because declaration and
1647 // initialization are separate, the property might have been deleted
1648 // before we reach the initialization point.
1649 //
1650 // Example:
1651 //
1652 // function f() { eval("delete x; const x;"); }
1653 //
1654 // In that case, the initialization behaves like a normal assignment.
1655 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001656
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001657 if (*object == context->extension()) {
1658 // This is the property that was introduced by the const declaration.
1659 // Set it if it hasn't been set before. NOTE: We cannot use
1660 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001661 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001662 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001663 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001664 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1665
1666 PropertyType type = lookup.type();
1667 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001668 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001669 int index = lookup.GetFieldIndex();
1670 if (properties->get(index)->IsTheHole()) {
1671 properties->set(index, *value);
1672 }
1673 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001674 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1675 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001676 }
1677 } else {
1678 // We should not reach here. Any real, named property should be
1679 // either a field or a dictionary slot.
1680 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001681 }
1682 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001683 // The property was found on some other object. Set it if it is not a
1684 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001685 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001686 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001687 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001689 JSReceiver::SetProperty(object, name, value, attributes,
1690 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001693
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001694 return *value;
1695}
1696
1697
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001698RUNTIME_FUNCTION(MaybeObject*,
1699 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001701 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001702 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001703 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001704 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001705 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001706 }
1707 return *object;
1708}
1709
1710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001711RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001712 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001713 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001714 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1715 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001716 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001717 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001718 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001719 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001720 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001721 RUNTIME_ASSERT(index >= 0);
1722 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001724 Handle<Object> result = RegExpImpl::Exec(regexp,
1725 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001726 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001727 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001728 if (result.is_null()) return Failure::Exception();
1729 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001730}
1731
1732
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001733RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001734 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001735 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001736 if (elements_count < 0 ||
1737 elements_count > FixedArray::kMaxLength ||
1738 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001739 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001740 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001741 Object* new_object;
1742 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001744 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1745 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001746 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1748 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1750 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001751 {
1752 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001753 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001756 }
1757 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001758 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001759 array->set_elements(elements);
1760 array->set_length(Smi::FromInt(elements_count));
1761 // Write in-object properties after the length of the array.
1762 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1763 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1764 return array;
1765}
1766
1767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001768RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001769 AssertNoAllocation no_alloc;
1770 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001771 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1772 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001773
1774 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001776
1777 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001778 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001779
1780 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001781 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001782
1783 Map* map = regexp->map();
1784 Object* constructor = map->constructor();
1785 if (constructor->IsJSFunction() &&
1786 JSFunction::cast(constructor)->initial_map() == map) {
1787 // If we still have the original map, set in-object properties directly.
1788 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001789 // Both true and false are immovable immortal objects so no need for write
1790 // barrier.
1791 regexp->InObjectPropertyAtPut(
1792 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1793 regexp->InObjectPropertyAtPut(
1794 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1795 regexp->InObjectPropertyAtPut(
1796 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001797 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1798 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001799 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001800 return regexp;
1801 }
1802
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001803 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001804 PropertyAttributes final =
1805 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1806 PropertyAttributes writable =
1807 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001809 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001810 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001811 source,
1812 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001813 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001815 global,
1816 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 ASSERT(!result->IsFailure());
1818 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001819 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001820 ignoreCase,
1821 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001822 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001823 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001824 multiline,
1825 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826 ASSERT(!result->IsFailure());
1827 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001828 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001829 Smi::FromInt(0),
1830 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001831 ASSERT(!result->IsFailure());
1832 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001833 return regexp;
1834}
1835
1836
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001837RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001838 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001839 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001840 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001841 // This is necessary to enable fast checks for absence of elements
1842 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001844 return Smi::FromInt(0);
1845}
1846
1847
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001848static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1849 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001850 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001851 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1853 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1854 Handle<JSFunction> optimized =
1855 isolate->factory()->NewFunction(key,
1856 JS_OBJECT_TYPE,
1857 JSObject::kHeaderSize,
1858 code,
1859 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001860 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001861 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001862 return optimized;
1863}
1864
1865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001866RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001868 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001869 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001870
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001871 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1872 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1873 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1874 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1875 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1876 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1877 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001878
1879 return *holder;
1880}
1881
1882
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001883RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001884 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001885 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001886
1887 if (!callable->IsJSFunction()) {
1888 HandleScope scope(isolate);
1889 bool threw = false;
1890 Handle<Object> delegate =
1891 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1892 if (threw) return Failure::Exception();
1893 callable = JSFunction::cast(*delegate);
1894 }
1895 JSFunction* function = JSFunction::cast(callable);
1896
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001897 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001898 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001899 return isolate->heap()->undefined_value();
1900 }
1901 // Returns undefined for strict or native functions, or
1902 // the associated global receiver for "normal" functions.
1903
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001904 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001905 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001906 return global_context->global()->global_receiver();
1907}
1908
1909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001910RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001911 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001913 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001914 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 Handle<String> pattern = args.at<String>(2);
1916 Handle<String> flags = args.at<String>(3);
1917
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001918 // Get the RegExp function from the context in the literals array.
1919 // This is the RegExp function from the context in which the
1920 // function was created. We do not use the RegExp function from the
1921 // current global context because this might be the RegExp function
1922 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001923 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001924 Handle<JSFunction>(
1925 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 // Compute the regular expression literal.
1927 bool has_pending_exception;
1928 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001929 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1930 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001931 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001932 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 return Failure::Exception();
1934 }
1935 literals->set(index, *regexp);
1936 return *regexp;
1937}
1938
1939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001940RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 NoHandleAllocation ha;
1942 ASSERT(args.length() == 1);
1943
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001944 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001945 return f->shared()->name();
1946}
1947
1948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001949RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001950 NoHandleAllocation ha;
1951 ASSERT(args.length() == 2);
1952
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001953 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1954 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001955 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001956 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001957}
1958
1959
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001960RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1961 NoHandleAllocation ha;
1962 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001963 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001964 return isolate->heap()->ToBoolean(
1965 f->shared()->name_should_print_as_anonymous());
1966}
1967
1968
1969RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1970 NoHandleAllocation ha;
1971 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001972 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001973 f->shared()->set_name_should_print_as_anonymous(true);
1974 return isolate->heap()->undefined_value();
1975}
1976
1977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001978RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001979 NoHandleAllocation ha;
1980 ASSERT(args.length() == 1);
1981
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001982 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001983 Object* obj = f->RemovePrototype();
1984 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001985
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001986 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001987}
1988
1989
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001990RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001991 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001992 ASSERT(args.length() == 1);
1993
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001994 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001995 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1996 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997
1998 return *GetScriptWrapper(Handle<Script>::cast(script));
1999}
2000
2001
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002002RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002003 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002004 ASSERT(args.length() == 1);
2005
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002006 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002007 Handle<SharedFunctionInfo> shared(f->shared());
2008 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009}
2010
2011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002012RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 NoHandleAllocation ha;
2014 ASSERT(args.length() == 1);
2015
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002016 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017 int pos = fun->shared()->start_position();
2018 return Smi::FromInt(pos);
2019}
2020
2021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002022RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002023 ASSERT(args.length() == 2);
2024
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002025 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002026 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2027
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002028 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2029
2030 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002031 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002032}
2033
2034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002035RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036 NoHandleAllocation ha;
2037 ASSERT(args.length() == 2);
2038
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002039 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2040 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002041 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002042 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002043}
2044
2045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002046RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002047 NoHandleAllocation ha;
2048 ASSERT(args.length() == 2);
2049
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002050 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2051 CONVERT_SMI_ARG_CHECKED(length, 1);
2052 fun->shared()->set_length(length);
2053 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002054}
2055
2056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002057RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002058 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002059 ASSERT(args.length() == 2);
2060
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002061 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002062 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002063 Object* obj;
2064 { MaybeObject* maybe_obj =
2065 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2066 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2067 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002068 return args[0]; // return TOS
2069}
2070
2071
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002072RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2073 NoHandleAllocation ha;
2074 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002075 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002076
2077 MaybeObject* maybe_name =
2078 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2079 String* name;
2080 if (!maybe_name->To(&name)) return maybe_name;
2081
2082 if (function->HasFastProperties()) {
2083 // Construct a new field descriptor with updated attributes.
2084 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2085 int index = instance_desc->Search(name);
2086 ASSERT(index != DescriptorArray::kNotFound);
2087 PropertyDetails details(instance_desc->GetDetails(index));
2088 CallbacksDescriptor new_desc(name,
2089 instance_desc->GetValue(index),
2090 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2091 details.index());
2092 // Construct a new field descriptors array containing the new descriptor.
2093 Object* descriptors_unchecked;
2094 { MaybeObject* maybe_descriptors_unchecked =
2095 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2096 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2097 return maybe_descriptors_unchecked;
2098 }
2099 }
2100 DescriptorArray* new_descriptors =
2101 DescriptorArray::cast(descriptors_unchecked);
2102 // Create a new map featuring the new field descriptors array.
2103 Object* map_unchecked;
2104 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2105 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2106 return maybe_map_unchecked;
2107 }
2108 }
2109 Map* new_map = Map::cast(map_unchecked);
2110 new_map->set_instance_descriptors(new_descriptors);
2111 function->set_map(new_map);
2112 } else { // Dictionary properties.
2113 // Directly manipulate the property details.
2114 int entry = function->property_dictionary()->FindEntry(name);
2115 ASSERT(entry != StringDictionary::kNotFound);
2116 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2117 PropertyDetails new_details(
2118 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2119 details.type(),
2120 details.index());
2121 function->property_dictionary()->DetailsAtPut(entry, new_details);
2122 }
2123 return function;
2124}
2125
2126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002127RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002128 NoHandleAllocation ha;
2129 ASSERT(args.length() == 1);
2130
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002131 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002132 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002133}
2134
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002136RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002137 NoHandleAllocation ha;
2138 ASSERT(args.length() == 1);
2139
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002140 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002141 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002142}
2143
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002145RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002146 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002147 ASSERT(args.length() == 2);
2148
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002149 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002150 Handle<Object> code = args.at<Object>(1);
2151
2152 Handle<Context> context(target->context());
2153
2154 if (!code->IsNull()) {
2155 RUNTIME_ASSERT(code->IsJSFunction());
2156 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002157 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002158
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002159 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002160 return Failure::Exception();
2161 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002162 // Since we don't store the source for this we should never
2163 // optimize this.
2164 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002165 // Set the code, scope info, formal parameter count,
2166 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002167 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002168 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002169 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002170 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002171 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002172 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002173 // Set the source code of the target function to undefined.
2174 // SetCode is only used for built-in constructors like String,
2175 // Array, and Object, and some web code
2176 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002177 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002178 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002179 // Clear the optimization hints related to the compiled code as these are no
2180 // longer valid when the code is overwritten.
2181 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002182 context = Handle<Context>(fun->context());
2183
2184 // Make sure we get a fresh copy of the literal vector to avoid
2185 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002186 int number_of_literals = fun->NumberOfLiterals();
2187 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002188 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002189 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002190 // Insert the object, regexp and array functions in the literals
2191 // array prefix. These are the functions that will be used when
2192 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002193 literals->set(JSFunction::kLiteralGlobalContextIndex,
2194 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002196 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002197 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002198
2199 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2200 isolate->logger()->LogExistingFunction(
2201 shared, Handle<Code>(shared->code()));
2202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002203 }
2204
2205 target->set_context(*context);
2206 return *target;
2207}
2208
2209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002210RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002211 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002212 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002213 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002214 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002215 RUNTIME_ASSERT(num >= 0);
2216 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002217 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002218}
2219
2220
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2222 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002223 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002224 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002225 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002226 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002227 }
2228 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002229 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002230}
2231
2232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002233RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002234 NoHandleAllocation ha;
2235 ASSERT(args.length() == 2);
2236
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002237 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002238 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002239 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002240
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002241 uint32_t i = 0;
2242 if (index->IsSmi()) {
2243 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002244 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002245 i = value;
2246 } else {
2247 ASSERT(index->IsHeapNumber());
2248 double value = HeapNumber::cast(index)->value();
2249 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002250 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002251
2252 // Flatten the string. If someone wants to get a char at an index
2253 // in a cons string, it is likely that more indices will be
2254 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002255 Object* flat;
2256 { MaybeObject* maybe_flat = subject->TryFlatten();
2257 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2258 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002259 subject = String::cast(flat);
2260
2261 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002262 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002263 }
2264
2265 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002266}
2267
2268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002269RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002270 NoHandleAllocation ha;
2271 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002273}
2274
lrn@chromium.org25156de2010-04-06 13:10:27 +00002275
2276class FixedArrayBuilder {
2277 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002278 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2279 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002280 length_(0),
2281 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002282 // Require a non-zero initial size. Ensures that doubling the size to
2283 // extend the array will work.
2284 ASSERT(initial_capacity > 0);
2285 }
2286
2287 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2288 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002289 length_(0),
2290 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002291 // Require a non-zero initial size. Ensures that doubling the size to
2292 // extend the array will work.
2293 ASSERT(backing_store->length() > 0);
2294 }
2295
2296 bool HasCapacity(int elements) {
2297 int length = array_->length();
2298 int required_length = length_ + elements;
2299 return (length >= required_length);
2300 }
2301
2302 void EnsureCapacity(int elements) {
2303 int length = array_->length();
2304 int required_length = length_ + elements;
2305 if (length < required_length) {
2306 int new_length = length;
2307 do {
2308 new_length *= 2;
2309 } while (new_length < required_length);
2310 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002311 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002312 array_->CopyTo(0, *extended_array, 0, length_);
2313 array_ = extended_array;
2314 }
2315 }
2316
2317 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002318 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002319 ASSERT(length_ < capacity());
2320 array_->set(length_, value);
2321 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002322 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002323 }
2324
2325 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002326 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002327 ASSERT(length_ < capacity());
2328 array_->set(length_, value);
2329 length_++;
2330 }
2331
2332 Handle<FixedArray> array() {
2333 return array_;
2334 }
2335
2336 int length() {
2337 return length_;
2338 }
2339
2340 int capacity() {
2341 return array_->length();
2342 }
2343
2344 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002345 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002346 result_array->set_length(Smi::FromInt(length_));
2347 return result_array;
2348 }
2349
2350 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002351 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002352 target_array->set_length(Smi::FromInt(length_));
2353 return target_array;
2354 }
2355
2356 private:
2357 Handle<FixedArray> array_;
2358 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002359 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360};
2361
2362
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002364const int kStringBuilderConcatHelperLengthBits = 11;
2365const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002366
2367template <typename schar>
2368static inline void StringBuilderConcatHelper(String*,
2369 schar*,
2370 FixedArray*,
2371 int);
2372
lrn@chromium.org25156de2010-04-06 13:10:27 +00002373typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2374 StringBuilderSubstringLength;
2375typedef BitField<int,
2376 kStringBuilderConcatHelperLengthBits,
2377 kStringBuilderConcatHelperPositionBits>
2378 StringBuilderSubstringPosition;
2379
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002380
2381class ReplacementStringBuilder {
2382 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002383 ReplacementStringBuilder(Heap* heap,
2384 Handle<String> subject,
2385 int estimated_part_count)
2386 : heap_(heap),
2387 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002388 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002389 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002390 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002391 // Require a non-zero initial size. Ensures that doubling the size to
2392 // extend the array will work.
2393 ASSERT(estimated_part_count > 0);
2394 }
2395
lrn@chromium.org25156de2010-04-06 13:10:27 +00002396 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2397 int from,
2398 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002399 ASSERT(from >= 0);
2400 int length = to - from;
2401 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002402 if (StringBuilderSubstringLength::is_valid(length) &&
2403 StringBuilderSubstringPosition::is_valid(from)) {
2404 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2405 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002406 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002407 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002408 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002409 builder->Add(Smi::FromInt(-length));
2410 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002411 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002412 }
2413
2414
2415 void EnsureCapacity(int elements) {
2416 array_builder_.EnsureCapacity(elements);
2417 }
2418
2419
2420 void AddSubjectSlice(int from, int to) {
2421 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002422 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002423 }
2424
2425
2426 void AddString(Handle<String> string) {
2427 int length = string->length();
2428 ASSERT(length > 0);
2429 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002430 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002431 is_ascii_ = false;
2432 }
2433 IncrementCharacterCount(length);
2434 }
2435
2436
2437 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002438 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002439 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 }
2441
2442 Handle<String> joined_string;
2443 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002444 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002445 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002446 char* char_buffer = seq->GetChars();
2447 StringBuilderConcatHelper(*subject_,
2448 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002449 *array_builder_.array(),
2450 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002451 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002452 } else {
2453 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002454 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002455 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 uc16* char_buffer = seq->GetChars();
2457 StringBuilderConcatHelper(*subject_,
2458 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002459 *array_builder_.array(),
2460 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002462 }
2463 return joined_string;
2464 }
2465
2466
2467 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002468 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 V8::FatalProcessOutOfMemory("String.replace result too large.");
2470 }
2471 character_count_ += by;
2472 }
2473
lrn@chromium.org25156de2010-04-06 13:10:27 +00002474 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002475 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002476 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002477
lrn@chromium.org25156de2010-04-06 13:10:27 +00002478 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002479 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2480 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002481 }
2482
2483
ager@chromium.org04921a82011-06-27 13:21:41 +00002484 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2485 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002486 }
2487
2488
2489 void AddElement(Object* element) {
2490 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002491 ASSERT(array_builder_.capacity() > array_builder_.length());
2492 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493 }
2494
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002495 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002496 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 int character_count_;
2499 bool is_ascii_;
2500};
2501
2502
2503class CompiledReplacement {
2504 public:
2505 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002506 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002507
2508 void Compile(Handle<String> replacement,
2509 int capture_count,
2510 int subject_length);
2511
2512 void Apply(ReplacementStringBuilder* builder,
2513 int match_from,
2514 int match_to,
2515 Handle<JSArray> last_match_info);
2516
2517 // Number of distinct parts of the replacement pattern.
2518 int parts() {
2519 return parts_.length();
2520 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002521
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002522 bool simple_hint() {
2523 return simple_hint_;
2524 }
2525
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002526 private:
2527 enum PartType {
2528 SUBJECT_PREFIX = 1,
2529 SUBJECT_SUFFIX,
2530 SUBJECT_CAPTURE,
2531 REPLACEMENT_SUBSTRING,
2532 REPLACEMENT_STRING,
2533
2534 NUMBER_OF_PART_TYPES
2535 };
2536
2537 struct ReplacementPart {
2538 static inline ReplacementPart SubjectMatch() {
2539 return ReplacementPart(SUBJECT_CAPTURE, 0);
2540 }
2541 static inline ReplacementPart SubjectCapture(int capture_index) {
2542 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2543 }
2544 static inline ReplacementPart SubjectPrefix() {
2545 return ReplacementPart(SUBJECT_PREFIX, 0);
2546 }
2547 static inline ReplacementPart SubjectSuffix(int subject_length) {
2548 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2549 }
2550 static inline ReplacementPart ReplacementString() {
2551 return ReplacementPart(REPLACEMENT_STRING, 0);
2552 }
2553 static inline ReplacementPart ReplacementSubString(int from, int to) {
2554 ASSERT(from >= 0);
2555 ASSERT(to > from);
2556 return ReplacementPart(-from, to);
2557 }
2558
2559 // If tag <= 0 then it is the negation of a start index of a substring of
2560 // the replacement pattern, otherwise it's a value from PartType.
2561 ReplacementPart(int tag, int data)
2562 : tag(tag), data(data) {
2563 // Must be non-positive or a PartType value.
2564 ASSERT(tag < NUMBER_OF_PART_TYPES);
2565 }
2566 // Either a value of PartType or a non-positive number that is
2567 // the negation of an index into the replacement string.
2568 int tag;
2569 // The data value's interpretation depends on the value of tag:
2570 // tag == SUBJECT_PREFIX ||
2571 // tag == SUBJECT_SUFFIX: data is unused.
2572 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2573 // tag == REPLACEMENT_SUBSTRING ||
2574 // tag == REPLACEMENT_STRING: data is index into array of substrings
2575 // of the replacement string.
2576 // tag <= 0: Temporary representation of the substring of the replacement
2577 // string ranging over -tag .. data.
2578 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2579 // substring objects.
2580 int data;
2581 };
2582
2583 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002584 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002585 Vector<Char> characters,
2586 int capture_count,
2587 int subject_length) {
2588 int length = characters.length();
2589 int last = 0;
2590 for (int i = 0; i < length; i++) {
2591 Char c = characters[i];
2592 if (c == '$') {
2593 int next_index = i + 1;
2594 if (next_index == length) { // No next character!
2595 break;
2596 }
2597 Char c2 = characters[next_index];
2598 switch (c2) {
2599 case '$':
2600 if (i > last) {
2601 // There is a substring before. Include the first "$".
2602 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2603 last = next_index + 1; // Continue after the second "$".
2604 } else {
2605 // Let the next substring start with the second "$".
2606 last = next_index;
2607 }
2608 i = next_index;
2609 break;
2610 case '`':
2611 if (i > last) {
2612 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2613 }
2614 parts->Add(ReplacementPart::SubjectPrefix());
2615 i = next_index;
2616 last = i + 1;
2617 break;
2618 case '\'':
2619 if (i > last) {
2620 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2621 }
2622 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2623 i = next_index;
2624 last = i + 1;
2625 break;
2626 case '&':
2627 if (i > last) {
2628 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2629 }
2630 parts->Add(ReplacementPart::SubjectMatch());
2631 i = next_index;
2632 last = i + 1;
2633 break;
2634 case '0':
2635 case '1':
2636 case '2':
2637 case '3':
2638 case '4':
2639 case '5':
2640 case '6':
2641 case '7':
2642 case '8':
2643 case '9': {
2644 int capture_ref = c2 - '0';
2645 if (capture_ref > capture_count) {
2646 i = next_index;
2647 continue;
2648 }
2649 int second_digit_index = next_index + 1;
2650 if (second_digit_index < length) {
2651 // Peek ahead to see if we have two digits.
2652 Char c3 = characters[second_digit_index];
2653 if ('0' <= c3 && c3 <= '9') { // Double digits.
2654 int double_digit_ref = capture_ref * 10 + c3 - '0';
2655 if (double_digit_ref <= capture_count) {
2656 next_index = second_digit_index;
2657 capture_ref = double_digit_ref;
2658 }
2659 }
2660 }
2661 if (capture_ref > 0) {
2662 if (i > last) {
2663 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2664 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002665 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002666 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2667 last = next_index + 1;
2668 }
2669 i = next_index;
2670 break;
2671 }
2672 default:
2673 i = next_index;
2674 break;
2675 }
2676 }
2677 }
2678 if (length > last) {
2679 if (last == 0) {
2680 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002681 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002682 } else {
2683 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2684 }
2685 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002686 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002687 }
2688
2689 ZoneList<ReplacementPart> parts_;
2690 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002691 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002692};
2693
2694
2695void CompiledReplacement::Compile(Handle<String> replacement,
2696 int capture_count,
2697 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002698 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002699 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002700 String::FlatContent content = replacement->GetFlatContent();
2701 ASSERT(content.IsFlat());
2702 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002703 simple_hint_ = ParseReplacementPattern(&parts_,
2704 content.ToAsciiVector(),
2705 capture_count,
2706 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002707 } else {
2708 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002709 simple_hint_ = ParseReplacementPattern(&parts_,
2710 content.ToUC16Vector(),
2711 capture_count,
2712 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002713 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002714 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002715 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002716 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002717 int substring_index = 0;
2718 for (int i = 0, n = parts_.length(); i < n; i++) {
2719 int tag = parts_[i].tag;
2720 if (tag <= 0) { // A replacement string slice.
2721 int from = -tag;
2722 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 replacement_substrings_.Add(
2724 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002725 parts_[i].tag = REPLACEMENT_SUBSTRING;
2726 parts_[i].data = substring_index;
2727 substring_index++;
2728 } else if (tag == REPLACEMENT_STRING) {
2729 replacement_substrings_.Add(replacement);
2730 parts_[i].data = substring_index;
2731 substring_index++;
2732 }
2733 }
2734}
2735
2736
2737void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2738 int match_from,
2739 int match_to,
2740 Handle<JSArray> last_match_info) {
2741 for (int i = 0, n = parts_.length(); i < n; i++) {
2742 ReplacementPart part = parts_[i];
2743 switch (part.tag) {
2744 case SUBJECT_PREFIX:
2745 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2746 break;
2747 case SUBJECT_SUFFIX: {
2748 int subject_length = part.data;
2749 if (match_to < subject_length) {
2750 builder->AddSubjectSlice(match_to, subject_length);
2751 }
2752 break;
2753 }
2754 case SUBJECT_CAPTURE: {
2755 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002756 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002757 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2758 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2759 if (from >= 0 && to > from) {
2760 builder->AddSubjectSlice(from, to);
2761 }
2762 break;
2763 }
2764 case REPLACEMENT_SUBSTRING:
2765 case REPLACEMENT_STRING:
2766 builder->AddString(replacement_substrings_[part.data]);
2767 break;
2768 default:
2769 UNREACHABLE();
2770 }
2771 }
2772}
2773
2774
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002775void FindAsciiStringIndices(Vector<const char> subject,
2776 char pattern,
2777 ZoneList<int>* indices,
2778 unsigned int limit) {
2779 ASSERT(limit > 0);
2780 // Collect indices of pattern in subject using memchr.
2781 // Stop after finding at most limit values.
2782 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2783 const char* subject_end = subject_start + subject.length();
2784 const char* pos = subject_start;
2785 while (limit > 0) {
2786 pos = reinterpret_cast<const char*>(
2787 memchr(pos, pattern, subject_end - pos));
2788 if (pos == NULL) return;
2789 indices->Add(static_cast<int>(pos - subject_start));
2790 pos++;
2791 limit--;
2792 }
2793}
2794
2795
2796template <typename SubjectChar, typename PatternChar>
2797void FindStringIndices(Isolate* isolate,
2798 Vector<const SubjectChar> subject,
2799 Vector<const PatternChar> pattern,
2800 ZoneList<int>* indices,
2801 unsigned int limit) {
2802 ASSERT(limit > 0);
2803 // Collect indices of pattern in subject.
2804 // Stop after finding at most limit values.
2805 int pattern_length = pattern.length();
2806 int index = 0;
2807 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2808 while (limit > 0) {
2809 index = search.Search(subject, index);
2810 if (index < 0) return;
2811 indices->Add(index);
2812 index += pattern_length;
2813 limit--;
2814 }
2815}
2816
2817
2818void FindStringIndicesDispatch(Isolate* isolate,
2819 String* subject,
2820 String* pattern,
2821 ZoneList<int>* indices,
2822 unsigned int limit) {
2823 {
2824 AssertNoAllocation no_gc;
2825 String::FlatContent subject_content = subject->GetFlatContent();
2826 String::FlatContent pattern_content = pattern->GetFlatContent();
2827 ASSERT(subject_content.IsFlat());
2828 ASSERT(pattern_content.IsFlat());
2829 if (subject_content.IsAscii()) {
2830 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2831 if (pattern_content.IsAscii()) {
2832 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2833 if (pattern_vector.length() == 1) {
2834 FindAsciiStringIndices(subject_vector,
2835 pattern_vector[0],
2836 indices,
2837 limit);
2838 } else {
2839 FindStringIndices(isolate,
2840 subject_vector,
2841 pattern_vector,
2842 indices,
2843 limit);
2844 }
2845 } else {
2846 FindStringIndices(isolate,
2847 subject_vector,
2848 pattern_content.ToUC16Vector(),
2849 indices,
2850 limit);
2851 }
2852 } else {
2853 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002854 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002855 FindStringIndices(isolate,
2856 subject_vector,
2857 pattern_content.ToAsciiVector(),
2858 indices,
2859 limit);
2860 } else {
2861 FindStringIndices(isolate,
2862 subject_vector,
2863 pattern_content.ToUC16Vector(),
2864 indices,
2865 limit);
2866 }
2867 }
2868 }
2869}
2870
2871
2872template<typename ResultSeqString>
2873MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2874 Isolate* isolate,
2875 Handle<String> subject,
2876 Handle<JSRegExp> pattern_regexp,
2877 Handle<String> replacement) {
2878 ASSERT(subject->IsFlat());
2879 ASSERT(replacement->IsFlat());
2880
2881 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2882 ZoneList<int> indices(8);
2883 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2884 String* pattern =
2885 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2886 int subject_len = subject->length();
2887 int pattern_len = pattern->length();
2888 int replacement_len = replacement->length();
2889
2890 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2891
2892 int matches = indices.length();
2893 if (matches == 0) return *subject;
2894
2895 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2896 int subject_pos = 0;
2897 int result_pos = 0;
2898
2899 Handle<ResultSeqString> result;
2900 if (ResultSeqString::kHasAsciiEncoding) {
2901 result = Handle<ResultSeqString>::cast(
2902 isolate->factory()->NewRawAsciiString(result_len));
2903 } else {
2904 result = Handle<ResultSeqString>::cast(
2905 isolate->factory()->NewRawTwoByteString(result_len));
2906 }
2907
2908 for (int i = 0; i < matches; i++) {
2909 // Copy non-matched subject content.
2910 if (subject_pos < indices.at(i)) {
2911 String::WriteToFlat(*subject,
2912 result->GetChars() + result_pos,
2913 subject_pos,
2914 indices.at(i));
2915 result_pos += indices.at(i) - subject_pos;
2916 }
2917
2918 // Replace match.
2919 if (replacement_len > 0) {
2920 String::WriteToFlat(*replacement,
2921 result->GetChars() + result_pos,
2922 0,
2923 replacement_len);
2924 result_pos += replacement_len;
2925 }
2926
2927 subject_pos = indices.at(i) + pattern_len;
2928 }
2929 // Add remaining subject content at the end.
2930 if (subject_pos < subject_len) {
2931 String::WriteToFlat(*subject,
2932 result->GetChars() + result_pos,
2933 subject_pos,
2934 subject_len);
2935 }
2936 return *result;
2937}
2938
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002939
lrn@chromium.org303ada72010-10-27 09:33:13 +00002940MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002941 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002942 String* subject,
2943 JSRegExp* regexp,
2944 String* replacement,
2945 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002946 ASSERT(subject->IsFlat());
2947 ASSERT(replacement->IsFlat());
2948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002949 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002950
2951 int length = subject->length();
2952 Handle<String> subject_handle(subject);
2953 Handle<JSRegExp> regexp_handle(regexp);
2954 Handle<String> replacement_handle(replacement);
2955 Handle<JSArray> last_match_info_handle(last_match_info);
2956 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2957 subject_handle,
2958 0,
2959 last_match_info_handle);
2960 if (match.is_null()) {
2961 return Failure::Exception();
2962 }
2963 if (match->IsNull()) {
2964 return *subject_handle;
2965 }
2966
2967 int capture_count = regexp_handle->CaptureCount();
2968
2969 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002970 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002971 CompiledReplacement compiled_replacement;
2972 compiled_replacement.Compile(replacement_handle,
2973 capture_count,
2974 length);
2975
2976 bool is_global = regexp_handle->GetFlags().is_global();
2977
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002978 // Shortcut for simple non-regexp global replacements
2979 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002980 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002981 compiled_replacement.simple_hint()) {
2982 if (subject_handle->HasOnlyAsciiChars() &&
2983 replacement_handle->HasOnlyAsciiChars()) {
2984 return StringReplaceStringWithString<SeqAsciiString>(
2985 isolate, subject_handle, regexp_handle, replacement_handle);
2986 } else {
2987 return StringReplaceStringWithString<SeqTwoByteString>(
2988 isolate, subject_handle, regexp_handle, replacement_handle);
2989 }
2990 }
2991
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002992 // Guessing the number of parts that the final result string is built
2993 // from. Global regexps can match any number of times, so we guess
2994 // conservatively.
2995 int expected_parts =
2996 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002997 ReplacementStringBuilder builder(isolate->heap(),
2998 subject_handle,
2999 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003000
3001 // Index of end of last match.
3002 int prev = 0;
3003
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003004 // Number of parts added by compiled replacement plus preceeding
3005 // string and possibly suffix after last match. It is possible for
3006 // all components to use two elements when encoded as two smis.
3007 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003008 bool matched = true;
3009 do {
3010 ASSERT(last_match_info_handle->HasFastElements());
3011 // Increase the capacity of the builder before entering local handle-scope,
3012 // so its internal buffer can safely allocate a new handle if it grows.
3013 builder.EnsureCapacity(parts_added_per_loop);
3014
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003015 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003016 int start, end;
3017 {
3018 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003019 FixedArray* match_info_array =
3020 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003021
3022 ASSERT_EQ(capture_count * 2 + 2,
3023 RegExpImpl::GetLastCaptureCount(match_info_array));
3024 start = RegExpImpl::GetCapture(match_info_array, 0);
3025 end = RegExpImpl::GetCapture(match_info_array, 1);
3026 }
3027
3028 if (prev < start) {
3029 builder.AddSubjectSlice(prev, start);
3030 }
3031 compiled_replacement.Apply(&builder,
3032 start,
3033 end,
3034 last_match_info_handle);
3035 prev = end;
3036
3037 // Only continue checking for global regexps.
3038 if (!is_global) break;
3039
3040 // Continue from where the match ended, unless it was an empty match.
3041 int next = end;
3042 if (start == end) {
3043 next = end + 1;
3044 if (next > length) break;
3045 }
3046
3047 match = RegExpImpl::Exec(regexp_handle,
3048 subject_handle,
3049 next,
3050 last_match_info_handle);
3051 if (match.is_null()) {
3052 return Failure::Exception();
3053 }
3054 matched = !match->IsNull();
3055 } while (matched);
3056
3057 if (prev < length) {
3058 builder.AddSubjectSlice(prev, length);
3059 }
3060
3061 return *(builder.ToString());
3062}
3063
3064
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003065template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003066MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003067 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003068 String* subject,
3069 JSRegExp* regexp,
3070 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003071 ASSERT(subject->IsFlat());
3072
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003073 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003074
3075 Handle<String> subject_handle(subject);
3076 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003077
3078 // Shortcut for simple non-regexp global replacements
3079 if (regexp_handle->GetFlags().is_global() &&
3080 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3081 Handle<String> empty_string_handle(HEAP->empty_string());
3082 if (subject_handle->HasOnlyAsciiChars()) {
3083 return StringReplaceStringWithString<SeqAsciiString>(
3084 isolate, subject_handle, regexp_handle, empty_string_handle);
3085 } else {
3086 return StringReplaceStringWithString<SeqTwoByteString>(
3087 isolate, subject_handle, regexp_handle, empty_string_handle);
3088 }
3089 }
3090
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003091 Handle<JSArray> last_match_info_handle(last_match_info);
3092 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3093 subject_handle,
3094 0,
3095 last_match_info_handle);
3096 if (match.is_null()) return Failure::Exception();
3097 if (match->IsNull()) return *subject_handle;
3098
3099 ASSERT(last_match_info_handle->HasFastElements());
3100
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003101 int start, end;
3102 {
3103 AssertNoAllocation match_info_array_is_not_in_a_handle;
3104 FixedArray* match_info_array =
3105 FixedArray::cast(last_match_info_handle->elements());
3106
3107 start = RegExpImpl::GetCapture(match_info_array, 0);
3108 end = RegExpImpl::GetCapture(match_info_array, 1);
3109 }
3110
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003111 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003112 int new_length = length - (end - start);
3113 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003114 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003115 }
3116 Handle<ResultSeqString> answer;
3117 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003118 answer = Handle<ResultSeqString>::cast(
3119 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003120 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003121 answer = Handle<ResultSeqString>::cast(
3122 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003123 }
3124
3125 // If the regexp isn't global, only match once.
3126 if (!regexp_handle->GetFlags().is_global()) {
3127 if (start > 0) {
3128 String::WriteToFlat(*subject_handle,
3129 answer->GetChars(),
3130 0,
3131 start);
3132 }
3133 if (end < length) {
3134 String::WriteToFlat(*subject_handle,
3135 answer->GetChars() + start,
3136 end,
3137 length);
3138 }
3139 return *answer;
3140 }
3141
3142 int prev = 0; // Index of end of last match.
3143 int next = 0; // Start of next search (prev unless last match was empty).
3144 int position = 0;
3145
3146 do {
3147 if (prev < start) {
3148 // Add substring subject[prev;start] to answer string.
3149 String::WriteToFlat(*subject_handle,
3150 answer->GetChars() + position,
3151 prev,
3152 start);
3153 position += start - prev;
3154 }
3155 prev = end;
3156 next = end;
3157 // Continue from where the match ended, unless it was an empty match.
3158 if (start == end) {
3159 next++;
3160 if (next > length) break;
3161 }
3162 match = RegExpImpl::Exec(regexp_handle,
3163 subject_handle,
3164 next,
3165 last_match_info_handle);
3166 if (match.is_null()) return Failure::Exception();
3167 if (match->IsNull()) break;
3168
3169 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003170 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003171 {
3172 AssertNoAllocation match_info_array_is_not_in_a_handle;
3173 FixedArray* match_info_array =
3174 FixedArray::cast(last_match_info_handle->elements());
3175 start = RegExpImpl::GetCapture(match_info_array, 0);
3176 end = RegExpImpl::GetCapture(match_info_array, 1);
3177 }
3178 } while (true);
3179
3180 if (prev < length) {
3181 // Add substring subject[prev;length] to answer string.
3182 String::WriteToFlat(*subject_handle,
3183 answer->GetChars() + position,
3184 prev,
3185 length);
3186 position += length - prev;
3187 }
3188
3189 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003190 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003191 }
3192
3193 // Shorten string and fill
3194 int string_size = ResultSeqString::SizeFor(position);
3195 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3196 int delta = allocated_string_size - string_size;
3197
3198 answer->set_length(position);
3199 if (delta == 0) return *answer;
3200
3201 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003202 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003203 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003204 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003205 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003206
3207 return *answer;
3208}
3209
3210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003211RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003212 ASSERT(args.length() == 4);
3213
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003214 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003215 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003216 Object* flat_subject;
3217 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3218 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3219 return maybe_flat_subject;
3220 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003221 }
3222 subject = String::cast(flat_subject);
3223 }
3224
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003225 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003226 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003227 Object* flat_replacement;
3228 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3229 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3230 return maybe_flat_replacement;
3231 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003232 }
3233 replacement = String::cast(flat_replacement);
3234 }
3235
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003236 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3237 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003238
3239 ASSERT(last_match_info->HasFastElements());
3240
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003241 if (replacement->length() == 0) {
3242 if (subject->HasOnlyAsciiChars()) {
3243 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003244 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003245 } else {
3246 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003247 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003248 }
3249 }
3250
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003251 return StringReplaceRegExpWithString(isolate,
3252 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003253 regexp,
3254 replacement,
3255 last_match_info);
3256}
3257
3258
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003259Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3260 Handle<String> subject,
3261 Handle<String> search,
3262 Handle<String> replace,
3263 bool* found,
3264 int recursion_limit) {
3265 if (recursion_limit == 0) return Handle<String>::null();
3266 if (subject->IsConsString()) {
3267 ConsString* cons = ConsString::cast(*subject);
3268 Handle<String> first = Handle<String>(cons->first());
3269 Handle<String> second = Handle<String>(cons->second());
3270 Handle<String> new_first =
3271 StringReplaceOneCharWithString(isolate,
3272 first,
3273 search,
3274 replace,
3275 found,
3276 recursion_limit - 1);
3277 if (*found) return isolate->factory()->NewConsString(new_first, second);
3278 if (new_first.is_null()) return new_first;
3279
3280 Handle<String> new_second =
3281 StringReplaceOneCharWithString(isolate,
3282 second,
3283 search,
3284 replace,
3285 found,
3286 recursion_limit - 1);
3287 if (*found) return isolate->factory()->NewConsString(first, new_second);
3288 if (new_second.is_null()) return new_second;
3289
3290 return subject;
3291 } else {
3292 int index = StringMatch(isolate, subject, search, 0);
3293 if (index == -1) return subject;
3294 *found = true;
3295 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3296 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3297 Handle<String> second =
3298 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3299 return isolate->factory()->NewConsString(cons1, second);
3300 }
3301}
3302
3303
3304RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3305 ASSERT(args.length() == 3);
3306 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003307 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3308 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3309 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003310
3311 // If the cons string tree is too deep, we simply abort the recursion and
3312 // retry with a flattened subject string.
3313 const int kRecursionLimit = 0x1000;
3314 bool found = false;
3315 Handle<String> result =
3316 Runtime::StringReplaceOneCharWithString(isolate,
3317 subject,
3318 search,
3319 replace,
3320 &found,
3321 kRecursionLimit);
3322 if (!result.is_null()) return *result;
3323 return *Runtime::StringReplaceOneCharWithString(isolate,
3324 FlattenGetString(subject),
3325 search,
3326 replace,
3327 &found,
3328 kRecursionLimit);
3329}
3330
3331
ager@chromium.org7c537e22008-10-16 08:43:32 +00003332// Perform string match of pattern on subject, starting at start index.
3333// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003334// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003335int Runtime::StringMatch(Isolate* isolate,
3336 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003337 Handle<String> pat,
3338 int start_index) {
3339 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003340 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003341
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003342 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003343 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003344
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003345 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003346 if (start_index + pattern_length > subject_length) return -1;
3347
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003348 if (!sub->IsFlat()) FlattenString(sub);
3349 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003350
ager@chromium.org7c537e22008-10-16 08:43:32 +00003351 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003352 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003353 String::FlatContent seq_sub = sub->GetFlatContent();
3354 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003355
ager@chromium.org7c537e22008-10-16 08:43:32 +00003356 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003357 if (seq_pat.IsAscii()) {
3358 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3359 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003360 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003361 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003362 pat_vector,
3363 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003364 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003365 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003366 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003367 pat_vector,
3368 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003369 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003370 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3371 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003372 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003373 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003374 pat_vector,
3375 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003376 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003377 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003379 pat_vector,
3380 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003381}
3382
3383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003384RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003385 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003386 ASSERT(args.length() == 3);
3387
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003388 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3389 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003390
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003391 Object* index = args[2];
3392 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003393 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003394
ager@chromium.org870a0b62008-11-04 11:43:05 +00003395 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003396 int position =
3397 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003398 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399}
3400
3401
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003402template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003403static int StringMatchBackwards(Vector<const schar> subject,
3404 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003405 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003406 int pattern_length = pattern.length();
3407 ASSERT(pattern_length >= 1);
3408 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003409
3410 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003411 for (int i = 0; i < pattern_length; i++) {
3412 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003413 if (c > String::kMaxAsciiCharCode) {
3414 return -1;
3415 }
3416 }
3417 }
3418
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003419 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003420 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003421 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003422 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003423 while (j < pattern_length) {
3424 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003425 break;
3426 }
3427 j++;
3428 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003429 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 return i;
3431 }
3432 }
3433 return -1;
3434}
3435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003436RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003437 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003438 ASSERT(args.length() == 3);
3439
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003440 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3441 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003442
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003443 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003444 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003445 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003446
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003447 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003448 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003449
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003450 if (start_index + pat_length > sub_length) {
3451 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003452 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003453
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003454 if (pat_length == 0) {
3455 return Smi::FromInt(start_index);
3456 }
3457
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003458 if (!sub->IsFlat()) FlattenString(sub);
3459 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003460
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003461 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003462 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3463
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003464 String::FlatContent sub_content = sub->GetFlatContent();
3465 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003466
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003467 if (pat_content.IsAscii()) {
3468 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3469 if (sub_content.IsAscii()) {
3470 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003471 pat_vector,
3472 start_index);
3473 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003474 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003475 pat_vector,
3476 start_index);
3477 }
3478 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003479 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3480 if (sub_content.IsAscii()) {
3481 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003482 pat_vector,
3483 start_index);
3484 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003485 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003486 pat_vector,
3487 start_index);
3488 }
3489 }
3490
3491 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003492}
3493
3494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003495RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003496 NoHandleAllocation ha;
3497 ASSERT(args.length() == 2);
3498
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003499 CONVERT_ARG_CHECKED(String, str1, 0);
3500 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003501
3502 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003503 int str1_length = str1->length();
3504 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003505
3506 // Decide trivial cases without flattening.
3507 if (str1_length == 0) {
3508 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3509 return Smi::FromInt(-str2_length);
3510 } else {
3511 if (str2_length == 0) return Smi::FromInt(str1_length);
3512 }
3513
3514 int end = str1_length < str2_length ? str1_length : str2_length;
3515
3516 // No need to flatten if we are going to find the answer on the first
3517 // character. At this point we know there is at least one character
3518 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003519 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003520 if (d != 0) return Smi::FromInt(d);
3521
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003522 str1->TryFlatten();
3523 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003524
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003525 StringInputBuffer& buf1 =
3526 *isolate->runtime_state()->string_locale_compare_buf1();
3527 StringInputBuffer& buf2 =
3528 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003529
3530 buf1.Reset(str1);
3531 buf2.Reset(str2);
3532
3533 for (int i = 0; i < end; i++) {
3534 uint16_t char1 = buf1.GetNext();
3535 uint16_t char2 = buf2.GetNext();
3536 if (char1 != char2) return Smi::FromInt(char1 - char2);
3537 }
3538
3539 return Smi::FromInt(str1_length - str2_length);
3540}
3541
3542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003543RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003544 NoHandleAllocation ha;
3545 ASSERT(args.length() == 3);
3546
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003547 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003548 int start, end;
3549 // We have a fast integer-only case here to avoid a conversion to double in
3550 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003551 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3552 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3553 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3554 start = from_number;
3555 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003556 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003557 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3558 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003559 start = FastD2I(from_number);
3560 end = FastD2I(to_number);
3561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003562 RUNTIME_ASSERT(end >= start);
3563 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003564 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003566 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003567}
3568
3569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003570RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003571 ASSERT_EQ(3, args.length());
3572
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003573 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3574 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3575 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003576 HandleScope handles;
3577
3578 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3579
3580 if (match.is_null()) {
3581 return Failure::Exception();
3582 }
3583 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003584 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003585 }
3586 int length = subject->length();
3587
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003588 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003589 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003590 int start;
3591 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003592 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003593 {
3594 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003595 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003596 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3597 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3598 }
3599 offsets.Add(start);
3600 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003601 if (start == end) if (++end > length) break;
3602 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003603 if (match.is_null()) {
3604 return Failure::Exception();
3605 }
3606 } while (!match->IsNull());
3607 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003608 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003609 Handle<String> substring = isolate->factory()->
3610 NewSubString(subject, offsets.at(0), offsets.at(1));
3611 elements->set(0, *substring);
3612 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003613 int from = offsets.at(i * 2);
3614 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003615 Handle<String> substring = isolate->factory()->
3616 NewProperSubString(subject, from, to);
3617 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003618 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003620 result->set_length(Smi::FromInt(matches));
3621 return *result;
3622}
3623
3624
lrn@chromium.org25156de2010-04-06 13:10:27 +00003625// Two smis before and after the match, for very long strings.
3626const int kMaxBuilderEntriesPerRegExpMatch = 5;
3627
3628
3629static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3630 Handle<JSArray> last_match_info,
3631 int match_start,
3632 int match_end) {
3633 // Fill last_match_info with a single capture.
3634 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3635 AssertNoAllocation no_gc;
3636 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3637 RegExpImpl::SetLastCaptureCount(elements, 2);
3638 RegExpImpl::SetLastInput(elements, *subject);
3639 RegExpImpl::SetLastSubject(elements, *subject);
3640 RegExpImpl::SetCapture(elements, 0, match_start);
3641 RegExpImpl::SetCapture(elements, 1, match_end);
3642}
3643
3644
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003645template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646static bool SearchStringMultiple(Isolate* isolate,
3647 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003648 Vector<const PatternChar> pattern,
3649 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003650 FixedArrayBuilder* builder,
3651 int* match_pos) {
3652 int pos = *match_pos;
3653 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003654 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003655 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003656 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003657 while (pos <= max_search_start) {
3658 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3659 *match_pos = pos;
3660 return false;
3661 }
3662 // Position of end of previous match.
3663 int match_end = pos + pattern_length;
3664 int new_pos = search.Search(subject, match_end);
3665 if (new_pos >= 0) {
3666 // A match.
3667 if (new_pos > match_end) {
3668 ReplacementStringBuilder::AddSubjectSlice(builder,
3669 match_end,
3670 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003671 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003672 pos = new_pos;
3673 builder->Add(pattern_string);
3674 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003675 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003676 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003677 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003678
lrn@chromium.org25156de2010-04-06 13:10:27 +00003679 if (pos < max_search_start) {
3680 ReplacementStringBuilder::AddSubjectSlice(builder,
3681 pos + pattern_length,
3682 subject_length);
3683 }
3684 *match_pos = pos;
3685 return true;
3686}
3687
3688
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003689static bool SearchStringMultiple(Isolate* isolate,
3690 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003691 Handle<String> pattern,
3692 Handle<JSArray> last_match_info,
3693 FixedArrayBuilder* builder) {
3694 ASSERT(subject->IsFlat());
3695 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003696
3697 // Treating as if a previous match was before first character.
3698 int match_pos = -pattern->length();
3699
3700 for (;;) { // Break when search complete.
3701 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3702 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003703 String::FlatContent subject_content = subject->GetFlatContent();
3704 String::FlatContent pattern_content = pattern->GetFlatContent();
3705 if (subject_content.IsAscii()) {
3706 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3707 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003708 if (SearchStringMultiple(isolate,
3709 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003710 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003711 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003712 builder,
3713 &match_pos)) break;
3714 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003715 if (SearchStringMultiple(isolate,
3716 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003717 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003718 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003719 builder,
3720 &match_pos)) break;
3721 }
3722 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003723 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3724 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003725 if (SearchStringMultiple(isolate,
3726 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003727 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003728 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003729 builder,
3730 &match_pos)) break;
3731 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003732 if (SearchStringMultiple(isolate,
3733 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003734 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003735 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003736 builder,
3737 &match_pos)) break;
3738 }
3739 }
3740 }
3741
3742 if (match_pos >= 0) {
3743 SetLastMatchInfoNoCaptures(subject,
3744 last_match_info,
3745 match_pos,
3746 match_pos + pattern->length());
3747 return true;
3748 }
3749 return false; // No matches at all.
3750}
3751
3752
3753static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003754 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003755 Handle<String> subject,
3756 Handle<JSRegExp> regexp,
3757 Handle<JSArray> last_match_array,
3758 FixedArrayBuilder* builder) {
3759 ASSERT(subject->IsFlat());
3760 int match_start = -1;
3761 int match_end = 0;
3762 int pos = 0;
3763 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3764 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3765
ulan@chromium.org812308e2012-02-29 15:58:45 +00003766 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003767 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003768 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003769 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003770
3771 for (;;) { // Break on failure, return on exception.
3772 RegExpImpl::IrregexpResult result =
3773 RegExpImpl::IrregexpExecOnce(regexp,
3774 subject,
3775 pos,
3776 register_vector);
3777 if (result == RegExpImpl::RE_SUCCESS) {
3778 match_start = register_vector[0];
3779 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3780 if (match_end < match_start) {
3781 ReplacementStringBuilder::AddSubjectSlice(builder,
3782 match_end,
3783 match_start);
3784 }
3785 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003786 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003787 if (!first) {
3788 builder->Add(*isolate->factory()->NewProperSubString(subject,
3789 match_start,
3790 match_end));
3791 } else {
3792 builder->Add(*isolate->factory()->NewSubString(subject,
3793 match_start,
3794 match_end));
3795 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003796 if (match_start != match_end) {
3797 pos = match_end;
3798 } else {
3799 pos = match_end + 1;
3800 if (pos > subject_length) break;
3801 }
3802 } else if (result == RegExpImpl::RE_FAILURE) {
3803 break;
3804 } else {
3805 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3806 return result;
3807 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003808 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003809 }
3810
3811 if (match_start >= 0) {
3812 if (match_end < subject_length) {
3813 ReplacementStringBuilder::AddSubjectSlice(builder,
3814 match_end,
3815 subject_length);
3816 }
3817 SetLastMatchInfoNoCaptures(subject,
3818 last_match_array,
3819 match_start,
3820 match_end);
3821 return RegExpImpl::RE_SUCCESS;
3822 } else {
3823 return RegExpImpl::RE_FAILURE; // No matches at all.
3824 }
3825}
3826
3827
3828static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003829 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003830 Handle<String> subject,
3831 Handle<JSRegExp> regexp,
3832 Handle<JSArray> last_match_array,
3833 FixedArrayBuilder* builder) {
3834
3835 ASSERT(subject->IsFlat());
3836 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3837 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3838
ulan@chromium.org812308e2012-02-29 15:58:45 +00003839 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003840 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003841
3842 RegExpImpl::IrregexpResult result =
3843 RegExpImpl::IrregexpExecOnce(regexp,
3844 subject,
3845 0,
3846 register_vector);
3847
3848 int capture_count = regexp->CaptureCount();
3849 int subject_length = subject->length();
3850
3851 // Position to search from.
3852 int pos = 0;
3853 // End of previous match. Differs from pos if match was empty.
3854 int match_end = 0;
3855 if (result == RegExpImpl::RE_SUCCESS) {
3856 // Need to keep a copy of the previous match for creating last_match_info
3857 // at the end, so we have two vectors that we swap between.
ulan@chromium.org812308e2012-02-29 15:58:45 +00003858 OffsetsVector registers2(required_registers, isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003859 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003860 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003861 do {
3862 int match_start = register_vector[0];
3863 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3864 if (match_end < match_start) {
3865 ReplacementStringBuilder::AddSubjectSlice(builder,
3866 match_end,
3867 match_start);
3868 }
3869 match_end = register_vector[1];
3870
3871 {
3872 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003873 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003874 // Arguments array to replace function is match, captures, index and
3875 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003876 Handle<FixedArray> elements =
3877 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003878 Handle<String> match;
3879 if (!first) {
3880 match = isolate->factory()->NewProperSubString(subject,
3881 match_start,
3882 match_end);
3883 } else {
3884 match = isolate->factory()->NewSubString(subject,
3885 match_start,
3886 match_end);
3887 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003888 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003889 for (int i = 1; i <= capture_count; i++) {
3890 int start = register_vector[i * 2];
3891 if (start >= 0) {
3892 int end = register_vector[i * 2 + 1];
3893 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003894 Handle<String> substring;
3895 if (!first) {
3896 substring = isolate->factory()->NewProperSubString(subject,
3897 start,
3898 end);
3899 } else {
3900 substring = isolate->factory()->NewSubString(subject, start, end);
3901 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003902 elements->set(i, *substring);
3903 } else {
3904 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003905 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003906 }
3907 }
3908 elements->set(capture_count + 1, Smi::FromInt(match_start));
3909 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003910 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003911 }
3912 // Swap register vectors, so the last successful match is in
3913 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003914 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003915 prev_register_vector = register_vector;
3916 register_vector = tmp;
3917
3918 if (match_end > match_start) {
3919 pos = match_end;
3920 } else {
3921 pos = match_end + 1;
3922 if (pos > subject_length) {
3923 break;
3924 }
3925 }
3926
3927 result = RegExpImpl::IrregexpExecOnce(regexp,
3928 subject,
3929 pos,
3930 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003931 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003932 } while (result == RegExpImpl::RE_SUCCESS);
3933
3934 if (result != RegExpImpl::RE_EXCEPTION) {
3935 // Finished matching, with at least one match.
3936 if (match_end < subject_length) {
3937 ReplacementStringBuilder::AddSubjectSlice(builder,
3938 match_end,
3939 subject_length);
3940 }
3941
3942 int last_match_capture_count = (capture_count + 1) * 2;
3943 int last_match_array_size =
3944 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3945 last_match_array->EnsureSize(last_match_array_size);
3946 AssertNoAllocation no_gc;
3947 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3948 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3949 RegExpImpl::SetLastSubject(elements, *subject);
3950 RegExpImpl::SetLastInput(elements, *subject);
3951 for (int i = 0; i < last_match_capture_count; i++) {
3952 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3953 }
3954 return RegExpImpl::RE_SUCCESS;
3955 }
3956 }
3957 // No matches at all, return failure or exception result directly.
3958 return result;
3959}
3960
3961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003962RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003963 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003964 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003965
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003966 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003967 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003968 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3969 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3970 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003971
3972 ASSERT(last_match_info->HasFastElements());
3973 ASSERT(regexp->GetFlags().is_global());
3974 Handle<FixedArray> result_elements;
3975 if (result_array->HasFastElements()) {
3976 result_elements =
3977 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003978 }
3979 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003980 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003981 }
3982 FixedArrayBuilder builder(result_elements);
3983
3984 if (regexp->TypeTag() == JSRegExp::ATOM) {
3985 Handle<String> pattern(
3986 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003987 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 if (SearchStringMultiple(isolate, subject, pattern,
3989 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003990 return *builder.ToJSArray(result_array);
3991 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003992 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003993 }
3994
3995 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3996
3997 RegExpImpl::IrregexpResult result;
3998 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003999 result = SearchRegExpNoCaptureMultiple(isolate,
4000 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004001 regexp,
4002 last_match_info,
4003 &builder);
4004 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004005 result = SearchRegExpMultiple(isolate,
4006 subject,
4007 regexp,
4008 last_match_info,
4009 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004010 }
4011 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004012 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004013 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4014 return Failure::Exception();
4015}
4016
4017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004018RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 NoHandleAllocation ha;
4020 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004021 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004022 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004024 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004025 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004026 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004027 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004028 // Character array used for conversion.
4029 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004030 return isolate->heap()->
4031 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004032 }
4033 }
4034
4035 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004036 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004037 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004038 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039 }
4040 if (isinf(value)) {
4041 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004042 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004043 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004044 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004047 MaybeObject* result =
4048 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004049 DeleteArray(str);
4050 return result;
4051}
4052
4053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004054RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004055 NoHandleAllocation ha;
4056 ASSERT(args.length() == 2);
4057
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004058 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004060 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061 }
4062 if (isinf(value)) {
4063 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004064 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004066 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004068 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 int f = FastD2I(f_number);
4070 RUNTIME_ASSERT(f >= 0);
4071 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004072 MaybeObject* res =
4073 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004075 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076}
4077
4078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004079RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004080 NoHandleAllocation ha;
4081 ASSERT(args.length() == 2);
4082
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004083 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004085 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 }
4087 if (isinf(value)) {
4088 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004089 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004091 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004093 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 int f = FastD2I(f_number);
4095 RUNTIME_ASSERT(f >= -1 && f <= 20);
4096 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004097 MaybeObject* res =
4098 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004100 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101}
4102
4103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004104RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004105 NoHandleAllocation ha;
4106 ASSERT(args.length() == 2);
4107
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004108 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004110 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 }
4112 if (isinf(value)) {
4113 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004114 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004116 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004118 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 int f = FastD2I(f_number);
4120 RUNTIME_ASSERT(f >= 1 && f <= 21);
4121 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004122 MaybeObject* res =
4123 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004125 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126}
4127
4128
4129// Returns a single character string where first character equals
4130// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004131static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004132 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004133 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004134 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004135 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004137 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138}
4139
4140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004141MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4142 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004143 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004144 // Handle [] indexing on Strings
4145 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004146 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4147 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004148 }
4149
4150 // Handle [] indexing on String objects
4151 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004152 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4153 Handle<Object> result =
4154 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4155 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156 }
4157
4158 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004159 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160 }
4161
4162 return object->GetElement(index);
4163}
4164
4165
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004166MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4167 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004168 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004169 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004170
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004172 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004174 isolate->factory()->NewTypeError("non_object_property_load",
4175 HandleVector(args, 2));
4176 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 }
4178
4179 // Check if the given key is an array index.
4180 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004181 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004182 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004183 }
4184
4185 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004186 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004188 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 bool has_pending_exception = false;
4191 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004192 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004193 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004194 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 }
4196
ager@chromium.org32912102009-01-16 10:38:43 +00004197 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198 // the element if so.
4199 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004200 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004202 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 }
4204}
4205
4206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004207RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 NoHandleAllocation ha;
4209 ASSERT(args.length() == 2);
4210
4211 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004212 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004214 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004215}
4216
4217
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004218// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004219RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004220 NoHandleAllocation ha;
4221 ASSERT(args.length() == 2);
4222
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004223 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004224 // itself.
4225 //
4226 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004227 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004228 // global proxy object never has properties. This is the case
4229 // because the global proxy object forwards everything to its hidden
4230 // prototype including local lookups.
4231 //
4232 // Additionally, we need to make sure that we do not cache results
4233 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004234 if (args[0]->IsJSObject()) {
4235 if (!args[0]->IsJSGlobalProxy() &&
4236 !args[0]->IsAccessCheckNeeded() &&
4237 args[1]->IsString()) {
4238 JSObject* receiver = JSObject::cast(args[0]);
4239 String* key = String::cast(args[1]);
4240 if (receiver->HasFastProperties()) {
4241 // Attempt to use lookup cache.
4242 Map* receiver_map = receiver->map();
4243 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4244 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4245 if (offset != -1) {
4246 Object* value = receiver->FastPropertyAt(offset);
4247 return value->IsTheHole()
4248 ? isolate->heap()->undefined_value()
4249 : value;
4250 }
4251 // Lookup cache miss. Perform lookup and update the cache if
4252 // appropriate.
4253 LookupResult result(isolate);
4254 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004255 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004256 int offset = result.GetFieldIndex();
4257 keyed_lookup_cache->Update(receiver_map, key, offset);
4258 return receiver->FastPropertyAt(offset);
4259 }
4260 } else {
4261 // Attempt dictionary lookup.
4262 StringDictionary* dictionary = receiver->property_dictionary();
4263 int entry = dictionary->FindEntry(key);
4264 if ((entry != StringDictionary::kNotFound) &&
4265 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4266 Object* value = dictionary->ValueAt(entry);
4267 if (!receiver->IsGlobalObject()) return value;
4268 value = JSGlobalPropertyCell::cast(value)->value();
4269 if (!value->IsTheHole()) return value;
4270 // If value is the hole do the general lookup.
4271 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004272 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004273 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4274 // JSObject without a string key. If the key is a Smi, check for a
4275 // definite out-of-bounds access to elements, which is a strong indicator
4276 // that subsequent accesses will also call the runtime. Proactively
4277 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4278 // doubles for those future calls in the case that the elements would
4279 // become FAST_DOUBLE_ELEMENTS.
4280 Handle<JSObject> js_object(args.at<JSObject>(0));
4281 ElementsKind elements_kind = js_object->GetElementsKind();
4282 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4283 elements_kind == FAST_DOUBLE_ELEMENTS) {
4284 FixedArrayBase* elements = js_object->elements();
4285 if (args.at<Smi>(1)->value() >= elements->length()) {
4286 MaybeObject* maybe_object = TransitionElements(js_object,
4287 FAST_ELEMENTS,
4288 isolate);
4289 if (maybe_object->IsFailure()) return maybe_object;
4290 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004291 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004292 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004293 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4294 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004295 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004296 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004297 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004298 if (index >= 0 && index < str->length()) {
4299 Handle<Object> result = GetCharAt(str, index);
4300 return *result;
4301 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004302 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004303
4304 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004305 return Runtime::GetObjectProperty(isolate,
4306 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004307 args.at<Object>(1));
4308}
4309
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004310// Implements part of 8.12.9 DefineOwnProperty.
4311// There are 3 cases that lead here:
4312// Step 4b - define a new accessor property.
4313// Steps 9c & 12 - replace an existing data property with an accessor property.
4314// Step 12 - update an existing accessor property with an accessor or generic
4315// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004316RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004317 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004318 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004319 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
4320 CONVERT_ARG_CHECKED(String, name, 1);
4321 CONVERT_SMI_ARG_CHECKED(flag_setter, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004322 Object* fun = args[3];
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004323 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004324
ager@chromium.org5c838252010-02-19 08:53:10 +00004325 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004326 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004327
4328 RUNTIME_ASSERT(!obj->IsNull());
4329 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004330 return obj->DefineAccessor(name, flag_setter == 0, fun, attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004331}
4332
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004333// Implements part of 8.12.9 DefineOwnProperty.
4334// There are 3 cases that lead here:
4335// Step 4a - define a new data property.
4336// Steps 9b & 12 - replace an existing accessor property with a data property.
4337// Step 12 - update an existing data property with a data or generic
4338// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004339RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004340 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004341 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004342 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4343 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00004344 Handle<Object> obj_value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004345 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004346
ager@chromium.org5c838252010-02-19 08:53:10 +00004347 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004348 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4349
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004350 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004351 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004352
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004353 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004354 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004355 Object* callback = result.GetCallbackObject();
4356 // To be compatible with Safari we do not change the value on API objects
4357 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4358 // the value.
4359 if (callback->IsAccessorInfo()) {
4360 return isolate->heap()->undefined_value();
4361 }
4362 // Avoid redefining foreign callback as data property, just use the stored
4363 // setter to update the value instead.
4364 // TODO(mstarzinger): So far this only works if property attributes don't
4365 // change, this should be fixed once we cleanup the underlying code.
4366 if (callback->IsForeign() && result.GetAttributes() == attr) {
4367 return js_object->SetPropertyWithCallback(callback,
4368 *name,
4369 *obj_value,
4370 result.holder(),
4371 kStrictMode);
4372 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004373 }
4374
ager@chromium.org5c838252010-02-19 08:53:10 +00004375 // Take special care when attributes are different and there is already
4376 // a property. For simplicity we normalize the property which enables us
4377 // to not worry about changing the instance_descriptor and creating a new
4378 // map. The current version of SetObjectProperty does not handle attributes
4379 // correctly in the case where a property is a field and is reset with
4380 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004381 if (result.IsProperty() &&
4382 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004383 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004384 if (js_object->IsJSGlobalProxy()) {
4385 // Since the result is a property, the prototype will exist so
4386 // we don't have to check for null.
4387 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004388 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004389 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004390 // Use IgnoreAttributes version since a readonly property may be
4391 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004392 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4393 *obj_value,
4394 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004395 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004396
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004397 return Runtime::ForceSetObjectProperty(isolate,
4398 js_object,
4399 name,
4400 obj_value,
4401 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004402}
4403
4404
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004405MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4406 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004407 Handle<Object> key,
4408 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004409 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004410 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004411 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004412 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004414 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004415 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004416 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004417 isolate->factory()->NewTypeError("non_object_property_store",
4418 HandleVector(args, 2));
4419 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004420 }
4421
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004422 if (object->IsJSProxy()) {
4423 bool has_pending_exception = false;
4424 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4425 if (has_pending_exception) return Failure::Exception();
4426 return JSProxy::cast(*object)->SetProperty(
4427 String::cast(*name), *value, attr, strict_mode);
4428 }
4429
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004430 // If the object isn't a JavaScript object, we ignore the store.
4431 if (!object->IsJSObject()) return *value;
4432
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004433 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4434
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004435 // Check if the given key is an array index.
4436 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004437 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4439 // of a string using [] notation. We need to support this too in
4440 // JavaScript.
4441 // In the case of a String object we just need to redirect the assignment to
4442 // the underlying string if the index is in range. Since the underlying
4443 // string does nothing with the assignment then we can ignore such
4444 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004445 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004446 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004447 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004449 Handle<Object> result = JSObject::SetElement(
4450 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004451 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004452 return *value;
4453 }
4454
4455 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004456 Handle<Object> result;
4457 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004458 result = JSObject::SetElement(
4459 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004460 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004461 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004462 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004463 result = JSReceiver::SetProperty(
4464 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004465 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004466 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 return *value;
4468 }
4469
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004470 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 bool has_pending_exception = false;
4472 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4473 if (has_pending_exception) return Failure::Exception();
4474 Handle<String> name = Handle<String>::cast(converted);
4475
4476 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004477 return js_object->SetElement(
4478 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004479 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004480 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 }
4482}
4483
4484
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004485MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4486 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004487 Handle<Object> key,
4488 Handle<Object> value,
4489 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004490 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004491
4492 // Check if the given key is an array index.
4493 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004494 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004495 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4496 // of a string using [] notation. We need to support this too in
4497 // JavaScript.
4498 // In the case of a String object we just need to redirect the assignment to
4499 // the underlying string if the index is in range. Since the underlying
4500 // string does nothing with the assignment then we can ignore such
4501 // assignments.
4502 if (js_object->IsStringObjectWithCharacterAt(index)) {
4503 return *value;
4504 }
4505
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004506 return js_object->SetElement(
4507 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004508 }
4509
4510 if (key->IsString()) {
4511 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004512 return js_object->SetElement(
4513 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004514 } else {
4515 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004516 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004517 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4518 *value,
4519 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004520 }
4521 }
4522
4523 // Call-back into JavaScript to convert the key to a string.
4524 bool has_pending_exception = false;
4525 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4526 if (has_pending_exception) return Failure::Exception();
4527 Handle<String> name = Handle<String>::cast(converted);
4528
4529 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004530 return js_object->SetElement(
4531 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004532 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004533 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004534 }
4535}
4536
4537
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004538MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004539 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004540 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004541 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004542
4543 // Check if the given key is an array index.
4544 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004545 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004546 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4547 // characters of a string using [] notation. In the case of a
4548 // String object we just need to redirect the deletion to the
4549 // underlying string if the index is in range. Since the
4550 // underlying string does nothing with the deletion, we can ignore
4551 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004552 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004553 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004554 }
4555
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004556 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004557 }
4558
4559 Handle<String> key_string;
4560 if (key->IsString()) {
4561 key_string = Handle<String>::cast(key);
4562 } else {
4563 // Call-back into JavaScript to convert the key to a string.
4564 bool has_pending_exception = false;
4565 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4566 if (has_pending_exception) return Failure::Exception();
4567 key_string = Handle<String>::cast(converted);
4568 }
4569
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004570 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004571 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004572}
4573
4574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004575RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004576 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004577 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004578
4579 Handle<Object> object = args.at<Object>(0);
4580 Handle<Object> key = args.at<Object>(1);
4581 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004582 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004583 RUNTIME_ASSERT(
4584 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004585 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004586 PropertyAttributes attributes =
4587 static_cast<PropertyAttributes>(unchecked_attributes);
4588
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004589 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004590 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004591 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004592 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004594
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004595 return Runtime::SetObjectProperty(isolate,
4596 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004597 key,
4598 value,
4599 attributes,
4600 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601}
4602
4603
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004604RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4605 NoHandleAllocation ha;
4606 RUNTIME_ASSERT(args.length() == 1);
4607 Handle<Object> object = args.at<Object>(0);
4608 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4609}
4610
4611
4612RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4613 NoHandleAllocation ha;
4614 RUNTIME_ASSERT(args.length() == 1);
4615 Handle<Object> object = args.at<Object>(0);
4616 return TransitionElements(object, FAST_ELEMENTS, isolate);
4617}
4618
4619
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004620// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004621// This is used to decide if we should transform null and undefined
4622// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004623RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004624 NoHandleAllocation ha;
4625 RUNTIME_ASSERT(args.length() == 1);
4626
4627 Handle<Object> object = args.at<Object>(0);
4628
4629 if (object->IsJSFunction()) {
4630 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004631 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004632 }
4633 return isolate->heap()->undefined_value();
4634}
4635
4636
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004637RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4638 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004639 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004640 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4641 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004642 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004643 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4644 HandleScope scope;
4645
4646 Object* raw_boilerplate_object = literals->get(literal_index);
4647 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4648#if DEBUG
4649 ElementsKind elements_kind = object->GetElementsKind();
4650#endif
4651 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4652 // Smis should never trigger transitions.
4653 ASSERT(!value->IsSmi());
4654
4655 if (value->IsNumber()) {
4656 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004657 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4658 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004659 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4660 FixedDoubleArray* double_array =
4661 FixedDoubleArray::cast(object->elements());
4662 HeapNumber* number = HeapNumber::cast(*value);
4663 double_array->set(store_index, number->Number());
4664 } else {
4665 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4666 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004667 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4668 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004669 FixedArray* object_array =
4670 FixedArray::cast(object->elements());
4671 object_array->set(store_index, *value);
4672 }
4673 return *object;
4674}
4675
4676
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004677// Set a local property, even if it is READ_ONLY. If the property does not
4678// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004679RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004680 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004681 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004682 CONVERT_ARG_CHECKED(JSObject, object, 0);
4683 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004684 // Compute attributes.
4685 PropertyAttributes attributes = NONE;
4686 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004687 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004688 // Only attribute bits should be set.
4689 RUNTIME_ASSERT(
4690 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4691 attributes = static_cast<PropertyAttributes>(unchecked_value);
4692 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004693
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004694 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004695 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004696}
4697
4698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004699RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004700 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004701 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004703 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4704 CONVERT_ARG_CHECKED(String, key, 1);
4705 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004706 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004707 ? JSReceiver::STRICT_DELETION
4708 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004709}
4710
4711
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712static Object* HasLocalPropertyImplementation(Isolate* isolate,
4713 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004714 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004715 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004716 // Handle hidden prototypes. If there's a hidden prototype above this thing
4717 // then we have to check it for properties, because they are supposed to
4718 // look like they are on this object.
4719 Handle<Object> proto(object->GetPrototype());
4720 if (proto->IsJSObject() &&
4721 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004722 return HasLocalPropertyImplementation(isolate,
4723 Handle<JSObject>::cast(proto),
4724 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004725 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004726 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004727}
4728
4729
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004730RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004731 NoHandleAllocation ha;
4732 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004733 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004735 uint32_t index;
4736 const bool key_is_array_index = key->AsArrayIndex(&index);
4737
ager@chromium.org9085a012009-05-11 19:22:57 +00004738 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004739 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004740 if (obj->IsJSObject()) {
4741 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004742 // Fast case: either the key is a real named property or it is not
4743 // an array index and there are no interceptors or hidden
4744 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004745 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004746 Map* map = object->map();
4747 if (!key_is_array_index &&
4748 !map->has_named_interceptor() &&
4749 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4750 return isolate->heap()->false_value();
4751 }
4752 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004753 HandleScope scope(isolate);
4754 return HasLocalPropertyImplementation(isolate,
4755 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004756 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004757 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004758 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004759 String* string = String::cast(obj);
4760 if (index < static_cast<uint32_t>(string->length())) {
4761 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 }
4763 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004764 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765}
4766
4767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004768RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 NoHandleAllocation na;
4770 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004771 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4772 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004773
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004774 bool result = receiver->HasProperty(key);
4775 if (isolate->has_pending_exception()) return Failure::Exception();
4776 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004777}
4778
4779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004780RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 NoHandleAllocation na;
4782 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004783 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4784 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004786 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004787 if (isolate->has_pending_exception()) return Failure::Exception();
4788 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004789}
4790
4791
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004792RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793 NoHandleAllocation ha;
4794 ASSERT(args.length() == 2);
4795
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004796 CONVERT_ARG_CHECKED(JSObject, object, 0);
4797 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798
4799 uint32_t index;
4800 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004801 JSObject::LocalElementType type = object->HasLocalElement(index);
4802 switch (type) {
4803 case JSObject::UNDEFINED_ELEMENT:
4804 case JSObject::STRING_CHARACTER_ELEMENT:
4805 return isolate->heap()->false_value();
4806 case JSObject::INTERCEPTED_ELEMENT:
4807 case JSObject::FAST_ELEMENT:
4808 return isolate->heap()->true_value();
4809 case JSObject::DICTIONARY_ELEMENT: {
4810 if (object->IsJSGlobalProxy()) {
4811 Object* proto = object->GetPrototype();
4812 if (proto->IsNull()) {
4813 return isolate->heap()->false_value();
4814 }
4815 ASSERT(proto->IsJSGlobalObject());
4816 object = JSObject::cast(proto);
4817 }
4818 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004819 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004820 if (elements->map() ==
4821 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004822 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004823 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004824 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004825 }
4826 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004827 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004828 PropertyDetails details = dictionary->DetailsAt(entry);
4829 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4830 }
4831 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004832 }
4833
ager@chromium.org870a0b62008-11-04 11:43:05 +00004834 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004835 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836}
4837
4838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004839RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004840 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004841 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004842 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004843 bool threw = false;
4844 Handle<JSArray> result = GetKeysFor(object, &threw);
4845 if (threw) return Failure::Exception();
4846 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847}
4848
4849
4850// Returns either a FixedArray as Runtime_GetPropertyNames,
4851// or, if the given object has an enum cache that contains
4852// all enumerable properties of the object and its prototypes
4853// have none, the map of the object. This is used to speed up
4854// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004855RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856 ASSERT(args.length() == 1);
4857
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004858 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004859
4860 if (raw_object->IsSimpleEnum()) return raw_object->map();
4861
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004862 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004863 Handle<JSReceiver> object(raw_object);
4864 bool threw = false;
4865 Handle<FixedArray> content =
4866 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4867 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004868
4869 // Test again, since cache may have been built by preceding call.
4870 if (object->IsSimpleEnum()) return object->map();
4871
4872 return *content;
4873}
4874
4875
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004876// Find the length of the prototype chain that is to to handled as one. If a
4877// prototype object is hidden it is to be viewed as part of the the object it
4878// is prototype for.
4879static int LocalPrototypeChainLength(JSObject* obj) {
4880 int count = 1;
4881 Object* proto = obj->GetPrototype();
4882 while (proto->IsJSObject() &&
4883 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4884 count++;
4885 proto = JSObject::cast(proto)->GetPrototype();
4886 }
4887 return count;
4888}
4889
4890
4891// Return the names of the local named properties.
4892// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004893RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004894 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004895 ASSERT(args.length() == 1);
4896 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004897 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004898 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004899 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004900
4901 // Skip the global proxy as it has no properties and always delegates to the
4902 // real global object.
4903 if (obj->IsJSGlobalProxy()) {
4904 // Only collect names if access is permitted.
4905 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004906 !isolate->MayNamedAccess(*obj,
4907 isolate->heap()->undefined_value(),
4908 v8::ACCESS_KEYS)) {
4909 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4910 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004911 }
4912 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4913 }
4914
4915 // Find the number of objects making up this.
4916 int length = LocalPrototypeChainLength(*obj);
4917
4918 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004919 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004920 int total_property_count = 0;
4921 Handle<JSObject> jsproto = obj;
4922 for (int i = 0; i < length; i++) {
4923 // Only collect names if access is permitted.
4924 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004925 !isolate->MayNamedAccess(*jsproto,
4926 isolate->heap()->undefined_value(),
4927 v8::ACCESS_KEYS)) {
4928 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4929 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004930 }
4931 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004932 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004933 local_property_count[i] = n;
4934 total_property_count += n;
4935 if (i < length - 1) {
4936 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4937 }
4938 }
4939
4940 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004941 Handle<FixedArray> names =
4942 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004943
4944 // Get the property names.
4945 jsproto = obj;
4946 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004947 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004948 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004949 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4950 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004951 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004952 proto_with_hidden_properties++;
4953 }
4954 if (i < length - 1) {
4955 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4956 }
4957 }
4958
4959 // Filter out name of hidden propeties object.
4960 if (proto_with_hidden_properties > 0) {
4961 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004962 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004963 names->length() - proto_with_hidden_properties);
4964 int dest_pos = 0;
4965 for (int i = 0; i < total_property_count; i++) {
4966 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004967 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004968 continue;
4969 }
4970 names->set(dest_pos++, name);
4971 }
4972 }
4973
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004974 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004975}
4976
4977
4978// Return the names of the local indexed properties.
4979// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004980RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004981 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004982 ASSERT(args.length() == 1);
4983 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004984 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004985 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004986 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004987
4988 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004989 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004990 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004991 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004992}
4993
4994
4995// Return information on whether an object has a named or indexed interceptor.
4996// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004997RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004998 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004999 ASSERT(args.length() == 1);
5000 if (!args[0]->IsJSObject()) {
5001 return Smi::FromInt(0);
5002 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005003 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005004
5005 int result = 0;
5006 if (obj->HasNamedInterceptor()) result |= 2;
5007 if (obj->HasIndexedInterceptor()) result |= 1;
5008
5009 return Smi::FromInt(result);
5010}
5011
5012
5013// Return property names from named interceptor.
5014// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005015RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005017 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005018 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005019
5020 if (obj->HasNamedInterceptor()) {
5021 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5022 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5023 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005024 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005025}
5026
5027
5028// Return element names from indexed interceptor.
5029// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005030RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005031 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005032 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005033 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005034
5035 if (obj->HasIndexedInterceptor()) {
5036 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5037 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5038 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005039 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005040}
5041
5042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005043RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005044 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005045 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005046 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005047 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005048
5049 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005050 // Do access checks before going to the global object.
5051 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005052 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005053 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005054 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5055 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005056 }
5057
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005058 Handle<Object> proto(object->GetPrototype());
5059 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005060 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005061 object = Handle<JSObject>::cast(proto);
5062 }
5063
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005064 bool threw = false;
5065 Handle<FixedArray> contents =
5066 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5067 if (threw) return Failure::Exception();
5068
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005069 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5070 // property array and since the result is mutable we have to create
5071 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005072 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005073 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005074 for (int i = 0; i < length; i++) {
5075 Object* entry = contents->get(i);
5076 if (entry->IsString()) {
5077 copy->set(i, entry);
5078 } else {
5079 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005080 HandleScope scope(isolate);
5081 Handle<Object> entry_handle(entry, isolate);
5082 Handle<Object> entry_str =
5083 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005084 copy->set(i, *entry_str);
5085 }
5086 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005088}
5089
5090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005091RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005092 NoHandleAllocation ha;
5093 ASSERT(args.length() == 1);
5094
5095 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005096 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005097 it.AdvanceToArgumentsFrame();
5098 JavaScriptFrame* frame = it.frame();
5099
5100 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005101 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005102
5103 // Try to convert the key to an index. If successful and within
5104 // index return the the argument from the frame.
5105 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005106 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005107 return frame->GetParameter(index);
5108 }
5109
5110 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005111 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005112 bool exception = false;
5113 Handle<Object> converted =
5114 Execution::ToString(args.at<Object>(0), &exception);
5115 if (exception) return Failure::Exception();
5116 Handle<String> key = Handle<String>::cast(converted);
5117
5118 // Try to convert the string key into an array index.
5119 if (key->AsArrayIndex(&index)) {
5120 if (index < n) {
5121 return frame->GetParameter(index);
5122 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005123 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005124 }
5125 }
5126
5127 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005128 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5129 if (key->Equals(isolate->heap()->callee_symbol())) {
5130 Object* function = frame->function();
5131 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005132 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005133 return isolate->Throw(*isolate->factory()->NewTypeError(
5134 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5135 }
5136 return function;
5137 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005138
5139 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005140 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005141}
5142
5143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005144RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005145 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005146 Object* object = args[0];
5147 return (object->IsJSObject() && !object->IsGlobalObject())
5148 ? JSObject::cast(object)->TransformToFastProperties(0)
5149 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005150}
5151
5152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005153RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005154 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005155 Object* obj = args[0];
5156 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5157 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5158 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005159}
5160
5161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005162RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005163 NoHandleAllocation ha;
5164 ASSERT(args.length() == 1);
5165
5166 return args[0]->ToBoolean();
5167}
5168
5169
5170// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5171// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005172RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005173 NoHandleAllocation ha;
5174
5175 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005176 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005177 HeapObject* heap_obj = HeapObject::cast(obj);
5178
5179 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005180 if (heap_obj->map()->is_undetectable()) {
5181 return isolate->heap()->undefined_symbol();
5182 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005183
5184 InstanceType instance_type = heap_obj->map()->instance_type();
5185 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005186 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005187 }
5188
5189 switch (instance_type) {
5190 case ODDBALL_TYPE:
5191 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005192 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005193 }
5194 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005195 return FLAG_harmony_typeof
5196 ? isolate->heap()->null_symbol()
5197 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198 }
5199 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005200 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005201 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005202 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005203 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005204 default:
5205 // For any kind of object not handled above, the spec rule for
5206 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005207 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208 }
5209}
5210
5211
lrn@chromium.org25156de2010-04-06 13:10:27 +00005212static bool AreDigits(const char*s, int from, int to) {
5213 for (int i = from; i < to; i++) {
5214 if (s[i] < '0' || s[i] > '9') return false;
5215 }
5216
5217 return true;
5218}
5219
5220
5221static int ParseDecimalInteger(const char*s, int from, int to) {
5222 ASSERT(to - from < 10); // Overflow is not possible.
5223 ASSERT(from < to);
5224 int d = s[from] - '0';
5225
5226 for (int i = from + 1; i < to; i++) {
5227 d = 10 * d + (s[i] - '0');
5228 }
5229
5230 return d;
5231}
5232
5233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005234RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005235 NoHandleAllocation ha;
5236 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005237 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005238 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005239
5240 // Fast case: short integer or some sorts of junk values.
5241 int len = subject->length();
5242 if (subject->IsSeqAsciiString()) {
5243 if (len == 0) return Smi::FromInt(0);
5244
5245 char const* data = SeqAsciiString::cast(subject)->GetChars();
5246 bool minus = (data[0] == '-');
5247 int start_pos = (minus ? 1 : 0);
5248
5249 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005250 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005251 } else if (data[start_pos] > '9') {
5252 // Fast check for a junk value. A valid string may start from a
5253 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5254 // the 'I' character ('Infinity'). All of that have codes not greater than
5255 // '9' except 'I'.
5256 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005257 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005258 }
5259 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5260 // The maximal/minimal smi has 10 digits. If the string has less digits we
5261 // know it will fit into the smi-data type.
5262 int d = ParseDecimalInteger(data, start_pos, len);
5263 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005264 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005265 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005266 } else if (!subject->HasHashCode() &&
5267 len <= String::kMaxArrayIndexSize &&
5268 (len == 1 || data[0] != '0')) {
5269 // String hash is not calculated yet but all the data are present.
5270 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005271 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005272#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005273 subject->Hash(); // Force hash calculation.
5274 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5275 static_cast<int>(hash));
5276#endif
5277 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005278 }
5279 return Smi::FromInt(d);
5280 }
5281 }
5282
5283 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005284 return isolate->heap()->NumberFromDouble(
5285 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005286}
5287
5288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005289RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005290 NoHandleAllocation ha;
5291 ASSERT(args.length() == 1);
5292
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005293 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005294 int length = Smi::cast(codes->length())->value();
5295
5296 // Check if the string can be ASCII.
5297 int i;
5298 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005299 Object* element;
5300 { MaybeObject* maybe_element = codes->GetElement(i);
5301 // We probably can't get an exception here, but just in order to enforce
5302 // the checking of inputs in the runtime calls we check here.
5303 if (!maybe_element->ToObject(&element)) return maybe_element;
5304 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005305 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5306 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5307 break;
5308 }
5309
lrn@chromium.org303ada72010-10-27 09:33:13 +00005310 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005312 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005313 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005314 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315 }
5316
lrn@chromium.org303ada72010-10-27 09:33:13 +00005317 Object* object = NULL;
5318 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 String* result = String::cast(object);
5320 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005321 Object* element;
5322 { MaybeObject* maybe_element = codes->GetElement(i);
5323 if (!maybe_element->ToObject(&element)) return maybe_element;
5324 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005325 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005326 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005327 }
5328 return result;
5329}
5330
5331
5332// kNotEscaped is generated by the following:
5333//
5334// #!/bin/perl
5335// for (my $i = 0; $i < 256; $i++) {
5336// print "\n" if $i % 16 == 0;
5337// my $c = chr($i);
5338// my $escaped = 1;
5339// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5340// print $escaped ? "0, " : "1, ";
5341// }
5342
5343
5344static bool IsNotEscaped(uint16_t character) {
5345 // Only for 8 bit characters, the rest are always escaped (in a different way)
5346 ASSERT(character < 256);
5347 static const char kNotEscaped[256] = {
5348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5351 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5353 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5354 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5355 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5364 };
5365 return kNotEscaped[character] != 0;
5366}
5367
5368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005369RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 const char hex_chars[] = "0123456789ABCDEF";
5371 NoHandleAllocation ha;
5372 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005373 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005374
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005375 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005376
5377 int escaped_length = 0;
5378 int length = source->length();
5379 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005380 Access<StringInputBuffer> buffer(
5381 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005382 buffer->Reset(source);
5383 while (buffer->has_more()) {
5384 uint16_t character = buffer->GetNext();
5385 if (character >= 256) {
5386 escaped_length += 6;
5387 } else if (IsNotEscaped(character)) {
5388 escaped_length++;
5389 } else {
5390 escaped_length += 3;
5391 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005392 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005393 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005394 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005395 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005396 return Failure::OutOfMemoryException();
5397 }
5398 }
5399 }
5400 // No length change implies no change. Return original string if no change.
5401 if (escaped_length == length) {
5402 return source;
5403 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005404 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005405 { MaybeObject* maybe_o =
5406 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005407 if (!maybe_o->ToObject(&o)) return maybe_o;
5408 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409 String* destination = String::cast(o);
5410 int dest_position = 0;
5411
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005412 Access<StringInputBuffer> buffer(
5413 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005414 buffer->Rewind();
5415 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005416 uint16_t chr = buffer->GetNext();
5417 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005418 destination->Set(dest_position, '%');
5419 destination->Set(dest_position+1, 'u');
5420 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5421 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5422 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5423 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005424 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005425 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005426 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005427 dest_position++;
5428 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005429 destination->Set(dest_position, '%');
5430 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5431 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005432 dest_position += 3;
5433 }
5434 }
5435 return destination;
5436}
5437
5438
5439static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5440 static const signed char kHexValue['g'] = {
5441 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5442 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5443 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5444 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5445 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5446 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5447 -1, 10, 11, 12, 13, 14, 15 };
5448
5449 if (character1 > 'f') return -1;
5450 int hi = kHexValue[character1];
5451 if (hi == -1) return -1;
5452 if (character2 > 'f') return -1;
5453 int lo = kHexValue[character2];
5454 if (lo == -1) return -1;
5455 return (hi << 4) + lo;
5456}
5457
5458
ager@chromium.org870a0b62008-11-04 11:43:05 +00005459static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005460 int i,
5461 int length,
5462 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005463 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005464 int32_t hi = 0;
5465 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005466 if (character == '%' &&
5467 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005468 source->Get(i + 1) == 'u' &&
5469 (hi = TwoDigitHex(source->Get(i + 2),
5470 source->Get(i + 3))) != -1 &&
5471 (lo = TwoDigitHex(source->Get(i + 4),
5472 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005473 *step = 6;
5474 return (hi << 8) + lo;
5475 } else if (character == '%' &&
5476 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005477 (lo = TwoDigitHex(source->Get(i + 1),
5478 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 *step = 3;
5480 return lo;
5481 } else {
5482 *step = 1;
5483 return character;
5484 }
5485}
5486
5487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005488RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489 NoHandleAllocation ha;
5490 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005491 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005493 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005494
5495 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005496 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497
5498 int unescaped_length = 0;
5499 for (int i = 0; i < length; unescaped_length++) {
5500 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005501 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005502 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005503 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 i += step;
5505 }
5506
5507 // No length change implies no change. Return original string if no change.
5508 if (unescaped_length == length)
5509 return source;
5510
lrn@chromium.org303ada72010-10-27 09:33:13 +00005511 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005512 { MaybeObject* maybe_o =
5513 ascii ?
5514 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5515 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005516 if (!maybe_o->ToObject(&o)) return maybe_o;
5517 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005518 String* destination = String::cast(o);
5519
5520 int dest_position = 0;
5521 for (int i = 0; i < length; dest_position++) {
5522 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005523 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005524 i += step;
5525 }
5526 return destination;
5527}
5528
5529
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005530static const unsigned int kQuoteTableLength = 128u;
5531
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005532static const int kJsonQuotesCharactersPerEntry = 8;
5533static const char* const JsonQuotes =
5534 "\\u0000 \\u0001 \\u0002 \\u0003 "
5535 "\\u0004 \\u0005 \\u0006 \\u0007 "
5536 "\\b \\t \\n \\u000b "
5537 "\\f \\r \\u000e \\u000f "
5538 "\\u0010 \\u0011 \\u0012 \\u0013 "
5539 "\\u0014 \\u0015 \\u0016 \\u0017 "
5540 "\\u0018 \\u0019 \\u001a \\u001b "
5541 "\\u001c \\u001d \\u001e \\u001f "
5542 " ! \\\" # "
5543 "$ % & ' "
5544 "( ) * + "
5545 ", - . / "
5546 "0 1 2 3 "
5547 "4 5 6 7 "
5548 "8 9 : ; "
5549 "< = > ? "
5550 "@ A B C "
5551 "D E F G "
5552 "H I J K "
5553 "L M N O "
5554 "P Q R S "
5555 "T U V W "
5556 "X Y Z [ "
5557 "\\\\ ] ^ _ "
5558 "` a b c "
5559 "d e f g "
5560 "h i j k "
5561 "l m n o "
5562 "p q r s "
5563 "t u v w "
5564 "x y z { "
5565 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005566
5567
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005568// For a string that is less than 32k characters it should always be
5569// possible to allocate it in new space.
5570static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5571
5572
5573// Doing JSON quoting cannot make the string more than this many times larger.
5574static const int kJsonQuoteWorstCaseBlowup = 6;
5575
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005576static const int kSpaceForQuotesAndComma = 3;
5577static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005578
5579// Covers the entire ASCII range (all other characters are unchanged by JSON
5580// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005581static const byte JsonQuoteLengths[kQuoteTableLength] = {
5582 6, 6, 6, 6, 6, 6, 6, 6,
5583 2, 2, 2, 6, 2, 2, 6, 6,
5584 6, 6, 6, 6, 6, 6, 6, 6,
5585 6, 6, 6, 6, 6, 6, 6, 6,
5586 1, 1, 2, 1, 1, 1, 1, 1,
5587 1, 1, 1, 1, 1, 1, 1, 1,
5588 1, 1, 1, 1, 1, 1, 1, 1,
5589 1, 1, 1, 1, 1, 1, 1, 1,
5590 1, 1, 1, 1, 1, 1, 1, 1,
5591 1, 1, 1, 1, 1, 1, 1, 1,
5592 1, 1, 1, 1, 1, 1, 1, 1,
5593 1, 1, 1, 1, 2, 1, 1, 1,
5594 1, 1, 1, 1, 1, 1, 1, 1,
5595 1, 1, 1, 1, 1, 1, 1, 1,
5596 1, 1, 1, 1, 1, 1, 1, 1,
5597 1, 1, 1, 1, 1, 1, 1, 1,
5598};
5599
5600
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005601template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005602MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005603
5604
5605template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005606MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5607 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005608}
5609
5610
5611template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005612MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5613 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005614}
5615
5616
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005617template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005618static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5619 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005620 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005621 const Char* read_cursor = characters.start();
5622 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005623 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005624 int quoted_length = kSpaceForQuotes;
5625 while (read_cursor < end) {
5626 Char c = *(read_cursor++);
5627 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5628 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005629 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005630 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005631 }
5632 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005633 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5634 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005635 Object* new_object;
5636 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005637 return new_alloc;
5638 }
5639 StringType* new_string = StringType::cast(new_object);
5640
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005641 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005642 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005643 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005644 *(write_cursor++) = '"';
5645
5646 read_cursor = characters.start();
5647 while (read_cursor < end) {
5648 Char c = *(read_cursor++);
5649 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5650 *(write_cursor++) = c;
5651 } else {
5652 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5653 const char* replacement = JsonQuotes +
5654 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5655 for (int i = 0; i < len; i++) {
5656 *write_cursor++ = *replacement++;
5657 }
5658 }
5659 }
5660 *(write_cursor++) = '"';
5661 return new_string;
5662}
5663
5664
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005665template <typename SinkChar, typename SourceChar>
5666static inline SinkChar* WriteQuoteJsonString(
5667 Isolate* isolate,
5668 SinkChar* write_cursor,
5669 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005670 // SinkChar is only char if SourceChar is guaranteed to be char.
5671 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005672 const SourceChar* read_cursor = characters.start();
5673 const SourceChar* end = read_cursor + characters.length();
5674 *(write_cursor++) = '"';
5675 while (read_cursor < end) {
5676 SourceChar c = *(read_cursor++);
5677 if (sizeof(SourceChar) > 1u &&
5678 static_cast<unsigned>(c) >= kQuoteTableLength) {
5679 *(write_cursor++) = static_cast<SinkChar>(c);
5680 } else {
5681 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5682 const char* replacement = JsonQuotes +
5683 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5684 write_cursor[0] = replacement[0];
5685 if (len > 1) {
5686 write_cursor[1] = replacement[1];
5687 if (len > 2) {
5688 ASSERT(len == 6);
5689 write_cursor[2] = replacement[2];
5690 write_cursor[3] = replacement[3];
5691 write_cursor[4] = replacement[4];
5692 write_cursor[5] = replacement[5];
5693 }
5694 }
5695 write_cursor += len;
5696 }
5697 }
5698 *(write_cursor++) = '"';
5699 return write_cursor;
5700}
5701
5702
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005703template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005704static MaybeObject* QuoteJsonString(Isolate* isolate,
5705 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005706 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005707 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005708 int worst_case_length =
5709 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005710 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005711 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005712 }
5713
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005714 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5715 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005716 Object* new_object;
5717 if (!new_alloc->ToObject(&new_object)) {
5718 return new_alloc;
5719 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005720 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005721 // Even if our string is small enough to fit in new space we still have to
5722 // handle it being allocated in old space as may happen in the third
5723 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5724 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005725 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005726 }
5727 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005728 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005729
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005730 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005731 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005732 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005733 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5734 write_cursor,
5735 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005736 int final_length = static_cast<int>(
5737 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005738 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005739 isolate->heap()->new_space()->
5740 template ShrinkStringAtAllocationBoundary<StringType>(
5741 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005742 return new_string;
5743}
5744
5745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005746RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005747 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005748 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005749 if (!str->IsFlat()) {
5750 MaybeObject* try_flatten = str->TryFlatten();
5751 Object* flat;
5752 if (!try_flatten->ToObject(&flat)) {
5753 return try_flatten;
5754 }
5755 str = String::cast(flat);
5756 ASSERT(str->IsFlat());
5757 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005758 String::FlatContent flat = str->GetFlatContent();
5759 ASSERT(flat.IsFlat());
5760 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005761 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005762 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005763 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005764 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005765 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005766 }
5767}
5768
5769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005770RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005771 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005772 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005773 if (!str->IsFlat()) {
5774 MaybeObject* try_flatten = str->TryFlatten();
5775 Object* flat;
5776 if (!try_flatten->ToObject(&flat)) {
5777 return try_flatten;
5778 }
5779 str = String::cast(flat);
5780 ASSERT(str->IsFlat());
5781 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005782 String::FlatContent flat = str->GetFlatContent();
5783 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005784 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005785 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005786 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005787 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005788 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005789 }
5790}
5791
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005792
5793template <typename Char, typename StringType>
5794static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5795 FixedArray* array,
5796 int worst_case_length) {
5797 int length = array->length();
5798
5799 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5800 worst_case_length);
5801 Object* new_object;
5802 if (!new_alloc->ToObject(&new_object)) {
5803 return new_alloc;
5804 }
5805 if (!isolate->heap()->new_space()->Contains(new_object)) {
5806 // Even if our string is small enough to fit in new space we still have to
5807 // handle it being allocated in old space as may happen in the third
5808 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5809 // CEntryStub::GenerateCore.
5810 return isolate->heap()->undefined_value();
5811 }
5812 AssertNoAllocation no_gc;
5813 StringType* new_string = StringType::cast(new_object);
5814 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5815
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005816 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005817 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005818 *(write_cursor++) = '[';
5819 for (int i = 0; i < length; i++) {
5820 if (i != 0) *(write_cursor++) = ',';
5821 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005822 String::FlatContent content = str->GetFlatContent();
5823 ASSERT(content.IsFlat());
5824 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005825 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5826 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005827 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005828 } else {
5829 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5830 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005831 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005832 }
5833 }
5834 *(write_cursor++) = ']';
5835
5836 int final_length = static_cast<int>(
5837 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005838 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005839 isolate->heap()->new_space()->
5840 template ShrinkStringAtAllocationBoundary<StringType>(
5841 new_string, final_length);
5842 return new_string;
5843}
5844
5845
5846RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5847 NoHandleAllocation ha;
5848 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005849 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005850
5851 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5852 FixedArray* elements = FixedArray::cast(array->elements());
5853 int n = elements->length();
5854 bool ascii = true;
5855 int total_length = 0;
5856
5857 for (int i = 0; i < n; i++) {
5858 Object* elt = elements->get(i);
5859 if (!elt->IsString()) return isolate->heap()->undefined_value();
5860 String* element = String::cast(elt);
5861 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5862 total_length += element->length();
5863 if (ascii && element->IsTwoByteRepresentation()) {
5864 ascii = false;
5865 }
5866 }
5867
5868 int worst_case_length =
5869 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5870 + total_length * kJsonQuoteWorstCaseBlowup;
5871
5872 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5873 return isolate->heap()->undefined_value();
5874 }
5875
5876 if (ascii) {
5877 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5878 elements,
5879 worst_case_length);
5880 } else {
5881 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5882 elements,
5883 worst_case_length);
5884 }
5885}
5886
5887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005888RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005889 NoHandleAllocation ha;
5890
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005891 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005892 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005893
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005894 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895
lrn@chromium.org25156de2010-04-06 13:10:27 +00005896 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005897 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005898 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005899}
5900
5901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005902RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005904 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005905
5906 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005907 double value = StringToDouble(isolate->unicode_cache(),
5908 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005909
5910 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005911 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005912}
5913
5914
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005915template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005916MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005917 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005918 String* s,
5919 int length,
5920 int input_string_length,
5921 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005922 // We try this twice, once with the assumption that the result is no longer
5923 // than the input and, if that assumption breaks, again with the exact
5924 // length. This may not be pretty, but it is nicer than what was here before
5925 // and I hereby claim my vaffel-is.
5926 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927 // Allocate the resulting string.
5928 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005929 // NOTE: This assumes that the upper/lower case of an ASCII
5930 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931 // might break in the future if we implement more context and locale
5932 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005933 Object* o;
5934 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005935 ? isolate->heap()->AllocateRawAsciiString(length)
5936 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005937 if (!maybe_o->ToObject(&o)) return maybe_o;
5938 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005939 String* result = String::cast(o);
5940 bool has_changed_character = false;
5941
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005942 // Convert all characters to upper case, assuming that they will fit
5943 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005944 Access<StringInputBuffer> buffer(
5945 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005946 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005947 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005948 // We can assume that the string is not empty
5949 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005950 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005951 bool has_next = buffer->has_more();
5952 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005953 int char_length = mapping->get(current, next, chars);
5954 if (char_length == 0) {
5955 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005956 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005957 i++;
5958 } else if (char_length == 1) {
5959 // Common case: converting the letter resulted in one character.
5960 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005961 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005962 has_changed_character = true;
5963 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005964 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005965 // We've assumed that the result would be as long as the
5966 // input but here is a character that converts to several
5967 // characters. No matter, we calculate the exact length
5968 // of the result and try the whole thing again.
5969 //
5970 // Note that this leaves room for optimization. We could just
5971 // memcpy what we already have to the result string. Also,
5972 // the result string is the last object allocated we could
5973 // "realloc" it and probably, in the vast majority of cases,
5974 // extend the existing string to be able to hold the full
5975 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005976 int next_length = 0;
5977 if (has_next) {
5978 next_length = mapping->get(next, 0, chars);
5979 if (next_length == 0) next_length = 1;
5980 }
5981 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982 while (buffer->has_more()) {
5983 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005984 // NOTE: we use 0 as the next character here because, while
5985 // the next character may affect what a character converts to,
5986 // it does not in any case affect the length of what it convert
5987 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988 int char_length = mapping->get(current, 0, chars);
5989 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005990 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005991 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005992 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005993 return Failure::OutOfMemoryException();
5994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005996 // Try again with the real length.
5997 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 } else {
5999 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006000 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001 i++;
6002 }
6003 has_changed_character = true;
6004 }
6005 current = next;
6006 }
6007 if (has_changed_character) {
6008 return result;
6009 } else {
6010 // If we didn't actually change anything in doing the conversion
6011 // we simple return the result and let the converted string
6012 // become garbage; there is no reason to keep two identical strings
6013 // alive.
6014 return s;
6015 }
6016}
6017
6018
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006019namespace {
6020
lrn@chromium.org303ada72010-10-27 09:33:13 +00006021static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6022
6023
6024// Given a word and two range boundaries returns a word with high bit
6025// set in every byte iff the corresponding input byte was strictly in
6026// the range (m, n). All the other bits in the result are cleared.
6027// This function is only useful when it can be inlined and the
6028// boundaries are statically known.
6029// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006030// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006031static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006032 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006033 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6034 // Use strict inequalities since in edge cases the function could be
6035 // further simplified.
6036 ASSERT(0 < m && m < n && n < 0x7F);
6037 // Has high bit set in every w byte less than n.
6038 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6039 // Has high bit set in every w byte greater than m.
6040 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6041 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6042}
6043
6044
6045enum AsciiCaseConversion {
6046 ASCII_TO_LOWER,
6047 ASCII_TO_UPPER
6048};
6049
6050
6051template <AsciiCaseConversion dir>
6052struct FastAsciiConverter {
6053 static bool Convert(char* dst, char* src, int length) {
6054#ifdef DEBUG
6055 char* saved_dst = dst;
6056 char* saved_src = src;
6057#endif
6058 // We rely on the distance between upper and lower case letters
6059 // being a known power of 2.
6060 ASSERT('a' - 'A' == (1 << 5));
6061 // Boundaries for the range of input characters than require conversion.
6062 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6063 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6064 bool changed = false;
6065 char* const limit = src + length;
6066#ifdef V8_HOST_CAN_READ_UNALIGNED
6067 // Process the prefix of the input that requires no conversion one
6068 // (machine) word at a time.
6069 while (src <= limit - sizeof(uintptr_t)) {
6070 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6071 if (AsciiRangeMask(w, lo, hi) != 0) {
6072 changed = true;
6073 break;
6074 }
6075 *reinterpret_cast<uintptr_t*>(dst) = w;
6076 src += sizeof(uintptr_t);
6077 dst += sizeof(uintptr_t);
6078 }
6079 // Process the remainder of the input performing conversion when
6080 // required one word at a time.
6081 while (src <= limit - sizeof(uintptr_t)) {
6082 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6083 uintptr_t m = AsciiRangeMask(w, lo, hi);
6084 // The mask has high (7th) bit set in every byte that needs
6085 // conversion and we know that the distance between cases is
6086 // 1 << 5.
6087 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6088 src += sizeof(uintptr_t);
6089 dst += sizeof(uintptr_t);
6090 }
6091#endif
6092 // Process the last few bytes of the input (or the whole input if
6093 // unaligned access is not supported).
6094 while (src < limit) {
6095 char c = *src;
6096 if (lo < c && c < hi) {
6097 c ^= (1 << 5);
6098 changed = true;
6099 }
6100 *dst = c;
6101 ++src;
6102 ++dst;
6103 }
6104#ifdef DEBUG
6105 CheckConvert(saved_dst, saved_src, length, changed);
6106#endif
6107 return changed;
6108 }
6109
6110#ifdef DEBUG
6111 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6112 bool expected_changed = false;
6113 for (int i = 0; i < length; i++) {
6114 if (dst[i] == src[i]) continue;
6115 expected_changed = true;
6116 if (dir == ASCII_TO_LOWER) {
6117 ASSERT('A' <= src[i] && src[i] <= 'Z');
6118 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6119 } else {
6120 ASSERT(dir == ASCII_TO_UPPER);
6121 ASSERT('a' <= src[i] && src[i] <= 'z');
6122 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6123 }
6124 }
6125 ASSERT(expected_changed == changed);
6126 }
6127#endif
6128};
6129
6130
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006131struct ToLowerTraits {
6132 typedef unibrow::ToLowercase UnibrowConverter;
6133
lrn@chromium.org303ada72010-10-27 09:33:13 +00006134 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006135};
6136
6137
6138struct ToUpperTraits {
6139 typedef unibrow::ToUppercase UnibrowConverter;
6140
lrn@chromium.org303ada72010-10-27 09:33:13 +00006141 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006142};
6143
6144} // namespace
6145
6146
6147template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006148MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006149 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006150 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006151 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006152 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006153 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006154 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006155
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006156 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006157 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006158 if (length == 0) return s;
6159
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006160 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006161 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006162 // NOTE: This assumes that the upper/lower case of an ASCII
6163 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164 // might break in the future if we implement more context and locale
6165 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006166 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006167 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006168 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006169 if (!maybe_o->ToObject(&o)) return maybe_o;
6170 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006171 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006172 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006173 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006174 return has_changed_character ? result : s;
6175 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006176
lrn@chromium.org303ada72010-10-27 09:33:13 +00006177 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006178 { MaybeObject* maybe_answer =
6179 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006180 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6181 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006182 if (answer->IsSmi()) {
6183 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006184 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006185 ConvertCaseHelper(isolate,
6186 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006187 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6188 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006189 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006190 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006191}
6192
6193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006194RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006195 return ConvertCase<ToLowerTraits>(
6196 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197}
6198
6199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006200RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006201 return ConvertCase<ToUpperTraits>(
6202 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203}
6204
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006205
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006206static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006207 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006208}
6209
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006211RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006212 NoHandleAllocation ha;
6213 ASSERT(args.length() == 3);
6214
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006215 CONVERT_ARG_CHECKED(String, s, 0);
6216 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6217 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006218
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006219 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006220 int length = s->length();
6221
6222 int left = 0;
6223 if (trimLeft) {
6224 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6225 left++;
6226 }
6227 }
6228
6229 int right = length;
6230 if (trimRight) {
6231 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6232 right--;
6233 }
6234 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006235 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006236}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006237
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006239RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006240 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006241 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006242 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6243 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006244 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6245
6246 int subject_length = subject->length();
6247 int pattern_length = pattern->length();
6248 RUNTIME_ASSERT(pattern_length > 0);
6249
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006250 if (limit == 0xffffffffu) {
6251 Handle<Object> cached_answer(StringSplitCache::Lookup(
6252 isolate->heap()->string_split_cache(),
6253 *subject,
6254 *pattern));
6255 if (*cached_answer != Smi::FromInt(0)) {
6256 Handle<JSArray> result =
6257 isolate->factory()->NewJSArrayWithElements(
6258 Handle<FixedArray>::cast(cached_answer));
6259 return *result;
6260 }
6261 }
6262
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006263 // The limit can be very large (0xffffffffu), but since the pattern
6264 // isn't empty, we can never create more parts than ~half the length
6265 // of the subject.
6266
6267 if (!subject->IsFlat()) FlattenString(subject);
6268
6269 static const int kMaxInitialListCapacity = 16;
6270
danno@chromium.org40cb8782011-05-25 07:58:50 +00006271 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006272
6273 // Find (up to limit) indices of separator and end-of-string in subject
6274 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6275 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006276 if (!pattern->IsFlat()) FlattenString(pattern);
6277
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006278 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006279
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006280 if (static_cast<uint32_t>(indices.length()) < limit) {
6281 indices.Add(subject_length);
6282 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006283
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006284 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006285
6286 // Create JSArray of substrings separated by separator.
6287 int part_count = indices.length();
6288
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006289 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006290 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006291 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006292 result->set_length(Smi::FromInt(part_count));
6293
6294 ASSERT(result->HasFastElements());
6295
6296 if (part_count == 1 && indices.at(0) == subject_length) {
6297 FixedArray::cast(result->elements())->set(0, *subject);
6298 return *result;
6299 }
6300
6301 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6302 int part_start = 0;
6303 for (int i = 0; i < part_count; i++) {
6304 HandleScope local_loop_handle;
6305 int part_end = indices.at(i);
6306 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006307 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006308 elements->set(i, *substring);
6309 part_start = part_end + pattern_length;
6310 }
6311
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006312 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006313 if (result->HasFastElements()) {
6314 StringSplitCache::Enter(isolate->heap(),
6315 isolate->heap()->string_split_cache(),
6316 *subject,
6317 *pattern,
6318 *elements);
6319 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006320 }
6321
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006322 return *result;
6323}
6324
6325
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006326// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006327// one-char strings in the cache. Gives up on the first char that is
6328// not in the cache and fills the remainder with smi zeros. Returns
6329// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006330static int CopyCachedAsciiCharsToArray(Heap* heap,
6331 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006332 FixedArray* elements,
6333 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006334 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006335 FixedArray* ascii_cache = heap->single_character_string_cache();
6336 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006337 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006338 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006339 for (i = 0; i < length; ++i) {
6340 Object* value = ascii_cache->get(chars[i]);
6341 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006342 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006343 }
6344 if (i < length) {
6345 ASSERT(Smi::FromInt(0) == 0);
6346 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6347 }
6348#ifdef DEBUG
6349 for (int j = 0; j < length; ++j) {
6350 Object* element = elements->get(j);
6351 ASSERT(element == Smi::FromInt(0) ||
6352 (element->IsString() && String::cast(element)->LooksValid()));
6353 }
6354#endif
6355 return i;
6356}
6357
6358
6359// Converts a String to JSArray.
6360// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006361RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006362 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006363 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006364 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006365 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006366
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006367 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006368 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006369
6370 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006371 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006372 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006373 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006374 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006375 { MaybeObject* maybe_obj =
6376 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006377 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6378 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006379 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006380 String::FlatContent content = s->GetFlatContent();
6381 if (content.IsAscii()) {
6382 Vector<const char> chars = content.ToAsciiVector();
6383 // Note, this will initialize all elements (not only the prefix)
6384 // to prevent GC from seeing partially initialized array.
6385 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6386 chars.start(),
6387 *elements,
6388 length);
6389 } else {
6390 MemsetPointer(elements->data_start(),
6391 isolate->heap()->undefined_value(),
6392 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006393 }
6394 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006395 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006396 }
6397 for (int i = position; i < length; ++i) {
6398 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6399 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006400 }
6401
6402#ifdef DEBUG
6403 for (int i = 0; i < length; ++i) {
6404 ASSERT(String::cast(elements->get(i))->length() == 1);
6405 }
6406#endif
6407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006408 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006409}
6410
6411
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006412RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006413 NoHandleAllocation ha;
6414 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006415 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006416 return value->ToObject();
6417}
6418
6419
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006420bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006421 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006422 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006423 return char_length == 0;
6424}
6425
6426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006427RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006428 NoHandleAllocation ha;
6429 ASSERT(args.length() == 1);
6430
6431 Object* number = args[0];
6432 RUNTIME_ASSERT(number->IsNumber());
6433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006434 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006435}
6436
6437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006438RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006439 NoHandleAllocation ha;
6440 ASSERT(args.length() == 1);
6441
6442 Object* number = args[0];
6443 RUNTIME_ASSERT(number->IsNumber());
6444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006446}
6447
6448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006449RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006450 NoHandleAllocation ha;
6451 ASSERT(args.length() == 1);
6452
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006453 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006454
6455 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6456 if (number > 0 && number <= Smi::kMaxValue) {
6457 return Smi::FromInt(static_cast<int>(number));
6458 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460}
6461
6462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006463RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006464 NoHandleAllocation ha;
6465 ASSERT(args.length() == 1);
6466
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006467 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006468
6469 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6470 if (number > 0 && number <= Smi::kMaxValue) {
6471 return Smi::FromInt(static_cast<int>(number));
6472 }
6473
6474 double double_value = DoubleToInteger(number);
6475 // Map both -0 and +0 to +0.
6476 if (double_value == 0) double_value = 0;
6477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006479}
6480
6481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006482RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006483 NoHandleAllocation ha;
6484 ASSERT(args.length() == 1);
6485
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006486 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006487 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006488}
6489
6490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006491RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006492 NoHandleAllocation ha;
6493 ASSERT(args.length() == 1);
6494
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006495 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006496
6497 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6498 if (number > 0 && number <= Smi::kMaxValue) {
6499 return Smi::FromInt(static_cast<int>(number));
6500 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006502}
6503
6504
ager@chromium.org870a0b62008-11-04 11:43:05 +00006505// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6506// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006507RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006508 NoHandleAllocation ha;
6509 ASSERT(args.length() == 1);
6510
6511 Object* obj = args[0];
6512 if (obj->IsSmi()) {
6513 return obj;
6514 }
6515 if (obj->IsHeapNumber()) {
6516 double value = HeapNumber::cast(obj)->value();
6517 int int_value = FastD2I(value);
6518 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6519 return Smi::FromInt(int_value);
6520 }
6521 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006522 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006523}
6524
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006526RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006527 NoHandleAllocation ha;
6528 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006529 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006530}
6531
6532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006533RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006534 NoHandleAllocation ha;
6535 ASSERT(args.length() == 2);
6536
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006537 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6538 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006539 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006540}
6541
6542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006543RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006544 NoHandleAllocation ha;
6545 ASSERT(args.length() == 2);
6546
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006547 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6548 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006549 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550}
6551
6552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006553RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006554 NoHandleAllocation ha;
6555 ASSERT(args.length() == 2);
6556
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006557 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6558 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006559 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560}
6561
6562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006563RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564 NoHandleAllocation ha;
6565 ASSERT(args.length() == 1);
6566
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006567 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006568 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569}
6570
6571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006572RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006573 NoHandleAllocation ha;
6574 ASSERT(args.length() == 0);
6575
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006576 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006577}
6578
6579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006580RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006581 NoHandleAllocation ha;
6582 ASSERT(args.length() == 2);
6583
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006584 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6585 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006586 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587}
6588
6589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006590RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006591 NoHandleAllocation ha;
6592 ASSERT(args.length() == 2);
6593
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006594 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6595 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596
ager@chromium.org3811b432009-10-28 14:53:37 +00006597 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006598 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006599 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006600}
6601
6602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006603RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006604 NoHandleAllocation ha;
6605 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006606 CONVERT_ARG_CHECKED(String, str1, 0);
6607 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006608 isolate->counters()->string_add_runtime()->Increment();
6609 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610}
6611
6612
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006613template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006614static inline void StringBuilderConcatHelper(String* special,
6615 sinkchar* sink,
6616 FixedArray* fixed_array,
6617 int array_length) {
6618 int position = 0;
6619 for (int i = 0; i < array_length; i++) {
6620 Object* element = fixed_array->get(i);
6621 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006622 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006623 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006624 int pos;
6625 int len;
6626 if (encoded_slice > 0) {
6627 // Position and length encoded in one smi.
6628 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6629 len = StringBuilderSubstringLength::decode(encoded_slice);
6630 } else {
6631 // Position and length encoded in two smis.
6632 Object* obj = fixed_array->get(++i);
6633 ASSERT(obj->IsSmi());
6634 pos = Smi::cast(obj)->value();
6635 len = -encoded_slice;
6636 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006637 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006638 sink + position,
6639 pos,
6640 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006641 position += len;
6642 } else {
6643 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006644 int element_length = string->length();
6645 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006646 position += element_length;
6647 }
6648 }
6649}
6650
6651
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006652RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006653 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006654 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006655 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006656 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006657 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006658 return Failure::OutOfMemoryException();
6659 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006660 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006661 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006662
6663 // This assumption is used by the slice encoding in one or two smis.
6664 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6665
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006666 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006667 if (maybe_result->IsFailure()) return maybe_result;
6668
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006669 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006670 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006671 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006672 }
6673 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006674 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006676 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677
6678 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006679 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680 } else if (array_length == 1) {
6681 Object* first = fixed_array->get(0);
6682 if (first->IsString()) return first;
6683 }
6684
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006685 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 int position = 0;
6687 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006688 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006689 Object* elt = fixed_array->get(i);
6690 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006691 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006692 int smi_value = Smi::cast(elt)->value();
6693 int pos;
6694 int len;
6695 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006696 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006697 pos = StringBuilderSubstringPosition::decode(smi_value);
6698 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006699 } else {
6700 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006701 len = -smi_value;
6702 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006703 i++;
6704 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006705 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006706 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006707 Object* next_smi = fixed_array->get(i);
6708 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006709 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006710 }
6711 pos = Smi::cast(next_smi)->value();
6712 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006713 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006714 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006715 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006716 ASSERT(pos >= 0);
6717 ASSERT(len >= 0);
6718 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006719 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006720 }
6721 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006722 } else if (elt->IsString()) {
6723 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006724 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006725 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006726 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006727 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006728 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006729 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006730 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006731 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006732 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006733 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006734 return Failure::OutOfMemoryException();
6735 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006736 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 }
6738
6739 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006741
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006742 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006743 { MaybeObject* maybe_object =
6744 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006745 if (!maybe_object->ToObject(&object)) return maybe_object;
6746 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006747 SeqAsciiString* answer = SeqAsciiString::cast(object);
6748 StringBuilderConcatHelper(special,
6749 answer->GetChars(),
6750 fixed_array,
6751 array_length);
6752 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006754 { MaybeObject* maybe_object =
6755 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006756 if (!maybe_object->ToObject(&object)) return maybe_object;
6757 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006758 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6759 StringBuilderConcatHelper(special,
6760 answer->GetChars(),
6761 fixed_array,
6762 array_length);
6763 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006765}
6766
6767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006768RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006769 NoHandleAllocation ha;
6770 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006771 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006772 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006773 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006774 return Failure::OutOfMemoryException();
6775 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006776 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006777 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006778
6779 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006780 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006781 }
6782 FixedArray* fixed_array = FixedArray::cast(array->elements());
6783 if (fixed_array->length() < array_length) {
6784 array_length = fixed_array->length();
6785 }
6786
6787 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006788 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006789 } else if (array_length == 1) {
6790 Object* first = fixed_array->get(0);
6791 if (first->IsString()) return first;
6792 }
6793
6794 int separator_length = separator->length();
6795 int max_nof_separators =
6796 (String::kMaxLength + separator_length - 1) / separator_length;
6797 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006798 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006799 return Failure::OutOfMemoryException();
6800 }
6801 int length = (array_length - 1) * separator_length;
6802 for (int i = 0; i < array_length; i++) {
6803 Object* element_obj = fixed_array->get(i);
6804 if (!element_obj->IsString()) {
6805 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006807 }
6808 String* element = String::cast(element_obj);
6809 int increment = element->length();
6810 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006811 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006812 return Failure::OutOfMemoryException();
6813 }
6814 length += increment;
6815 }
6816
6817 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006818 { MaybeObject* maybe_object =
6819 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006820 if (!maybe_object->ToObject(&object)) return maybe_object;
6821 }
6822 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6823
6824 uc16* sink = answer->GetChars();
6825#ifdef DEBUG
6826 uc16* end = sink + length;
6827#endif
6828
6829 String* first = String::cast(fixed_array->get(0));
6830 int first_length = first->length();
6831 String::WriteToFlat(first, sink, 0, first_length);
6832 sink += first_length;
6833
6834 for (int i = 1; i < array_length; i++) {
6835 ASSERT(sink + separator_length <= end);
6836 String::WriteToFlat(separator, sink, 0, separator_length);
6837 sink += separator_length;
6838
6839 String* element = String::cast(fixed_array->get(i));
6840 int element_length = element->length();
6841 ASSERT(sink + element_length <= end);
6842 String::WriteToFlat(element, sink, 0, element_length);
6843 sink += element_length;
6844 }
6845 ASSERT(sink == end);
6846
6847 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6848 return answer;
6849}
6850
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006851template <typename Char>
6852static void JoinSparseArrayWithSeparator(FixedArray* elements,
6853 int elements_length,
6854 uint32_t array_length,
6855 String* separator,
6856 Vector<Char> buffer) {
6857 int previous_separator_position = 0;
6858 int separator_length = separator->length();
6859 int cursor = 0;
6860 for (int i = 0; i < elements_length; i += 2) {
6861 int position = NumberToInt32(elements->get(i));
6862 String* string = String::cast(elements->get(i + 1));
6863 int string_length = string->length();
6864 if (string->length() > 0) {
6865 while (previous_separator_position < position) {
6866 String::WriteToFlat<Char>(separator, &buffer[cursor],
6867 0, separator_length);
6868 cursor += separator_length;
6869 previous_separator_position++;
6870 }
6871 String::WriteToFlat<Char>(string, &buffer[cursor],
6872 0, string_length);
6873 cursor += string->length();
6874 }
6875 }
6876 if (separator_length > 0) {
6877 // Array length must be representable as a signed 32-bit number,
6878 // otherwise the total string length would have been too large.
6879 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6880 int last_array_index = static_cast<int>(array_length - 1);
6881 while (previous_separator_position < last_array_index) {
6882 String::WriteToFlat<Char>(separator, &buffer[cursor],
6883 0, separator_length);
6884 cursor += separator_length;
6885 previous_separator_position++;
6886 }
6887 }
6888 ASSERT(cursor <= buffer.length());
6889}
6890
6891
6892RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6893 NoHandleAllocation ha;
6894 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006895 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006896 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6897 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006898 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006899 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006900 // elements_array is fast-mode JSarray of alternating positions
6901 // (increasing order) and strings.
6902 // array_length is length of original array (used to add separators);
6903 // separator is string to put between elements. Assumed to be non-empty.
6904
6905 // Find total length of join result.
6906 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006907 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006908 int max_string_length;
6909 if (is_ascii) {
6910 max_string_length = SeqAsciiString::kMaxLength;
6911 } else {
6912 max_string_length = SeqTwoByteString::kMaxLength;
6913 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006914 bool overflow = false;
6915 CONVERT_NUMBER_CHECKED(int, elements_length,
6916 Int32, elements_array->length());
6917 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6918 FixedArray* elements = FixedArray::cast(elements_array->elements());
6919 for (int i = 0; i < elements_length; i += 2) {
6920 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006921 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6922 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006923 int length = string->length();
6924 if (is_ascii && !string->IsAsciiRepresentation()) {
6925 is_ascii = false;
6926 max_string_length = SeqTwoByteString::kMaxLength;
6927 }
6928 if (length > max_string_length ||
6929 max_string_length - length < string_length) {
6930 overflow = true;
6931 break;
6932 }
6933 string_length += length;
6934 }
6935 int separator_length = separator->length();
6936 if (!overflow && separator_length > 0) {
6937 if (array_length <= 0x7fffffffu) {
6938 int separator_count = static_cast<int>(array_length) - 1;
6939 int remaining_length = max_string_length - string_length;
6940 if ((remaining_length / separator_length) >= separator_count) {
6941 string_length += separator_length * (array_length - 1);
6942 } else {
6943 // Not room for the separators within the maximal string length.
6944 overflow = true;
6945 }
6946 } else {
6947 // Nonempty separator and at least 2^31-1 separators necessary
6948 // means that the string is too large to create.
6949 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6950 overflow = true;
6951 }
6952 }
6953 if (overflow) {
6954 // Throw OutOfMemory exception for creating too large a string.
6955 V8::FatalProcessOutOfMemory("Array join result too large.");
6956 }
6957
6958 if (is_ascii) {
6959 MaybeObject* result_allocation =
6960 isolate->heap()->AllocateRawAsciiString(string_length);
6961 if (result_allocation->IsFailure()) return result_allocation;
6962 SeqAsciiString* result_string =
6963 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6964 JoinSparseArrayWithSeparator<char>(elements,
6965 elements_length,
6966 array_length,
6967 separator,
6968 Vector<char>(result_string->GetChars(),
6969 string_length));
6970 return result_string;
6971 } else {
6972 MaybeObject* result_allocation =
6973 isolate->heap()->AllocateRawTwoByteString(string_length);
6974 if (result_allocation->IsFailure()) return result_allocation;
6975 SeqTwoByteString* result_string =
6976 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6977 JoinSparseArrayWithSeparator<uc16>(elements,
6978 elements_length,
6979 array_length,
6980 separator,
6981 Vector<uc16>(result_string->GetChars(),
6982 string_length));
6983 return result_string;
6984 }
6985}
6986
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006988RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006989 NoHandleAllocation ha;
6990 ASSERT(args.length() == 2);
6991
6992 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6993 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006994 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006995}
6996
6997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006998RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006999 NoHandleAllocation ha;
7000 ASSERT(args.length() == 2);
7001
7002 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7003 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007004 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007005}
7006
7007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007008RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009 NoHandleAllocation ha;
7010 ASSERT(args.length() == 2);
7011
7012 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7013 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007014 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007015}
7016
7017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007018RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007019 NoHandleAllocation ha;
7020 ASSERT(args.length() == 1);
7021
7022 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007023 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007024}
7025
7026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007027RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028 NoHandleAllocation ha;
7029 ASSERT(args.length() == 2);
7030
7031 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7032 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007033 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007034}
7035
7036
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007037RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007038 NoHandleAllocation ha;
7039 ASSERT(args.length() == 2);
7040
7041 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7042 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007043 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007044}
7045
7046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007047RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048 NoHandleAllocation ha;
7049 ASSERT(args.length() == 2);
7050
7051 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7052 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007053 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007054}
7055
7056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007057RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058 NoHandleAllocation ha;
7059 ASSERT(args.length() == 2);
7060
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007061 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7062 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007063 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7064 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7065 if (x == y) return Smi::FromInt(EQUAL);
7066 Object* result;
7067 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7068 result = Smi::FromInt(EQUAL);
7069 } else {
7070 result = Smi::FromInt(NOT_EQUAL);
7071 }
7072 return result;
7073}
7074
7075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007076RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077 NoHandleAllocation ha;
7078 ASSERT(args.length() == 2);
7079
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007080 CONVERT_ARG_CHECKED(String, x, 0);
7081 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007082
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007083 bool not_equal = !x->Equals(y);
7084 // This is slightly convoluted because the value that signifies
7085 // equality is 0 and inequality is 1 so we have to negate the result
7086 // from String::Equals.
7087 ASSERT(not_equal == 0 || not_equal == 1);
7088 STATIC_CHECK(EQUAL == 0);
7089 STATIC_CHECK(NOT_EQUAL == 1);
7090 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091}
7092
7093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007094RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007095 NoHandleAllocation ha;
7096 ASSERT(args.length() == 3);
7097
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007098 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7099 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100 if (isnan(x) || isnan(y)) return args[2];
7101 if (x == y) return Smi::FromInt(EQUAL);
7102 if (isless(x, y)) return Smi::FromInt(LESS);
7103 return Smi::FromInt(GREATER);
7104}
7105
7106
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007107// Compare two Smis as if they were converted to strings and then
7108// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007109RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007110 NoHandleAllocation ha;
7111 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007112 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7113 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007114
7115 // If the integers are equal so are the string representations.
7116 if (x_value == y_value) return Smi::FromInt(EQUAL);
7117
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007118 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007119 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007120 if (x_value == 0 || y_value == 0)
7121 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007122
ager@chromium.org32912102009-01-16 10:38:43 +00007123 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007124 // smallest because the char code of '-' is less than the char code
7125 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007126
7127 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7128 // architectures using 32-bit Smis.
7129 uint32_t x_scaled = x_value;
7130 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007131 if (x_value < 0 || y_value < 0) {
7132 if (y_value >= 0) return Smi::FromInt(LESS);
7133 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007134 x_scaled = -x_value;
7135 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007136 }
7137
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007138 static const uint32_t kPowersOf10[] = {
7139 1, 10, 100, 1000, 10*1000, 100*1000,
7140 1000*1000, 10*1000*1000, 100*1000*1000,
7141 1000*1000*1000
7142 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007143
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007144 // If the integers have the same number of decimal digits they can be
7145 // compared directly as the numeric order is the same as the
7146 // lexicographic order. If one integer has fewer digits, it is scaled
7147 // by some power of 10 to have the same number of digits as the longer
7148 // integer. If the scaled integers are equal it means the shorter
7149 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007150
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007151 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7152 int x_log2 = IntegerLog2(x_scaled);
7153 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7154 x_log10 -= x_scaled < kPowersOf10[x_log10];
7155
7156 int y_log2 = IntegerLog2(y_scaled);
7157 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7158 y_log10 -= y_scaled < kPowersOf10[y_log10];
7159
7160 int tie = EQUAL;
7161
7162 if (x_log10 < y_log10) {
7163 // X has fewer digits. We would like to simply scale up X but that
7164 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7165 // be scaled up to 9_000_000_000. So we scale up by the next
7166 // smallest power and scale down Y to drop one digit. It is OK to
7167 // drop one digit from the longer integer since the final digit is
7168 // past the length of the shorter integer.
7169 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7170 y_scaled /= 10;
7171 tie = LESS;
7172 } else if (y_log10 < x_log10) {
7173 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7174 x_scaled /= 10;
7175 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007176 }
7177
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007178 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7179 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7180 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007181}
7182
7183
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007184static Object* StringInputBufferCompare(RuntimeState* state,
7185 String* x,
7186 String* y) {
7187 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7188 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007189 bufx.Reset(x);
7190 bufy.Reset(y);
7191 while (bufx.has_more() && bufy.has_more()) {
7192 int d = bufx.GetNext() - bufy.GetNext();
7193 if (d < 0) return Smi::FromInt(LESS);
7194 else if (d > 0) return Smi::FromInt(GREATER);
7195 }
7196
7197 // x is (non-trivial) prefix of y:
7198 if (bufy.has_more()) return Smi::FromInt(LESS);
7199 // y is prefix of x:
7200 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7201}
7202
7203
7204static Object* FlatStringCompare(String* x, String* y) {
7205 ASSERT(x->IsFlat());
7206 ASSERT(y->IsFlat());
7207 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7208 int prefix_length = x->length();
7209 if (y->length() < prefix_length) {
7210 prefix_length = y->length();
7211 equal_prefix_result = Smi::FromInt(GREATER);
7212 } else if (y->length() > prefix_length) {
7213 equal_prefix_result = Smi::FromInt(LESS);
7214 }
7215 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007216 String::FlatContent x_content = x->GetFlatContent();
7217 String::FlatContent y_content = y->GetFlatContent();
7218 if (x_content.IsAscii()) {
7219 Vector<const char> x_chars = x_content.ToAsciiVector();
7220 if (y_content.IsAscii()) {
7221 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007222 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007223 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007224 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007225 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7226 }
7227 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007228 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7229 if (y_content.IsAscii()) {
7230 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007231 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7232 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007233 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007234 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7235 }
7236 }
7237 Object* result;
7238 if (r == 0) {
7239 result = equal_prefix_result;
7240 } else {
7241 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7242 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007243 ASSERT(result ==
7244 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007245 return result;
7246}
7247
7248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007249RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007250 NoHandleAllocation ha;
7251 ASSERT(args.length() == 2);
7252
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007253 CONVERT_ARG_CHECKED(String, x, 0);
7254 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007255
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007256 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007257
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007258 // A few fast case tests before we flatten.
7259 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007260 if (y->length() == 0) {
7261 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007262 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007263 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007264 return Smi::FromInt(LESS);
7265 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007266
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007267 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007268 if (d < 0) return Smi::FromInt(LESS);
7269 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007270
lrn@chromium.org303ada72010-10-27 09:33:13 +00007271 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007272 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007273 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7274 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007275 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007276 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7277 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007278
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007279 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007280 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007281}
7282
7283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007284RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007285 NoHandleAllocation ha;
7286 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007287 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007288
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007289 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007290 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007291}
7292
7293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007294RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007295 NoHandleAllocation ha;
7296 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007297 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007298
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007299 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007300 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301}
7302
7303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007304RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007305 NoHandleAllocation ha;
7306 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007307 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007308
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007309 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007310 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311}
7312
7313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007314static const double kPiDividedBy4 = 0.78539816339744830962;
7315
7316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007317RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007318 NoHandleAllocation ha;
7319 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007320 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007322 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7323 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324 double result;
7325 if (isinf(x) && isinf(y)) {
7326 // Make sure that the result in case of two infinite arguments
7327 // is a multiple of Pi / 4. The sign of the result is determined
7328 // by the first argument (x) and the sign of the second argument
7329 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007330 int multiplier = (x < 0) ? -1 : 1;
7331 if (y < 0) multiplier *= 3;
7332 result = multiplier * kPiDividedBy4;
7333 } else {
7334 result = atan2(x, y);
7335 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007336 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007337}
7338
7339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007340RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341 NoHandleAllocation ha;
7342 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007343 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007345 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007347}
7348
7349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007350RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351 NoHandleAllocation ha;
7352 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007353 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007355 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007356 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007357}
7358
7359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007360RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007361 NoHandleAllocation ha;
7362 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007363 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007365 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367}
7368
7369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007370RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371 NoHandleAllocation ha;
7372 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007375 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377}
7378
7379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007380RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 NoHandleAllocation ha;
7382 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007383 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007385 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387}
7388
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007389// Slow version of Math.pow. We check for fast paths for special cases.
7390// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007391RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392 NoHandleAllocation ha;
7393 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007396 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007397
7398 // If the second argument is a smi, it is much faster to call the
7399 // custom powi() function than the generic pow().
7400 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007401 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007402 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007403 }
7404
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007405 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007406 int y_int = static_cast<int>(y);
7407 double result;
7408 if (y == y_int) {
7409 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7410 } else if (y == 0.5) {
7411 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7412 } else if (y == -0.5) {
7413 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7414 } else {
7415 result = power_double_double(x, y);
7416 }
7417 if (isnan(result)) return isolate->heap()->nan_value();
7418 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007419}
7420
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007421// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007422// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007423RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007424 NoHandleAllocation ha;
7425 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007426 isolate->counters()->math_pow()->Increment();
7427
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007428 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7429 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007430 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007431 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007432 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007433 double result = power_double_double(x, y);
7434 if (isnan(result)) return isolate->heap()->nan_value();
7435 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007436 }
7437}
7438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007440RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007441 NoHandleAllocation ha;
7442 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007443 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007444
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007445 if (!args[0]->IsHeapNumber()) {
7446 // Must be smi. Return the argument unchanged for all the other types
7447 // to make fuzz-natives test happy.
7448 return args[0];
7449 }
7450
7451 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7452
7453 double value = number->value();
7454 int exponent = number->get_exponent();
7455 int sign = number->get_sign();
7456
danno@chromium.org160a7b02011-04-18 15:51:38 +00007457 if (exponent < -1) {
7458 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7459 if (sign) return isolate->heap()->minus_zero_value();
7460 return Smi::FromInt(0);
7461 }
7462
7463 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7464 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007465 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007466 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007467 return Smi::FromInt(static_cast<int>(value + 0.5));
7468 }
7469
7470 // If the magnitude is big enough, there's no place for fraction part. If we
7471 // try to add 0.5 to this number, 1.0 will be added instead.
7472 if (exponent >= 52) {
7473 return number;
7474 }
7475
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007476 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007477
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007478 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007479 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007480}
7481
7482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007483RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007484 NoHandleAllocation ha;
7485 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007486 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007487
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007488 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007489 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007490}
7491
7492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007493RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007494 NoHandleAllocation ha;
7495 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007496 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007497
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007498 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007499 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007500}
7501
7502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007503RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007504 NoHandleAllocation ha;
7505 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007506 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007507
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007508 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007509 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007510}
7511
7512
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007513static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007514 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7515 181, 212, 243, 273, 304, 334};
7516 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7517 182, 213, 244, 274, 305, 335};
7518
7519 year += month / 12;
7520 month %= 12;
7521 if (month < 0) {
7522 year--;
7523 month += 12;
7524 }
7525
7526 ASSERT(month >= 0);
7527 ASSERT(month < 12);
7528
7529 // year_delta is an arbitrary number such that:
7530 // a) year_delta = -1 (mod 400)
7531 // b) year + year_delta > 0 for years in the range defined by
7532 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7533 // Jan 1 1970. This is required so that we don't run into integer
7534 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007535 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007536 // operations.
7537 static const int year_delta = 399999;
7538 static const int base_day = 365 * (1970 + year_delta) +
7539 (1970 + year_delta) / 4 -
7540 (1970 + year_delta) / 100 +
7541 (1970 + year_delta) / 400;
7542
7543 int year1 = year + year_delta;
7544 int day_from_year = 365 * year1 +
7545 year1 / 4 -
7546 year1 / 100 +
7547 year1 / 400 -
7548 base_day;
7549
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007550 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7551 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007552 }
7553
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007554 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007555}
7556
7557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007558RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007559 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007560 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007561
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007562 CONVERT_SMI_ARG_CHECKED(year, 0);
7563 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007564
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007565 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007566}
7567
7568
7569static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7570static const int kDaysIn4Years = 4 * 365 + 1;
7571static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7572static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7573static const int kDays1970to2000 = 30 * 365 + 7;
7574static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7575 kDays1970to2000;
7576static const int kYearsOffset = 400000;
7577
7578static const char kDayInYear[] = {
7579 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7580 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7581 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7582 22, 23, 24, 25, 26, 27, 28,
7583 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7584 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7585 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7586 22, 23, 24, 25, 26, 27, 28, 29, 30,
7587 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7588 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7589 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7590 22, 23, 24, 25, 26, 27, 28, 29, 30,
7591 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7592 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7593 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7594 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7595 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7596 22, 23, 24, 25, 26, 27, 28, 29, 30,
7597 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7598 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7599 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7600 22, 23, 24, 25, 26, 27, 28, 29, 30,
7601 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7602 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7603
7604 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7605 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7606 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7607 22, 23, 24, 25, 26, 27, 28,
7608 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7609 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7610 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7611 22, 23, 24, 25, 26, 27, 28, 29, 30,
7612 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7613 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7614 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7615 22, 23, 24, 25, 26, 27, 28, 29, 30,
7616 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7617 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7618 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7619 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7620 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7621 22, 23, 24, 25, 26, 27, 28, 29, 30,
7622 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7623 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7624 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7625 22, 23, 24, 25, 26, 27, 28, 29, 30,
7626 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7627 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7628
7629 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7630 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7631 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7632 22, 23, 24, 25, 26, 27, 28, 29,
7633 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7634 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7635 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7636 22, 23, 24, 25, 26, 27, 28, 29, 30,
7637 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7638 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7639 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7640 22, 23, 24, 25, 26, 27, 28, 29, 30,
7641 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7642 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7643 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7644 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7645 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7646 22, 23, 24, 25, 26, 27, 28, 29, 30,
7647 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7648 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7649 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7650 22, 23, 24, 25, 26, 27, 28, 29, 30,
7651 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7652 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7653
7654 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7655 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7656 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7657 22, 23, 24, 25, 26, 27, 28,
7658 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7659 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7660 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7661 22, 23, 24, 25, 26, 27, 28, 29, 30,
7662 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7663 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7664 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7665 22, 23, 24, 25, 26, 27, 28, 29, 30,
7666 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7667 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7668 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7669 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7670 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7671 22, 23, 24, 25, 26, 27, 28, 29, 30,
7672 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7673 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7674 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7675 22, 23, 24, 25, 26, 27, 28, 29, 30,
7676 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7677 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7678
7679static const char kMonthInYear[] = {
7680 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7681 0, 0, 0, 0, 0, 0,
7682 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7683 1, 1, 1,
7684 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7685 2, 2, 2, 2, 2, 2,
7686 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7687 3, 3, 3, 3, 3,
7688 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7689 4, 4, 4, 4, 4, 4,
7690 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7691 5, 5, 5, 5, 5,
7692 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7693 6, 6, 6, 6, 6, 6,
7694 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7695 7, 7, 7, 7, 7, 7,
7696 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7697 8, 8, 8, 8, 8,
7698 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7699 9, 9, 9, 9, 9, 9,
7700 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7701 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7702 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7703 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7704
7705 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7706 0, 0, 0, 0, 0, 0,
7707 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7708 1, 1, 1,
7709 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7710 2, 2, 2, 2, 2, 2,
7711 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7712 3, 3, 3, 3, 3,
7713 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7714 4, 4, 4, 4, 4, 4,
7715 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7716 5, 5, 5, 5, 5,
7717 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7718 6, 6, 6, 6, 6, 6,
7719 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7720 7, 7, 7, 7, 7, 7,
7721 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7722 8, 8, 8, 8, 8,
7723 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7724 9, 9, 9, 9, 9, 9,
7725 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7726 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7727 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7728 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7729
7730 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7731 0, 0, 0, 0, 0, 0,
7732 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7733 1, 1, 1, 1,
7734 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7735 2, 2, 2, 2, 2, 2,
7736 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7737 3, 3, 3, 3, 3,
7738 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7739 4, 4, 4, 4, 4, 4,
7740 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7741 5, 5, 5, 5, 5,
7742 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7743 6, 6, 6, 6, 6, 6,
7744 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7745 7, 7, 7, 7, 7, 7,
7746 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7747 8, 8, 8, 8, 8,
7748 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7749 9, 9, 9, 9, 9, 9,
7750 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7751 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7752 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7753 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7754
7755 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7756 0, 0, 0, 0, 0, 0,
7757 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7758 1, 1, 1,
7759 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7760 2, 2, 2, 2, 2, 2,
7761 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7762 3, 3, 3, 3, 3,
7763 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7764 4, 4, 4, 4, 4, 4,
7765 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7766 5, 5, 5, 5, 5,
7767 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7768 6, 6, 6, 6, 6, 6,
7769 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7770 7, 7, 7, 7, 7, 7,
7771 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7772 8, 8, 8, 8, 8,
7773 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7774 9, 9, 9, 9, 9, 9,
7775 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7776 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7777 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7778 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7779
7780
7781// This function works for dates from 1970 to 2099.
7782static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007783 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007784#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007785 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007786#endif
7787
7788 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7789 date %= kDaysIn4Years;
7790
7791 month = kMonthInYear[date];
7792 day = kDayInYear[date];
7793
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007794 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007795}
7796
7797
7798static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007799 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007800#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007801 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007802#endif
7803
7804 date += kDaysOffset;
7805 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7806 date %= kDaysIn400Years;
7807
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007808 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007809
7810 date--;
7811 int yd1 = date / kDaysIn100Years;
7812 date %= kDaysIn100Years;
7813 year += 100 * yd1;
7814
7815 date++;
7816 int yd2 = date / kDaysIn4Years;
7817 date %= kDaysIn4Years;
7818 year += 4 * yd2;
7819
7820 date--;
7821 int yd3 = date / 365;
7822 date %= 365;
7823 year += yd3;
7824
7825 bool is_leap = (!yd1 || yd2) && !yd3;
7826
7827 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007828 ASSERT(is_leap || (date >= 0));
7829 ASSERT((date < 365) || (is_leap && (date < 366)));
7830 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007831 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7832 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007833
7834 if (is_leap) {
7835 day = kDayInYear[2*365 + 1 + date];
7836 month = kMonthInYear[2*365 + 1 + date];
7837 } else {
7838 day = kDayInYear[date];
7839 month = kMonthInYear[date];
7840 }
7841
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007842 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007843}
7844
7845
7846static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007847 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007848 if (date >= 0 && date < 32 * kDaysIn4Years) {
7849 DateYMDFromTimeAfter1970(date, year, month, day);
7850 } else {
7851 DateYMDFromTimeSlow(date, year, month, day);
7852 }
7853}
7854
7855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007856RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007857 NoHandleAllocation ha;
7858 ASSERT(args.length() == 2);
7859
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007860 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007861 CONVERT_ARG_CHECKED(JSArray, res_array, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007862
7863 int year, month, day;
7864 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7865
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007866 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7867 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007868 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007869
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007870 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7871 if (maybe->IsFailure()) return maybe;
7872 FixedArray* elms = FixedArray::cast(res_array->elements());
7873 elms->set(0, Smi::FromInt(year));
7874 elms->set(1, Smi::FromInt(month));
7875 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007876
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007877 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007878}
7879
7880
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007881RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007882 HandleScope scope(isolate);
7883 ASSERT(args.length() == 3);
7884
7885 Handle<JSFunction> callee = args.at<JSFunction>(0);
7886 Object** parameters = reinterpret_cast<Object**>(args[1]);
7887 const int argument_count = Smi::cast(args[2])->value();
7888
7889 Handle<JSObject> result =
7890 isolate->factory()->NewArgumentsObject(callee, argument_count);
7891 // Allocate the elements if needed.
7892 int parameter_count = callee->shared()->formal_parameter_count();
7893 if (argument_count > 0) {
7894 if (parameter_count > 0) {
7895 int mapped_count = Min(argument_count, parameter_count);
7896 Handle<FixedArray> parameter_map =
7897 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7898 parameter_map->set_map(
7899 isolate->heap()->non_strict_arguments_elements_map());
7900
7901 Handle<Map> old_map(result->map());
7902 Handle<Map> new_map =
7903 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007904 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007905
7906 result->set_map(*new_map);
7907 result->set_elements(*parameter_map);
7908
7909 // Store the context and the arguments array at the beginning of the
7910 // parameter map.
7911 Handle<Context> context(isolate->context());
7912 Handle<FixedArray> arguments =
7913 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7914 parameter_map->set(0, *context);
7915 parameter_map->set(1, *arguments);
7916
7917 // Loop over the actual parameters backwards.
7918 int index = argument_count - 1;
7919 while (index >= mapped_count) {
7920 // These go directly in the arguments array and have no
7921 // corresponding slot in the parameter map.
7922 arguments->set(index, *(parameters - index - 1));
7923 --index;
7924 }
7925
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007926 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007927 while (index >= 0) {
7928 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007929 Handle<String> name(scope_info->ParameterName(index));
7930 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007931 bool duplicate = false;
7932 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007933 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007934 duplicate = true;
7935 break;
7936 }
7937 }
7938
7939 if (duplicate) {
7940 // This goes directly in the arguments array with a hole in the
7941 // parameter map.
7942 arguments->set(index, *(parameters - index - 1));
7943 parameter_map->set_the_hole(index + 2);
7944 } else {
7945 // The context index goes in the parameter map with a hole in the
7946 // arguments array.
7947 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007948 for (int j = 0; j < context_local_count; ++j) {
7949 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007950 context_index = j;
7951 break;
7952 }
7953 }
7954 ASSERT(context_index >= 0);
7955 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007956 parameter_map->set(index + 2, Smi::FromInt(
7957 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007958 }
7959
7960 --index;
7961 }
7962 } else {
7963 // If there is no aliasing, the arguments object elements are not
7964 // special in any way.
7965 Handle<FixedArray> elements =
7966 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7967 result->set_elements(*elements);
7968 for (int i = 0; i < argument_count; ++i) {
7969 elements->set(i, *(parameters - i - 1));
7970 }
7971 }
7972 }
7973 return *result;
7974}
7975
7976
7977RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007978 NoHandleAllocation ha;
7979 ASSERT(args.length() == 3);
7980
7981 JSFunction* callee = JSFunction::cast(args[0]);
7982 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007983 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007984
lrn@chromium.org303ada72010-10-27 09:33:13 +00007985 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007986 { MaybeObject* maybe_result =
7987 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007988 if (!maybe_result->ToObject(&result)) return maybe_result;
7989 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007990 // Allocate the elements if needed.
7991 if (length > 0) {
7992 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007993 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007994 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007995 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7996 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007997
7998 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007999 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008000 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008001 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008002
8003 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008004 for (int i = 0; i < length; i++) {
8005 array->set(i, *--parameters, mode);
8006 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008007 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008008 }
8009 return result;
8010}
8011
8012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008013RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008014 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008015 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008016 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8017 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
8018 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008019
whesse@chromium.org7b260152011-06-20 15:33:18 +00008020 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008021 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008022 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008023 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008024 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8025 context,
8026 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008027 return *result;
8028}
8029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008030
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008031// Find the arguments of the JavaScript function invocation that called
8032// into C++ code. Collect these in a newly allocated array of handles (possibly
8033// prefixed by a number of empty handles).
8034static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8035 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008036 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008037 // Find frame containing arguments passed to the caller.
8038 JavaScriptFrameIterator it;
8039 JavaScriptFrame* frame = it.frame();
8040 List<JSFunction*> functions(2);
8041 frame->GetFunctions(&functions);
8042 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008043 int inlined_jsframe_index = functions.length() - 1;
8044 JSFunction* inlined_function = functions[inlined_jsframe_index];
8045 Vector<SlotRef> args_slots =
8046 SlotRef::ComputeSlotMappingForArguments(
8047 frame,
8048 inlined_jsframe_index,
8049 inlined_function->shared()->formal_parameter_count());
8050
8051 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008052
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008053 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008054 SmartArrayPointer<Handle<Object> > param_data(
8055 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008056 for (int i = 0; i < args_count; i++) {
8057 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008058 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008059 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008060
8061 args_slots.Dispose();
8062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008063 return param_data;
8064 } else {
8065 it.AdvanceToArgumentsFrame();
8066 frame = it.frame();
8067 int args_count = frame->ComputeParametersCount();
8068
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008069 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008070 SmartArrayPointer<Handle<Object> > param_data(
8071 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008072 for (int i = 0; i < args_count; i++) {
8073 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008074 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008075 }
8076 return param_data;
8077 }
8078}
8079
8080
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008081RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8082 HandleScope scope(isolate);
8083 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008084 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008085 RUNTIME_ASSERT(args[3]->IsNumber());
8086 Handle<Object> bindee = args.at<Object>(1);
8087
8088 // TODO(lrn): Create bound function in C++ code from premade shared info.
8089 bound_function->shared()->set_bound(true);
8090 // Get all arguments of calling function (Function.prototype.bind).
8091 int argc = 0;
8092 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8093 // Don't count the this-arg.
8094 if (argc > 0) {
8095 ASSERT(*arguments[0] == args[2]);
8096 argc--;
8097 } else {
8098 ASSERT(args[2]->IsUndefined());
8099 }
8100 // Initialize array of bindings (function, this, and any existing arguments
8101 // if the function was already bound).
8102 Handle<FixedArray> new_bindings;
8103 int i;
8104 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8105 Handle<FixedArray> old_bindings(
8106 JSFunction::cast(*bindee)->function_bindings());
8107 new_bindings =
8108 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8109 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8110 i = 0;
8111 for (int n = old_bindings->length(); i < n; i++) {
8112 new_bindings->set(i, old_bindings->get(i));
8113 }
8114 } else {
8115 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8116 new_bindings = isolate->factory()->NewFixedArray(array_size);
8117 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8118 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8119 i = 2;
8120 }
8121 // Copy arguments, skipping the first which is "this_arg".
8122 for (int j = 0; j < argc; j++, i++) {
8123 new_bindings->set(i, *arguments[j + 1]);
8124 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008125 new_bindings->set_map_no_write_barrier(
8126 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008127 bound_function->set_function_bindings(*new_bindings);
8128
8129 // Update length.
8130 Handle<String> length_symbol = isolate->factory()->length_symbol();
8131 Handle<Object> new_length(args.at<Object>(3));
8132 PropertyAttributes attr =
8133 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8134 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8135 return *bound_function;
8136}
8137
8138
8139RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8140 HandleScope handles(isolate);
8141 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008142 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008143 if (callable->IsJSFunction()) {
8144 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8145 if (function->shared()->bound()) {
8146 Handle<FixedArray> bindings(function->function_bindings());
8147 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8148 return *isolate->factory()->NewJSArrayWithElements(bindings);
8149 }
8150 }
8151 return isolate->heap()->undefined_value();
8152}
8153
8154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008155RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008156 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008157 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008158 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008159 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008160 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008161
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008162 // The argument is a bound function. Extract its bound arguments
8163 // and callable.
8164 Handle<FixedArray> bound_args =
8165 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8166 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8167 Handle<Object> bound_function(
8168 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8169 ASSERT(!bound_function->IsJSFunction() ||
8170 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008172 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008173 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008174 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008175 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008176 param_data[i] = Handle<Object>(bound_args->get(
8177 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008178 }
8179
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008180 if (!bound_function->IsJSFunction()) {
8181 bool exception_thrown;
8182 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8183 &exception_thrown);
8184 if (exception_thrown) return Failure::Exception();
8185 }
8186 ASSERT(bound_function->IsJSFunction());
8187
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008188 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008189 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008190 Execution::New(Handle<JSFunction>::cast(bound_function),
8191 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008192 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008193 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008194 }
8195 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008196 return *result;
8197}
8198
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200static void TrySettingInlineConstructStub(Isolate* isolate,
8201 Handle<JSFunction> function) {
8202 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008203 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008204 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008205 }
8206 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008207 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008208 Handle<Code> code = compiler.CompileConstructStub(function);
8209 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008210 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008211}
8212
8213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008214RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008215 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008216 ASSERT(args.length() == 1);
8217
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008218 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008219
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008220 // If the constructor isn't a proper function we throw a type error.
8221 if (!constructor->IsJSFunction()) {
8222 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8223 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008224 isolate->factory()->NewTypeError("not_constructor", arguments);
8225 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008226 }
8227
8228 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008229
8230 // If function should not have prototype, construction is not allowed. In this
8231 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008232 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008233 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8234 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008235 isolate->factory()->NewTypeError("not_constructor", arguments);
8236 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008237 }
8238
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008239#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008240 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008241 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008242 if (debug->StepInActive()) {
8243 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008244 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008245#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008247 if (function->has_initial_map()) {
8248 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008249 // The 'Function' function ignores the receiver object when
8250 // called using 'new' and creates a new JSFunction object that
8251 // is returned. The receiver object is only used for error
8252 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008253 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008254 // allocate JSFunctions since it does not properly initialize
8255 // the shared part of the function. Since the receiver is
8256 // ignored anyway, we use the global object as the receiver
8257 // instead of a new JSFunction object. This way, errors are
8258 // reported the same way whether or not 'Function' is called
8259 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008260 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008261 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008262 }
8263
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008264 // The function should be compiled for the optimization hints to be
8265 // available. We cannot use EnsureCompiled because that forces a
8266 // compilation through the shared function info which makes it
8267 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008268 if (!function->is_compiled()) {
8269 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8270 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008271
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008272 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008273 if (!function->has_initial_map() &&
8274 shared->IsInobjectSlackTrackingInProgress()) {
8275 // The tracking is already in progress for another function. We can only
8276 // track one initial_map at a time, so we force the completion before the
8277 // function is called as a constructor for the first time.
8278 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008279 }
8280
8281 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8283 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008284 // Delay setting the stub if inobject slack tracking is in progress.
8285 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008286 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008287 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008288
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 isolate->counters()->constructed_objects()->Increment();
8290 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008291
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008292 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008293}
8294
8295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008296RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008297 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008298 ASSERT(args.length() == 1);
8299
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008300 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008301 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008302 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008303
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008304 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008305}
8306
8307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008308RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008309 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008310 ASSERT(args.length() == 1);
8311
8312 Handle<JSFunction> function = args.at<JSFunction>(0);
8313#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008314 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008315 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008316 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008317 PrintF("]\n");
8318 }
8319#endif
8320
lrn@chromium.org34e60782011-09-15 07:25:40 +00008321 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008323 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008324 return Failure::Exception();
8325 }
8326
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008327 // All done. Return the compiled code.
8328 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008329 return function->code();
8330}
8331
8332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008333RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008334 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008335 ASSERT(args.length() == 1);
8336 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008337
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00008338 function->shared()->set_profiler_ticks(0);
8339
lrn@chromium.org34e60782011-09-15 07:25:40 +00008340 // If the function is not compiled ignore the lazy
8341 // recompilation. This can happen if the debugger is activated and
8342 // the function is returned to the not compiled state.
8343 if (!function->shared()->is_compiled()) {
8344 function->ReplaceCode(function->shared()->code());
8345 return function->code();
8346 }
8347
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008348 // If the function is not optimizable or debugger is active continue using the
8349 // code from the full compiler.
8350 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008351 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008352 if (FLAG_trace_opt) {
8353 PrintF("[failed to optimize ");
8354 function->PrintName();
8355 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8356 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008357 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008358 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008359 function->ReplaceCode(function->shared()->code());
8360 return function->code();
8361 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008362 if (JSFunction::CompileOptimized(function,
8363 AstNode::kNoNumber,
8364 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008365 return function->code();
8366 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008367 if (FLAG_trace_opt) {
8368 PrintF("[failed to optimize ");
8369 function->PrintName();
8370 PrintF(": optimized compilation failed]\n");
8371 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008372 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008373 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008374}
8375
8376
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008377class ActivationsFinder : public ThreadVisitor {
8378 public:
8379 explicit ActivationsFinder(JSFunction* function)
8380 : function_(function), has_activations_(false) {}
8381
8382 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8383 if (has_activations_) return;
8384
8385 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8386 JavaScriptFrame* frame = it.frame();
8387 if (frame->is_optimized() && frame->function() == function_) {
8388 has_activations_ = true;
8389 return;
8390 }
8391 }
8392 }
8393
8394 bool has_activations() { return has_activations_; }
8395
8396 private:
8397 JSFunction* function_;
8398 bool has_activations_;
8399};
8400
8401
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008402RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008403 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008404 ASSERT(args.length() == 1);
8405 RUNTIME_ASSERT(args[0]->IsSmi());
8406 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008407 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008408 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8409 ASSERT(isolate->heap()->IsAllocationAllowed());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008410 int jsframes = deoptimizer->jsframe_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008411
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008412 deoptimizer->MaterializeHeapNumbers();
8413 delete deoptimizer;
8414
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008415 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008416 JavaScriptFrame* frame = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008417 for (int i = 0; i < jsframes - 1; i++) it.Advance();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008418 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008419
8420 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008421 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008422 Handle<Object> arguments;
8423 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008424 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008425 if (arguments.is_null()) {
8426 // FunctionGetArguments can't throw an exception, so cast away the
8427 // doubt with an assert.
8428 arguments = Handle<Object>(
8429 Accessors::FunctionGetArguments(*function,
8430 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008431 ASSERT(*arguments != isolate->heap()->null_value());
8432 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008433 }
8434 frame->SetExpression(i, *arguments);
8435 }
8436 }
8437
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008438 if (type == Deoptimizer::EAGER) {
8439 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008440 }
8441
8442 // Avoid doing too much work when running with --always-opt and keep
8443 // the optimized code around.
8444 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008445 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008446 }
8447
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008448 // Find other optimized activations of the function.
8449 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008450 while (!it.done()) {
8451 JavaScriptFrame* frame = it.frame();
8452 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008453 has_other_activations = true;
8454 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008455 }
8456 it.Advance();
8457 }
8458
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008459 if (!has_other_activations) {
8460 ActivationsFinder activations_finder(*function);
8461 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8462 has_other_activations = activations_finder.has_activations();
8463 }
8464
8465 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008466 if (FLAG_trace_deopt) {
8467 PrintF("[removing optimized code for: ");
8468 function->PrintName();
8469 PrintF("]\n");
8470 }
8471 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008472 } else {
8473 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008474 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008475 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008476}
8477
8478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008479RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008480 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008481 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008482 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008483}
8484
8485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008486RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008487 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008488 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008489 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008491
8492 Deoptimizer::DeoptimizeFunction(*function);
8493
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008494 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008495}
8496
8497
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008498RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8499#if defined(USE_SIMULATOR)
8500 return isolate->heap()->true_value();
8501#else
8502 return isolate->heap()->false_value();
8503#endif
8504}
8505
8506
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008507RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8508 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008509 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008510 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008511
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008512 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8513 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008514
8515 Code* unoptimized = function->shared()->code();
8516 if (args.length() == 2 &&
8517 unoptimized->kind() == Code::FUNCTION) {
8518 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8519 CHECK(type->IsEqualTo(CStrVector("osr")));
8520 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8521 unoptimized->set_allow_osr_at_loop_nesting_level(
8522 Code::kMaxLoopNestingMarker);
8523 }
8524
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008525 return isolate->heap()->undefined_value();
8526}
8527
8528
lrn@chromium.org1c092762011-05-09 09:42:16 +00008529RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8530 HandleScope scope(isolate);
8531 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008532 // The least significant bit (after untagging) indicates whether the
8533 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008534 if (!V8::UseCrankshaft()) {
8535 return Smi::FromInt(4); // 4 == "never".
8536 }
8537 if (FLAG_always_opt) {
8538 return Smi::FromInt(3); // 3 == "always".
8539 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008540 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008541 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8542 : Smi::FromInt(2); // 2 == "no".
8543}
8544
8545
8546RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8547 HandleScope scope(isolate);
8548 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008549 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008550 return Smi::FromInt(function->shared()->opt_count());
8551}
8552
8553
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008554RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008555 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008556 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008557 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008558
8559 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008560 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008561
8562 // We have hit a back edge in an unoptimized frame for a function that was
8563 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008564 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008565 // Keep track of whether we've succeeded in optimizing.
8566 bool succeeded = unoptimized->optimizable();
8567 if (succeeded) {
8568 // If we are trying to do OSR when there are already optimized
8569 // activations of the function, it means (a) the function is directly or
8570 // indirectly recursive and (b) an optimized invocation has been
8571 // deoptimized so that we are currently in an unoptimized activation.
8572 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008573 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008574 while (succeeded && !it.done()) {
8575 JavaScriptFrame* frame = it.frame();
8576 succeeded = !frame->is_optimized() || frame->function() != *function;
8577 it.Advance();
8578 }
8579 }
8580
8581 int ast_id = AstNode::kNoNumber;
8582 if (succeeded) {
8583 // The top JS function is this one, the PC is somewhere in the
8584 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008585 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008586 JavaScriptFrame* frame = it.frame();
8587 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008588 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008589 ASSERT(unoptimized->contains(frame->pc()));
8590
8591 // Use linear search of the unoptimized code's stack check table to find
8592 // the AST id matching the PC.
8593 Address start = unoptimized->instruction_start();
8594 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008595 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008596 uint32_t table_length = Memory::uint32_at(table_cursor);
8597 table_cursor += kIntSize;
8598 for (unsigned i = 0; i < table_length; ++i) {
8599 // Table entries are (AST id, pc offset) pairs.
8600 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8601 if (pc_offset == target_pc_offset) {
8602 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8603 break;
8604 }
8605 table_cursor += 2 * kIntSize;
8606 }
8607 ASSERT(ast_id != AstNode::kNoNumber);
8608 if (FLAG_trace_osr) {
8609 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8610 function->PrintName();
8611 PrintF("]\n");
8612 }
8613
8614 // Try to compile the optimized code. A true return value from
8615 // CompileOptimized means that compilation succeeded, not necessarily
8616 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008617 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008618 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008619 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8620 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008621 if (data->OsrPcOffset()->value() >= 0) {
8622 if (FLAG_trace_osr) {
8623 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008624 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008625 }
8626 ASSERT(data->OsrAstId()->value() == ast_id);
8627 } else {
8628 // We may never generate the desired OSR entry if we emit an
8629 // early deoptimize.
8630 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008631 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008632 } else {
8633 succeeded = false;
8634 }
8635 }
8636
8637 // Revert to the original stack checks in the original unoptimized code.
8638 if (FLAG_trace_osr) {
8639 PrintF("[restoring original stack checks in ");
8640 function->PrintName();
8641 PrintF("]\n");
8642 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008643 Handle<Code> check_code;
8644#ifdef V8_TARGET_ARCH_IA32
8645 if (FLAG_count_based_interrupts) {
8646 InterruptStub interrupt_stub;
8647 check_code = interrupt_stub.GetCode();
8648 } else // NOLINT
8649#endif
8650 { // NOLINT
8651 StackCheckStub check_stub;
8652 check_code = check_stub.GetCode();
8653 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008654 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008655 Deoptimizer::RevertStackCheckCode(*unoptimized,
8656 *check_code,
8657 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008658
8659 // Allow OSR only at nesting level zero again.
8660 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8661
8662 // If the optimization attempt succeeded, return the AST id tagged as a
8663 // smi. This tells the builtin that we need to translate the unoptimized
8664 // frame to an optimized one.
8665 if (succeeded) {
8666 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8667 return Smi::FromInt(ast_id);
8668 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008669 if (function->IsMarkedForLazyRecompilation()) {
8670 function->ReplaceCode(function->shared()->code());
8671 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008672 return Smi::FromInt(-1);
8673 }
8674}
8675
8676
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008677RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8678 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8679 return isolate->heap()->undefined_value();
8680}
8681
8682
danno@chromium.orgc612e022011-11-10 11:38:15 +00008683RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8684 HandleScope scope(isolate);
8685 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008686 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008687 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8688 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008689
8690 // If there are too many arguments, allocate argv via malloc.
8691 const int argv_small_size = 10;
8692 Handle<Object> argv_small_buffer[argv_small_size];
8693 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8694 Handle<Object>* argv = argv_small_buffer;
8695 if (argc > argv_small_size) {
8696 argv = new Handle<Object>[argc];
8697 if (argv == NULL) return isolate->StackOverflow();
8698 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8699 }
8700
8701 for (int i = 0; i < argc; ++i) {
8702 MaybeObject* maybe = args[1 + i];
8703 Object* object;
8704 if (!maybe->To<Object>(&object)) return maybe;
8705 argv[i] = Handle<Object>(object);
8706 }
8707
8708 bool threw;
8709 Handle<JSReceiver> hfun(fun);
8710 Handle<Object> hreceiver(receiver);
8711 Handle<Object> result =
8712 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8713
8714 if (threw) return Failure::Exception();
8715 return *result;
8716}
8717
8718
lrn@chromium.org34e60782011-09-15 07:25:40 +00008719RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8720 HandleScope scope(isolate);
8721 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008722 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008723 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008724 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008725 CONVERT_SMI_ARG_CHECKED(offset, 3);
8726 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008727 ASSERT(offset >= 0);
8728 ASSERT(argc >= 0);
8729
8730 // If there are too many arguments, allocate argv via malloc.
8731 const int argv_small_size = 10;
8732 Handle<Object> argv_small_buffer[argv_small_size];
8733 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8734 Handle<Object>* argv = argv_small_buffer;
8735 if (argc > argv_small_size) {
8736 argv = new Handle<Object>[argc];
8737 if (argv == NULL) return isolate->StackOverflow();
8738 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8739 }
8740
8741 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008742 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008743 }
8744
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008745 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008746 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008747 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008748
8749 if (threw) return Failure::Exception();
8750 return *result;
8751}
8752
8753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008754RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008755 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008756 ASSERT(args.length() == 1);
8757 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8758 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8759}
8760
8761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008762RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008763 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008764 ASSERT(args.length() == 1);
8765 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8766 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8767}
8768
8769
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008770RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008771 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008772 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008773
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008774 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008775 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008776 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008777 { MaybeObject* maybe_result =
8778 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008779 if (!maybe_result->ToObject(&result)) return maybe_result;
8780 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008781
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008782 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008783
kasper.lund7276f142008-07-30 08:49:36 +00008784 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008785}
8786
lrn@chromium.org303ada72010-10-27 09:33:13 +00008787
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008788RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8789 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008790 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008791 JSObject* extension_object;
8792 if (args[0]->IsJSObject()) {
8793 extension_object = JSObject::cast(args[0]);
8794 } else {
8795 // Convert the object to a proper JavaScript object.
8796 MaybeObject* maybe_js_object = args[0]->ToObject();
8797 if (!maybe_js_object->To(&extension_object)) {
8798 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8799 HandleScope scope(isolate);
8800 Handle<Object> handle = args.at<Object>(0);
8801 Handle<Object> result =
8802 isolate->factory()->NewTypeError("with_expression",
8803 HandleVector(&handle, 1));
8804 return isolate->Throw(*result);
8805 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008806 return maybe_js_object;
8807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008808 }
8809 }
8810
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008811 JSFunction* function;
8812 if (args[1]->IsSmi()) {
8813 // A smi sentinel indicates a context nested inside global code rather
8814 // than some function. There is a canonical empty function that can be
8815 // gotten from the global context.
8816 function = isolate->context()->global_context()->closure();
8817 } else {
8818 function = JSFunction::cast(args[1]);
8819 }
8820
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008821 Context* context;
8822 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008823 isolate->heap()->AllocateWithContext(function,
8824 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008825 extension_object);
8826 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008827 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008828 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008829}
8830
8831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008832RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008833 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008834 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008835 String* name = String::cast(args[0]);
8836 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008837 JSFunction* function;
8838 if (args[2]->IsSmi()) {
8839 // A smi sentinel indicates a context nested inside global code rather
8840 // than some function. There is a canonical empty function that can be
8841 // gotten from the global context.
8842 function = isolate->context()->global_context()->closure();
8843 } else {
8844 function = JSFunction::cast(args[2]);
8845 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008846 Context* context;
8847 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008848 isolate->heap()->AllocateCatchContext(function,
8849 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008850 name,
8851 thrown_object);
8852 if (!maybe_context->To(&context)) return maybe_context;
8853 isolate->set_context(context);
8854 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008855}
8856
8857
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008858RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8859 NoHandleAllocation ha;
8860 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008861 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008862 JSFunction* function;
8863 if (args[1]->IsSmi()) {
8864 // A smi sentinel indicates a context nested inside global code rather
8865 // than some function. There is a canonical empty function that can be
8866 // gotten from the global context.
8867 function = isolate->context()->global_context()->closure();
8868 } else {
8869 function = JSFunction::cast(args[1]);
8870 }
8871 Context* context;
8872 MaybeObject* maybe_context =
8873 isolate->heap()->AllocateBlockContext(function,
8874 isolate->context(),
8875 scope_info);
8876 if (!maybe_context->To(&context)) return maybe_context;
8877 isolate->set_context(context);
8878 return context;
8879}
8880
8881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008882RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008883 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008884 ASSERT(args.length() == 2);
8885
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008886 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8887 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008888
8889 int index;
8890 PropertyAttributes attributes;
8891 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008892 BindingFlags binding_flags;
8893 Handle<Object> holder = context->Lookup(name,
8894 flags,
8895 &index,
8896 &attributes,
8897 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008898
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008899 // If the slot was not found the result is true.
8900 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008901 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008902 }
8903
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008904 // If the slot was found in a context, it should be DONT_DELETE.
8905 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008906 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008907 }
8908
8909 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008910 // the global object, or the subject of a with. Try to delete it
8911 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008912 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008913 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008914}
8915
8916
ager@chromium.orga1645e22009-09-09 19:27:10 +00008917// A mechanism to return a pair of Object pointers in registers (if possible).
8918// How this is achieved is calling convention-dependent.
8919// All currently supported x86 compiles uses calling conventions that are cdecl
8920// variants where a 64-bit value is returned in two 32-bit registers
8921// (edx:eax on ia32, r1:r0 on ARM).
8922// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8923// In Win64 calling convention, a struct of two pointers is returned in memory,
8924// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008925#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008926struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008927 MaybeObject* x;
8928 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008929};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008930
lrn@chromium.org303ada72010-10-27 09:33:13 +00008931static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008932 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008933 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8934 // In Win64 they are assigned to a hidden first argument.
8935 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008936}
8937#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008938typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008939static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008940 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008941 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008942}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008943#endif
8944
8945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008946static inline MaybeObject* Unhole(Heap* heap,
8947 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008948 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008949 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8950 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008951 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008952}
8953
8954
danno@chromium.org40cb8782011-05-25 07:58:50 +00008955static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8956 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008957 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008958 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008959 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008960 JSFunction* context_extension_function =
8961 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008962 // If the holder isn't a context extension object, we just return it
8963 // as the receiver. This allows arguments objects to be used as
8964 // receivers, but only if they are put in the context scope chain
8965 // explicitly via a with-statement.
8966 Object* constructor = holder->map()->constructor();
8967 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008968 // Fall back to using the global object as the implicit receiver if
8969 // the property turns out to be a local variable allocated in a
8970 // context extension object - introduced via eval. Implicit global
8971 // receivers are indicated with the hole value.
8972 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008973}
8974
8975
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008976static ObjectPair LoadContextSlotHelper(Arguments args,
8977 Isolate* isolate,
8978 bool throw_error) {
8979 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008980 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008982 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008983 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008984 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008985 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008986 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008987
8988 int index;
8989 PropertyAttributes attributes;
8990 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008991 BindingFlags binding_flags;
8992 Handle<Object> holder = context->Lookup(name,
8993 flags,
8994 &index,
8995 &attributes,
8996 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008997
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008998 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008999 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009000 ASSERT(holder->IsContext());
9001 // If the "property" we were looking for is a local variable, the
9002 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009003 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009004 // Use the hole as the receiver to signal that the receiver is implicit
9005 // and that the global receiver should be used (as distinguished from an
9006 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009007 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009008 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009009 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009010 switch (binding_flags) {
9011 case MUTABLE_CHECK_INITIALIZED:
9012 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9013 if (value->IsTheHole()) {
9014 Handle<Object> reference_error =
9015 isolate->factory()->NewReferenceError("not_defined",
9016 HandleVector(&name, 1));
9017 return MakePair(isolate->Throw(*reference_error), NULL);
9018 }
9019 // FALLTHROUGH
9020 case MUTABLE_IS_INITIALIZED:
9021 case IMMUTABLE_IS_INITIALIZED:
9022 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9023 ASSERT(!value->IsTheHole());
9024 return MakePair(value, *receiver);
9025 case IMMUTABLE_CHECK_INITIALIZED:
9026 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9027 case MISSING_BINDING:
9028 UNREACHABLE();
9029 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009030 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031 }
9032
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009033 // Otherwise, if the slot was found the holder is a context extension
9034 // object, subject of a with, or a global object. We read the named
9035 // property from it.
9036 if (!holder.is_null()) {
9037 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9038 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009039 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009040 Handle<Object> receiver_handle(object->IsGlobalObject()
9041 ? GlobalObject::cast(*object)->global_receiver()
9042 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009043
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009044 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009045 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009046 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009047 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009048 }
9049
9050 if (throw_error) {
9051 // The property doesn't exist - throw exception.
9052 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009053 isolate->factory()->NewReferenceError("not_defined",
9054 HandleVector(&name, 1));
9055 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009056 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009057 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009058 return MakePair(isolate->heap()->undefined_value(),
9059 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009060 }
9061}
9062
9063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009064RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009065 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009066}
9067
9068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009069RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009070 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071}
9072
9073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009074RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009075 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009076 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009077
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009078 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009079 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
9080 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009081 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9082 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9083 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009084
9085 int index;
9086 PropertyAttributes attributes;
9087 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009088 BindingFlags binding_flags;
9089 Handle<Object> holder = context->Lookup(name,
9090 flags,
9091 &index,
9092 &attributes,
9093 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009094
9095 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009096 // The property was found in a context slot.
9097 Handle<Context> context = Handle<Context>::cast(holder);
9098 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9099 context->get(index)->IsTheHole()) {
9100 Handle<Object> error =
9101 isolate->factory()->NewReferenceError("not_defined",
9102 HandleVector(&name, 1));
9103 return isolate->Throw(*error);
9104 }
9105 // Ignore if read_only variable.
9106 if ((attributes & READ_ONLY) == 0) {
9107 // Context is a fixed array and set cannot fail.
9108 context->set(index, *value);
9109 } else if (strict_mode == kStrictMode) {
9110 // Setting read only property in strict mode.
9111 Handle<Object> error =
9112 isolate->factory()->NewTypeError("strict_cannot_assign",
9113 HandleVector(&name, 1));
9114 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009115 }
9116 return *value;
9117 }
9118
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009119 // Slow case: The property is not in a context slot. It is either in a
9120 // context extension object, a property of the subject of a with, or a
9121 // property of the global object.
9122 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009123
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009124 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009125 // The property exists on the holder.
9126 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009128 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009129 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009130
9131 if (strict_mode == kStrictMode) {
9132 // Throw in strict mode (assignment to undefined variable).
9133 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009134 isolate->factory()->NewReferenceError(
9135 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009136 return isolate->Throw(*error);
9137 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009138 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009139 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009140 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009141 }
9142
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009143 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009144 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009145 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009146 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009147 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009148 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009149 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009150 // Setting read only property in strict mode.
9151 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009152 isolate->factory()->NewTypeError(
9153 "strict_cannot_assign", HandleVector(&name, 1));
9154 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155 }
9156 return *value;
9157}
9158
9159
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009160RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009161 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162 ASSERT(args.length() == 1);
9163
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009164 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009165}
9166
9167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009168RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009169 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009170 ASSERT(args.length() == 1);
9171
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009172 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009173}
9174
9175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009176RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009177 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009178 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009179}
9180
9181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009182RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009183 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009184 ASSERT(args.length() == 1);
9185
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009186 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009187 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009188 isolate->factory()->NewReferenceError("not_defined",
9189 HandleVector(&name, 1));
9190 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009191}
9192
9193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009194RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009195 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009196
9197 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009198 if (isolate->stack_guard()->IsStackOverflow()) {
9199 NoHandleAllocation na;
9200 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009201 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009202
ulan@chromium.org812308e2012-02-29 15:58:45 +00009203 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009204}
9205
9206
yangguo@chromium.org56454712012-02-16 15:33:53 +00009207RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
9208 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00009209 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00009210}
9211
9212
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009213static int StackSize() {
9214 int n = 0;
9215 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9216 return n;
9217}
9218
9219
9220static void PrintTransition(Object* result) {
9221 // indentation
9222 { const int nmax = 80;
9223 int n = StackSize();
9224 if (n <= nmax)
9225 PrintF("%4d:%*s", n, n, "");
9226 else
9227 PrintF("%4d:%*s", n, nmax, "...");
9228 }
9229
9230 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009231 JavaScriptFrame::PrintTop(stdout, true, false);
9232 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009233 } else {
9234 // function result
9235 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009236 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009237 PrintF("\n");
9238 }
9239}
9240
9241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009242RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009243 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244 NoHandleAllocation ha;
9245 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009246 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009247}
9248
9249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009250RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009251 NoHandleAllocation ha;
9252 PrintTransition(args[0]);
9253 return args[0]; // return TOS
9254}
9255
9256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009257RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009258 NoHandleAllocation ha;
9259 ASSERT(args.length() == 1);
9260
9261#ifdef DEBUG
9262 if (args[0]->IsString()) {
9263 // If we have a string, assume it's a code "marker"
9264 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009265 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009266 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009267 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9268 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009269 } else {
9270 PrintF("DebugPrint: ");
9271 }
9272 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009273 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009274 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009275 HeapObject::cast(args[0])->map()->Print();
9276 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009277#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009278 // ShortPrint is available in release mode. Print is not.
9279 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009280#endif
9281 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009282 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009283
9284 return args[0]; // return TOS
9285}
9286
9287
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009288RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009289 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009290 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009291 isolate->PrintStack();
9292 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009293}
9294
9295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009296RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009297 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009298 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009299
9300 // According to ECMA-262, section 15.9.1, page 117, the precision of
9301 // the number in a Date object representing a particular instant in
9302 // time is milliseconds. Therefore, we floor the result of getting
9303 // the OS time.
9304 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009305 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009306}
9307
9308
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009309RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009310 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009311 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009313 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009314 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009316 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009317
9318 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009319 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009320 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009321 RUNTIME_ASSERT(output->HasFastElements());
9322
9323 AssertNoAllocation no_allocation;
9324
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009325 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009326 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9327 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009328 String::FlatContent str_content = str->GetFlatContent();
9329 if (str_content.IsAscii()) {
9330 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009331 output_array,
9332 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009333 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009334 ASSERT(str_content.IsTwoByte());
9335 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009336 output_array,
9337 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009338 }
9339
9340 if (result) {
9341 return *output;
9342 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009343 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009344 }
9345}
9346
9347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009348RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349 NoHandleAllocation ha;
9350 ASSERT(args.length() == 1);
9351
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009352 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009353 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009354 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009355}
9356
9357
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009358RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009359 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009360 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009362 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009363}
9364
9365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009366RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367 NoHandleAllocation ha;
9368 ASSERT(args.length() == 1);
9369
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009370 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009371 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009372}
9373
9374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009375RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009376 ASSERT(args.length() == 1);
9377 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009378 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009379 return JSGlobalObject::cast(global)->global_receiver();
9380}
9381
9382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009383RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009384 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009385 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009386 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009387
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009388 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009389 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009390 Handle<Object> result;
9391 if (source->IsSeqAsciiString()) {
9392 result = JsonParser<true>::Parse(source);
9393 } else {
9394 result = JsonParser<false>::Parse(source);
9395 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009396 if (result.is_null()) {
9397 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009399 return Failure::Exception();
9400 }
9401 return *result;
9402}
9403
9404
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009405bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9406 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009407 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9408 // Check with callback if set.
9409 AllowCodeGenerationFromStringsCallback callback =
9410 isolate->allow_code_gen_callback();
9411 if (callback == NULL) {
9412 // No callback set and code generation disallowed.
9413 return false;
9414 } else {
9415 // Callback set. Let it decide if code generation is allowed.
9416 VMState state(isolate, EXTERNAL);
9417 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009418 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009419}
9420
9421
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009422RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009423 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009424 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009425 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009426
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009427 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009428 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009429
9430 // Check if global context allows code generation from
9431 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009432 if (context->allow_code_gen_from_strings()->IsFalse() &&
9433 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009434 return isolate->Throw(*isolate->factory()->NewError(
9435 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9436 }
9437
9438 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009439 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009440 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009441 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009442 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009443 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9444 context,
9445 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009446 return *fun;
9447}
9448
9449
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009450static ObjectPair CompileGlobalEval(Isolate* isolate,
9451 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009452 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009453 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009454 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009455 Handle<Context> context = Handle<Context>(isolate->context());
9456 Handle<Context> global_context = Handle<Context>(context->global_context());
9457
9458 // Check if global context allows code generation from
9459 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009460 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9461 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009462 isolate->Throw(*isolate->factory()->NewError(
9463 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9464 return MakePair(Failure::Exception(), NULL);
9465 }
9466
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009467 // Deal with a normal eval call with a string argument. Compile it
9468 // and return the compiled function bound in the local context.
9469 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9470 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009471 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009472 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009473 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009474 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009475 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009476 Handle<JSFunction> compiled =
9477 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009478 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009479 return MakePair(*compiled, *receiver);
9480}
9481
9482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009483RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009484 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009486 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009487 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009488
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009489 // If "eval" didn't refer to the original GlobalEval, it's not a
9490 // direct call to eval.
9491 // (And even if it is, but the first argument isn't a string, just let
9492 // execution default to an indirect call to eval, which will also return
9493 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009494 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009495 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009496 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009497 }
9498
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009499 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009500 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009501 return CompileGlobalEval(isolate,
9502 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009503 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009504 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009505 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009506}
9507
9508
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009509RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009510 // This utility adjusts the property attributes for newly created Function
9511 // object ("new Function(...)") by changing the map.
9512 // All it does is changing the prototype property to enumerable
9513 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009514 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009515 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009516 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009517
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009518 Handle<Map> map = func->shared()->is_classic_mode()
9519 ? isolate->function_instance_map()
9520 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009521
9522 ASSERT(func->map()->instance_type() == map->instance_type());
9523 ASSERT(func->map()->instance_size() == map->instance_size());
9524 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009525 return *func;
9526}
9527
9528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009529RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009530 // Allocate a block of memory in NewSpace (filled with a filler).
9531 // Use as fallback for allocation in generated code when NewSpace
9532 // is full.
9533 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009534 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009535 int size = size_smi->value();
9536 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9537 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009538 Heap* heap = isolate->heap();
9539 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009540 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009541 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009543 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009544 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009545 }
9546 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009547 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009548}
9549
9550
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009551// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009552// array. Returns true if the element was pushed on the stack and
9553// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009554RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009555 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009556 CONVERT_ARG_CHECKED(JSArray, array, 0);
9557 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009558 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009559 int length = Smi::cast(array->length())->value();
9560 FixedArray* elements = FixedArray::cast(array->elements());
9561 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009562 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009563 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009564 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009565 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009566 { MaybeObject* maybe_obj =
9567 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009568 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9569 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009571}
9572
9573
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009574/**
9575 * A simple visitor visits every element of Array's.
9576 * The backend storage can be a fixed array for fast elements case,
9577 * or a dictionary for sparse array. Since Dictionary is a subtype
9578 * of FixedArray, the class can be used by both fast and slow cases.
9579 * The second parameter of the constructor, fast_elements, specifies
9580 * whether the storage is a FixedArray or Dictionary.
9581 *
9582 * An index limit is used to deal with the situation that a result array
9583 * length overflows 32-bit non-negative integer.
9584 */
9585class ArrayConcatVisitor {
9586 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009587 ArrayConcatVisitor(Isolate* isolate,
9588 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009589 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009590 isolate_(isolate),
9591 storage_(Handle<FixedArray>::cast(
9592 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009593 index_offset_(0u),
9594 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009595
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009596 ~ArrayConcatVisitor() {
9597 clear_storage();
9598 }
9599
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009600 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009601 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009602 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009603
9604 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009605 if (index < static_cast<uint32_t>(storage_->length())) {
9606 storage_->set(index, *elm);
9607 return;
9608 }
9609 // Our initial estimate of length was foiled, possibly by
9610 // getters on the arrays increasing the length of later arrays
9611 // during iteration.
9612 // This shouldn't happen in anything but pathological cases.
9613 SetDictionaryMode(index);
9614 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009615 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009616 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009617 Handle<SeededNumberDictionary> dict(
9618 SeededNumberDictionary::cast(*storage_));
9619 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009620 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009621 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009622 // Dictionary needed to grow.
9623 clear_storage();
9624 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009625 }
9626}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009627
9628 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009629 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9630 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009631 } else {
9632 index_offset_ += delta;
9633 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009634 }
9635
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009636 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009637 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009638 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009639 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009640 Handle<Map> map;
9641 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009642 map = isolate_->factory()->GetElementsTransitionMap(array,
9643 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009644 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009645 map = isolate_->factory()->GetElementsTransitionMap(array,
9646 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009647 }
9648 array->set_map(*map);
9649 array->set_length(*length);
9650 array->set_elements(*storage_);
9651 return array;
9652 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009653
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009654 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009655 // Convert storage to dictionary mode.
9656 void SetDictionaryMode(uint32_t index) {
9657 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009658 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009659 Handle<SeededNumberDictionary> slow_storage(
9660 isolate_->factory()->NewSeededNumberDictionary(
9661 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009662 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9663 for (uint32_t i = 0; i < current_length; i++) {
9664 HandleScope loop_scope;
9665 Handle<Object> element(current_storage->get(i));
9666 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009667 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009668 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009669 if (!new_storage.is_identical_to(slow_storage)) {
9670 slow_storage = loop_scope.CloseAndEscape(new_storage);
9671 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009672 }
9673 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009674 clear_storage();
9675 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009676 fast_elements_ = false;
9677 }
9678
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009679 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009680 isolate_->global_handles()->Destroy(
9681 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009682 }
9683
9684 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009685 storage_ = Handle<FixedArray>::cast(
9686 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009687 }
9688
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009689 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009690 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009691 // Index after last seen index. Always less than or equal to
9692 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009693 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009694 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009695};
9696
9697
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009698static uint32_t EstimateElementCount(Handle<JSArray> array) {
9699 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9700 int element_count = 0;
9701 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009702 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009703 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009704 // Fast elements can't have lengths that are not representable by
9705 // a 32-bit signed integer.
9706 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9707 int fast_length = static_cast<int>(length);
9708 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9709 for (int i = 0; i < fast_length; i++) {
9710 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009711 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009712 break;
9713 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009714 case FAST_DOUBLE_ELEMENTS:
9715 // TODO(1810): Decide if it's worthwhile to implement this.
9716 UNREACHABLE();
9717 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009718 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009719 Handle<SeededNumberDictionary> dictionary(
9720 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009721 int capacity = dictionary->Capacity();
9722 for (int i = 0; i < capacity; i++) {
9723 Handle<Object> key(dictionary->KeyAt(i));
9724 if (dictionary->IsKey(*key)) {
9725 element_count++;
9726 }
9727 }
9728 break;
9729 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009730 case NON_STRICT_ARGUMENTS_ELEMENTS:
9731 case EXTERNAL_BYTE_ELEMENTS:
9732 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9733 case EXTERNAL_SHORT_ELEMENTS:
9734 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9735 case EXTERNAL_INT_ELEMENTS:
9736 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9737 case EXTERNAL_FLOAT_ELEMENTS:
9738 case EXTERNAL_DOUBLE_ELEMENTS:
9739 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009740 // External arrays are always dense.
9741 return length;
9742 }
9743 // As an estimate, we assume that the prototype doesn't contain any
9744 // inherited elements.
9745 return element_count;
9746}
9747
9748
9749
9750template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009751static void IterateExternalArrayElements(Isolate* isolate,
9752 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009753 bool elements_are_ints,
9754 bool elements_are_guaranteed_smis,
9755 ArrayConcatVisitor* visitor) {
9756 Handle<ExternalArrayClass> array(
9757 ExternalArrayClass::cast(receiver->elements()));
9758 uint32_t len = static_cast<uint32_t>(array->length());
9759
9760 ASSERT(visitor != NULL);
9761 if (elements_are_ints) {
9762 if (elements_are_guaranteed_smis) {
9763 for (uint32_t j = 0; j < len; j++) {
9764 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009765 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009766 visitor->visit(j, e);
9767 }
9768 } else {
9769 for (uint32_t j = 0; j < len; j++) {
9770 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009771 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009772 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9773 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9774 visitor->visit(j, e);
9775 } else {
9776 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009777 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009778 visitor->visit(j, e);
9779 }
9780 }
9781 }
9782 } else {
9783 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009784 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009785 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009786 visitor->visit(j, e);
9787 }
9788 }
9789}
9790
9791
9792// Used for sorting indices in a List<uint32_t>.
9793static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9794 uint32_t a = *ap;
9795 uint32_t b = *bp;
9796 return (a == b) ? 0 : (a < b) ? -1 : 1;
9797}
9798
9799
9800static void CollectElementIndices(Handle<JSObject> object,
9801 uint32_t range,
9802 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009803 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009804 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009805 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009806 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009807 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9808 uint32_t length = static_cast<uint32_t>(elements->length());
9809 if (range < length) length = range;
9810 for (uint32_t i = 0; i < length; i++) {
9811 if (!elements->get(i)->IsTheHole()) {
9812 indices->Add(i);
9813 }
9814 }
9815 break;
9816 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009817 case FAST_DOUBLE_ELEMENTS: {
9818 // TODO(1810): Decide if it's worthwhile to implement this.
9819 UNREACHABLE();
9820 break;
9821 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009822 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009823 Handle<SeededNumberDictionary> dict(
9824 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009825 uint32_t capacity = dict->Capacity();
9826 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009827 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009828 Handle<Object> k(dict->KeyAt(j));
9829 if (dict->IsKey(*k)) {
9830 ASSERT(k->IsNumber());
9831 uint32_t index = static_cast<uint32_t>(k->Number());
9832 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009833 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009834 }
9835 }
9836 }
9837 break;
9838 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009839 default: {
9840 int dense_elements_length;
9841 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009842 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009843 dense_elements_length =
9844 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009845 break;
9846 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009847 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009848 dense_elements_length =
9849 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009850 break;
9851 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009852 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009853 dense_elements_length =
9854 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009855 break;
9856 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009857 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009858 dense_elements_length =
9859 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009860 break;
9861 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009862 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009863 dense_elements_length =
9864 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009865 break;
9866 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009867 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009868 dense_elements_length =
9869 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009870 break;
9871 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009872 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009873 dense_elements_length =
9874 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009875 break;
9876 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009877 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009878 dense_elements_length =
9879 ExternalFloatArray::cast(object->elements())->length();
9880 break;
9881 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009882 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009883 dense_elements_length =
9884 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009885 break;
9886 }
9887 default:
9888 UNREACHABLE();
9889 dense_elements_length = 0;
9890 break;
9891 }
9892 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9893 if (range <= length) {
9894 length = range;
9895 // We will add all indices, so we might as well clear it first
9896 // and avoid duplicates.
9897 indices->Clear();
9898 }
9899 for (uint32_t i = 0; i < length; i++) {
9900 indices->Add(i);
9901 }
9902 if (length == range) return; // All indices accounted for already.
9903 break;
9904 }
9905 }
9906
9907 Handle<Object> prototype(object->GetPrototype());
9908 if (prototype->IsJSObject()) {
9909 // The prototype will usually have no inherited element indices,
9910 // but we have to check.
9911 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9912 }
9913}
9914
9915
9916/**
9917 * A helper function that visits elements of a JSArray in numerical
9918 * order.
9919 *
9920 * The visitor argument called for each existing element in the array
9921 * with the element index and the element's value.
9922 * Afterwards it increments the base-index of the visitor by the array
9923 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009924 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009925 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009926static bool IterateElements(Isolate* isolate,
9927 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009928 ArrayConcatVisitor* visitor) {
9929 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9930 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009931 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009932 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009933 // Run through the elements FixedArray and use HasElement and GetElement
9934 // to check the prototype for missing elements.
9935 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9936 int fast_length = static_cast<int>(length);
9937 ASSERT(fast_length <= elements->length());
9938 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009939 HandleScope loop_scope(isolate);
9940 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009941 if (!element_value->IsTheHole()) {
9942 visitor->visit(j, element_value);
9943 } else if (receiver->HasElement(j)) {
9944 // Call GetElement on receiver, not its prototype, or getters won't
9945 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009946 element_value = Object::GetElement(receiver, j);
9947 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009948 visitor->visit(j, element_value);
9949 }
9950 }
9951 break;
9952 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009953 case FAST_DOUBLE_ELEMENTS: {
9954 // TODO(1810): Decide if it's worthwhile to implement this.
9955 UNREACHABLE();
9956 break;
9957 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009958 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009959 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009960 List<uint32_t> indices(dict->Capacity() / 2);
9961 // Collect all indices in the object and the prototypes less
9962 // than length. This might introduce duplicates in the indices list.
9963 CollectElementIndices(receiver, length, &indices);
9964 indices.Sort(&compareUInt32);
9965 int j = 0;
9966 int n = indices.length();
9967 while (j < n) {
9968 HandleScope loop_scope;
9969 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009970 Handle<Object> element = Object::GetElement(receiver, index);
9971 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009972 visitor->visit(index, element);
9973 // Skip to next different index (i.e., omit duplicates).
9974 do {
9975 j++;
9976 } while (j < n && indices[j] == index);
9977 }
9978 break;
9979 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009980 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009981 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9982 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009983 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009984 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009985 visitor->visit(j, e);
9986 }
9987 break;
9988 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009989 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009990 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009991 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009992 break;
9993 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009994 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009995 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009996 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009997 break;
9998 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009999 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010000 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010001 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010002 break;
10003 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010004 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010005 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010006 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010007 break;
10008 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010009 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010010 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010011 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010012 break;
10013 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010014 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010015 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010016 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010017 break;
10018 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010019 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010020 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010022 break;
10023 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010024 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010025 IterateExternalArrayElements<ExternalDoubleArray, double>(
10026 isolate, receiver, false, false, visitor);
10027 break;
10028 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010029 default:
10030 UNREACHABLE();
10031 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010032 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010033 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010034 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010035}
10036
10037
10038/**
10039 * Array::concat implementation.
10040 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010041 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010042 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010043 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010044RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010045 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010046 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010047
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010048 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010049 int argument_count = static_cast<int>(arguments->length()->Number());
10050 RUNTIME_ASSERT(arguments->HasFastElements());
10051 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010052
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010053 // Pass 1: estimate the length and number of elements of the result.
10054 // The actual length can be larger if any of the arguments have getters
10055 // that mutate other arguments (but will otherwise be precise).
10056 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010057
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010058 uint32_t estimate_result_length = 0;
10059 uint32_t estimate_nof_elements = 0;
10060 {
10061 for (int i = 0; i < argument_count; i++) {
10062 HandleScope loop_scope;
10063 Handle<Object> obj(elements->get(i));
10064 uint32_t length_estimate;
10065 uint32_t element_estimate;
10066 if (obj->IsJSArray()) {
10067 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010068 // TODO(1810): Find out if it's worthwhile to properly support
10069 // arbitrary ElementsKinds. For now, pessimistically transition to
10070 // FAST_ELEMENTS.
10071 if (array->HasFastDoubleElements()) {
10072 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010073 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010074 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010075 length_estimate =
10076 static_cast<uint32_t>(array->length()->Number());
10077 element_estimate =
10078 EstimateElementCount(array);
10079 } else {
10080 length_estimate = 1;
10081 element_estimate = 1;
10082 }
10083 // Avoid overflows by capping at kMaxElementCount.
10084 if (JSObject::kMaxElementCount - estimate_result_length <
10085 length_estimate) {
10086 estimate_result_length = JSObject::kMaxElementCount;
10087 } else {
10088 estimate_result_length += length_estimate;
10089 }
10090 if (JSObject::kMaxElementCount - estimate_nof_elements <
10091 element_estimate) {
10092 estimate_nof_elements = JSObject::kMaxElementCount;
10093 } else {
10094 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010095 }
10096 }
10097 }
10098
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010099 // If estimated number of elements is more than half of length, a
10100 // fixed array (fast case) is more time and space-efficient than a
10101 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010102 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010103
10104 Handle<FixedArray> storage;
10105 if (fast_case) {
10106 // The backing storage array must have non-existing elements to
10107 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010108 storage = isolate->factory()->NewFixedArrayWithHoles(
10109 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010110 } else {
10111 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10112 uint32_t at_least_space_for = estimate_nof_elements +
10113 (estimate_nof_elements >> 2);
10114 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010115 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010116 }
10117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010118 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010119
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010120 for (int i = 0; i < argument_count; i++) {
10121 Handle<Object> obj(elements->get(i));
10122 if (obj->IsJSArray()) {
10123 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010124 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010125 return Failure::Exception();
10126 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010127 } else {
10128 visitor.visit(0, obj);
10129 visitor.increase_index_offset(1);
10130 }
10131 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010132
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010133 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010134}
10135
10136
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010137// This will not allocate (flatten the string), but it may run
10138// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010139RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010140 NoHandleAllocation ha;
10141 ASSERT(args.length() == 1);
10142
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010143 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144 StringInputBuffer buffer(string);
10145 while (buffer.has_more()) {
10146 uint16_t character = buffer.GetNext();
10147 PrintF("%c", character);
10148 }
10149 return string;
10150}
10151
ager@chromium.org5ec48922009-05-05 07:25:34 +000010152// Moves all own elements of an object, that are below a limit, to positions
10153// starting at zero. All undefined values are placed after non-undefined values,
10154// and are followed by non-existing element. Does not change the length
10155// property.
10156// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010157RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010158 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010159 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010160 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10161 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010162}
10163
10164
10165// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010166RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010167 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010168 CONVERT_ARG_CHECKED(JSArray, from, 0);
10169 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010170 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010171 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010172 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010173 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10174 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010175 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010176 } else if (new_elements->map() ==
10177 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010178 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010179 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010180 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010181 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010182 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010183 Object* new_map;
10184 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010185 to->set_map(Map::cast(new_map));
10186 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010187 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010188 Object* obj;
10189 { MaybeObject* maybe_obj = from->ResetElements();
10190 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10191 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010192 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010193 return to;
10194}
10195
10196
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010197// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010198RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010199 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010200 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010201 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010202 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010203 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10204 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010205 } else if (object->IsJSArray()) {
10206 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010207 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010208 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010209 }
10210}
10211
10212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010213RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010214 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010215
10216 ASSERT_EQ(3, args.length());
10217
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010218 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010219 Handle<Object> key1 = args.at<Object>(1);
10220 Handle<Object> key2 = args.at<Object>(2);
10221
10222 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010223 if (!key1->ToArrayIndex(&index1)
10224 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010225 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010226 }
10227
ager@chromium.orgac091b72010-05-05 07:34:42 +000010228 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010229 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010230 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010231 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010232 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010233
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010234 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010235 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010236 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010237 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010238
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010239 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010240}
10241
10242
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010244// might have elements. Can either return keys (positive integers) or
10245// intervals (pair of a negative integer (-start-1) followed by a
10246// positive (length)) or undefined values.
10247// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010248RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010250 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010251 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010252 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010253 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 // Create an array and get all the keys into it, then remove all the
10255 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010256 bool threw = false;
10257 Handle<FixedArray> keys =
10258 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10259 if (threw) return Failure::Exception();
10260
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010261 int keys_length = keys->length();
10262 for (int i = 0; i < keys_length; i++) {
10263 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010264 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010265 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010266 // Zap invalid keys.
10267 keys->set_undefined(i);
10268 }
10269 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010270 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010271 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010272 ASSERT(array->HasFastElements() ||
10273 array->HasFastSmiOnlyElements() ||
10274 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010275 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010276 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010277 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010278 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010279 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010280 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010281 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010282 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010283 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010285 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286 }
10287}
10288
10289
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010290RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010292 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10293 CONVERT_ARG_CHECKED(String, name, 1);
10294 CONVERT_SMI_ARG_CHECKED(flag, 2);
10295 return obj->LookupAccessor(name, flag == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296}
10297
10298
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010299#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010300RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010301 ASSERT(args.length() == 0);
10302 return Execution::DebugBreakHelper();
10303}
10304
10305
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010306// Helper functions for wrapping and unwrapping stack frame ids.
10307static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010308 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309 return Smi::FromInt(id >> 2);
10310}
10311
10312
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010313static StackFrame::Id UnwrapFrameId(int wrapped) {
10314 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315}
10316
10317
10318// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010319// args[0]: debug event listener function to set or null or undefined for
10320// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010321// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010322RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010324 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10325 args[0]->IsUndefined() ||
10326 args[0]->IsNull());
10327 Handle<Object> callback = args.at<Object>(0);
10328 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010329 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010331 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332}
10333
10334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010335RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010336 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010337 isolate->stack_guard()->DebugBreak();
10338 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010339}
10340
10341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010342static MaybeObject* DebugLookupResultValue(Heap* heap,
10343 Object* receiver,
10344 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010345 LookupResult* result,
10346 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010347 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010348 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010349 case NORMAL:
10350 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010351 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010352 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010353 }
10354 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010355 case FIELD:
10356 value =
10357 JSObject::cast(
10358 result->holder())->FastPropertyAt(result->GetFieldIndex());
10359 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010360 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010361 }
10362 return value;
10363 case CONSTANT_FUNCTION:
10364 return result->GetConstantFunction();
10365 case CALLBACKS: {
10366 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010367 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010368 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10369 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010370 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010371 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010372 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010373 maybe_value = heap->isolate()->pending_exception();
10374 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010375 if (caught_exception != NULL) {
10376 *caught_exception = true;
10377 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010378 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010379 }
10380 return value;
10381 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010382 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010383 }
10384 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010385 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010386 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010387 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010388 case CONSTANT_TRANSITION:
10389 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010390 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010391 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010392 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010393 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010394 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010395 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010396 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010397}
10398
10399
ager@chromium.org32912102009-01-16 10:38:43 +000010400// Get debugger related details for an object property.
10401// args[0]: object holding property
10402// args[1]: name of the property
10403//
10404// The array returned contains the following information:
10405// 0: Property value
10406// 1: Property details
10407// 2: Property value is exception
10408// 3: Getter function if defined
10409// 4: Setter function if defined
10410// Items 2-4 are only filled if the property has either a getter or a setter
10411// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010412RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010413 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414
10415 ASSERT(args.length() == 2);
10416
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010417 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10418 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010420 // Make sure to set the current context to the context before the debugger was
10421 // entered (if the debugger is entered). The reason for switching context here
10422 // is that for some property lookups (accessors and interceptors) callbacks
10423 // into the embedding application can occour, and the embedding application
10424 // could have the assumption that its own global context is the current
10425 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010426 SaveContext save(isolate);
10427 if (isolate->debug()->InDebugger()) {
10428 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010429 }
10430
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010431 // Skip the global proxy as it has no properties and always delegates to the
10432 // real global object.
10433 if (obj->IsJSGlobalProxy()) {
10434 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10435 }
10436
10437
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010438 // Check if the name is trivially convertible to an index and get the element
10439 // if so.
10440 uint32_t index;
10441 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010442 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010443 Object* element_or_char;
10444 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010445 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010446 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10447 return maybe_element_or_char;
10448 }
10449 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010450 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010451 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010452 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010453 }
10454
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010455 // Find the number of objects making up this.
10456 int length = LocalPrototypeChainLength(*obj);
10457
10458 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010459 Handle<JSObject> jsproto = obj;
10460 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010461 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010462 jsproto->LocalLookup(*name, &result);
10463 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010464 // LookupResult is not GC safe as it holds raw object pointers.
10465 // GC can happen later in this code so put the required fields into
10466 // local variables using handles when required for later use.
10467 PropertyType result_type = result.type();
10468 Handle<Object> result_callback_obj;
10469 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010470 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10471 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010472 }
10473 Smi* property_details = result.GetPropertyDetails().AsSmi();
10474 // DebugLookupResultValue can cause GC so details from LookupResult needs
10475 // to be copied to handles before this.
10476 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010477 Object* raw_value;
10478 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010479 DebugLookupResultValue(isolate->heap(), *obj, *name,
10480 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010481 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10482 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010483 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010484
10485 // If the callback object is a fixed array then it contains JavaScript
10486 // getter and/or setter.
10487 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010488 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010489 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010490 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010491 details->set(0, *value);
10492 details->set(1, property_details);
10493 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010494 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010495 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10496 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010497 }
10498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010499 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010500 }
10501 if (i < length - 1) {
10502 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10503 }
10504 }
10505
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010506 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507}
10508
10509
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010510RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010511 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010512
10513 ASSERT(args.length() == 2);
10514
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010515 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10516 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010517
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010518 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519 obj->Lookup(*name, &result);
10520 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010521 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010522 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010523 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524}
10525
10526
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527// Return the property type calculated from the property details.
10528// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010529RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010530 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010531 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10532 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010533}
10534
10535
10536// Return the property attribute calculated from the property details.
10537// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010538RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010539 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010540 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10541 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010542}
10543
10544
10545// Return the property insertion index calculated from the property details.
10546// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010547RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010548 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010549 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10550 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010551}
10552
10553
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010554// Return property value from named interceptor.
10555// args[0]: object
10556// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010557RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010558 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010559 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010560 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010562 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010563
10564 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010565 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010566}
10567
10568
10569// Return element value from indexed interceptor.
10570// args[0]: object
10571// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010572RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010573 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010575 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010576 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10577 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10578
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010579 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010580}
10581
10582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010583RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584 ASSERT(args.length() >= 1);
10585 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010586 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010587 if (isolate->debug()->break_id() == 0 ||
10588 break_id != isolate->debug()->break_id()) {
10589 return isolate->Throw(
10590 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010591 }
10592
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010593 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594}
10595
10596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010597RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010598 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599 ASSERT(args.length() == 1);
10600
10601 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010602 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010603 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10604 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010605 if (!maybe_result->ToObject(&result)) return maybe_result;
10606 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607
10608 // Count all frames which are relevant to debugging stack trace.
10609 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010610 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010611 if (id == StackFrame::NO_ID) {
10612 // If there is no JavaScript stack frame count is 0.
10613 return Smi::FromInt(0);
10614 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010615
10616 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10617 n += it.frame()->GetInlineCount();
10618 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619 return Smi::FromInt(n);
10620}
10621
10622
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010623class FrameInspector {
10624 public:
10625 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010626 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010627 Isolate* isolate)
10628 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10629 // Calculate the deoptimized frame.
10630 if (frame->is_optimized()) {
10631 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010632 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010633 }
10634 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010635 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010636 is_optimized_ = frame_->is_optimized();
10637 }
10638
10639 ~FrameInspector() {
10640 // Get rid of the calculated deoptimized frame if any.
10641 if (deoptimized_frame_ != NULL) {
10642 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10643 isolate_);
10644 }
10645 }
10646
10647 int GetParametersCount() {
10648 return is_optimized_
10649 ? deoptimized_frame_->parameters_count()
10650 : frame_->ComputeParametersCount();
10651 }
10652 int expression_count() { return deoptimized_frame_->expression_count(); }
10653 Object* GetFunction() {
10654 return is_optimized_
10655 ? deoptimized_frame_->GetFunction()
10656 : frame_->function();
10657 }
10658 Object* GetParameter(int index) {
10659 return is_optimized_
10660 ? deoptimized_frame_->GetParameter(index)
10661 : frame_->GetParameter(index);
10662 }
10663 Object* GetExpression(int index) {
10664 return is_optimized_
10665 ? deoptimized_frame_->GetExpression(index)
10666 : frame_->GetExpression(index);
10667 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010668 int GetSourcePosition() {
10669 return is_optimized_
10670 ? deoptimized_frame_->GetSourcePosition()
10671 : frame_->LookupCode()->SourcePosition(frame_->pc());
10672 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010673 bool IsConstructor() {
10674 return is_optimized_ && !is_bottommost_
10675 ? deoptimized_frame_->HasConstructStub()
10676 : frame_->IsConstructor();
10677 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010678
10679 // To inspect all the provided arguments the frame might need to be
10680 // replaced with the arguments frame.
10681 void SetArgumentsFrame(JavaScriptFrame* frame) {
10682 ASSERT(has_adapted_arguments_);
10683 frame_ = frame;
10684 is_optimized_ = frame_->is_optimized();
10685 ASSERT(!is_optimized_);
10686 }
10687
10688 private:
10689 JavaScriptFrame* frame_;
10690 DeoptimizedFrameInfo* deoptimized_frame_;
10691 Isolate* isolate_;
10692 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010693 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010694 bool has_adapted_arguments_;
10695
10696 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10697};
10698
10699
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010700static const int kFrameDetailsFrameIdIndex = 0;
10701static const int kFrameDetailsReceiverIndex = 1;
10702static const int kFrameDetailsFunctionIndex = 2;
10703static const int kFrameDetailsArgumentCountIndex = 3;
10704static const int kFrameDetailsLocalCountIndex = 4;
10705static const int kFrameDetailsSourcePositionIndex = 5;
10706static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010707static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010708static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010709static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010710
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010711
10712static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10713 JavaScriptFrame* frame) {
10714 SaveContext* save = isolate->save_context();
10715 while (save != NULL && !save->IsBelowFrame(frame)) {
10716 save = save->prev();
10717 }
10718 ASSERT(save != NULL);
10719 return save;
10720}
10721
10722
ulan@chromium.org967e2702012-02-28 09:49:15 +000010723RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
10724 NoHandleAllocation ha;
10725 ASSERT(args.length() == 0);
10726 JavaScriptFrameIterator it(isolate);
10727 JavaScriptFrame* frame = it.frame();
10728 FrameInspector frame_inspector(frame, frame->GetInlineCount() - 1, isolate);
10729 return isolate->heap()->ToBoolean(frame_inspector.IsConstructor());
10730}
10731
10732
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010733// Return an array with frame details
10734// args[0]: number: break id
10735// args[1]: number: frame index
10736//
10737// The array returned contains the following information:
10738// 0: Frame id
10739// 1: Receiver
10740// 2: Function
10741// 3: Argument count
10742// 4: Local count
10743// 5: Source position
10744// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010745// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010746// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010747// Arguments name, value
10748// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010749// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010750RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010751 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010752 ASSERT(args.length() == 2);
10753
10754 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010755 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010756 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10757 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010758 if (!maybe_check->ToObject(&check)) return maybe_check;
10759 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010760 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010761 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762
10763 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010764 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010765 if (id == StackFrame::NO_ID) {
10766 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010767 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010768 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010769
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010770 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010771 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010772 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010773 if (index < count + it.frame()->GetInlineCount()) break;
10774 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010775 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010776 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010777
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010778 bool is_optimized = it.frame()->is_optimized();
10779
10780 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10781 if (is_optimized) {
10782 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010783 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010784 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010785 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010786
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010787 // Traverse the saved contexts chain to find the active context for the
10788 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010789 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790
10791 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010792 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010793
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010794 // Find source position in unoptimized code.
10795 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010796
ulan@chromium.org967e2702012-02-28 09:49:15 +000010797 // Check for constructor frame.
10798 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010799
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010800 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010801 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010802 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010803 Handle<ScopeInfo> scope_info(shared->scope_info());
10804 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010805
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010806 // Get the locals names and values into a temporary array.
10807 //
10808 // TODO(1240907): Hide compiler-introduced stack variables
10809 // (e.g. .result)? For users of the debugger, they will probably be
10810 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010811 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010812 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010813
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010814 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010815 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010816 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010817 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010818 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010819 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010820 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010821 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010822 // Get the context containing declarations.
10823 Handle<Context> context(
10824 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010825 for (; i < scope_info->LocalCount(); ++i) {
10826 Handle<String> name(scope_info->LocalName(i));
10827 VariableMode mode;
10828 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010829 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010830 locals->set(i * 2 + 1, context->get(
10831 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010832 }
10833 }
10834
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010835 // Check whether this frame is positioned at return. If not top
10836 // frame or if the frame is optimized it cannot be at a return.
10837 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010838 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010839 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010840 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010841
10842 // If positioned just before return find the value to be returned and add it
10843 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010844 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010845 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010846 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010847 Address internal_frame_sp = NULL;
10848 while (!it2.done()) {
10849 if (it2.frame()->is_internal()) {
10850 internal_frame_sp = it2.frame()->sp();
10851 } else {
10852 if (it2.frame()->is_java_script()) {
10853 if (it2.frame()->id() == it.frame()->id()) {
10854 // The internal frame just before the JavaScript frame contains the
10855 // value to return on top. A debug break at return will create an
10856 // internal frame to store the return value (eax/rax/r0) before
10857 // entering the debug break exit frame.
10858 if (internal_frame_sp != NULL) {
10859 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010860 Handle<Object>(Memory::Object_at(internal_frame_sp),
10861 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010862 break;
10863 }
10864 }
10865 }
10866
10867 // Indicate that the previous frame was not an internal frame.
10868 internal_frame_sp = NULL;
10869 }
10870 it2.Advance();
10871 }
10872 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873
10874 // Now advance to the arguments adapter frame (if any). It contains all
10875 // the provided parameters whereas the function frame always have the number
10876 // of arguments matching the functions parameters. The rest of the
10877 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010878 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010879 it.AdvanceToArgumentsFrame();
10880 frame_inspector.SetArgumentsFrame(it.frame());
10881 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010882
10883 // Find the number of arguments to fill. At least fill the number of
10884 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010885 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010886 if (argument_count < frame_inspector.GetParametersCount()) {
10887 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010888 }
10889
10890 // Calculate the size of the result.
10891 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010892 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010893 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010894 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010895
10896 // Add the frame id.
10897 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10898
10899 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010900 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010901
10902 // Add the arguments count.
10903 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10904
10905 // Add the locals count
10906 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010907 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010908
10909 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010910 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010911 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10912 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010913 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010914 }
10915
10916 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010917 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010918
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010919 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010920 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010921
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010922 // Add flags to indicate information on whether this frame is
10923 // bit 0: invoked in the debugger context.
10924 // bit 1: optimized frame.
10925 // bit 2: inlined in optimized frame
10926 int flags = 0;
10927 if (*save->context() == *isolate->debug()->debug_context()) {
10928 flags |= 1 << 0;
10929 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010930 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010931 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010932 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010933 }
10934 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010935
10936 // Fill the dynamic part.
10937 int details_index = kFrameDetailsFirstDynamicIndex;
10938
10939 // Add arguments name and value.
10940 for (int i = 0; i < argument_count; i++) {
10941 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010942 if (i < scope_info->ParameterCount()) {
10943 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010944 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010945 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010946 }
10947
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010948 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010949 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010950 // Get the value from the stack.
10951 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010952 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010953 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010954 }
10955 }
10956
10957 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010958 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959 details->set(details_index++, locals->get(i));
10960 }
10961
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010962 // Add the value being returned.
10963 if (at_return) {
10964 details->set(details_index++, *return_value);
10965 }
10966
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010967 // Add the receiver (same as in function frame).
10968 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10969 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010970 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010971 if (!receiver->IsJSObject() &&
10972 shared->is_classic_mode() &&
10973 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010974 // If the receiver is not a JSObject and the function is not a
10975 // builtin or strict-mode we have hit an optimization where a
10976 // value object is not converted into a wrapped JS objects. To
10977 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010978 // by creating correct wrapper object based on the calling frame's
10979 // global context.
10980 it.Advance();
10981 Handle<Context> calling_frames_global_context(
10982 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010983 receiver =
10984 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010985 }
10986 details->set(kFrameDetailsReceiverIndex, *receiver);
10987
10988 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010989 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010990}
10991
10992
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010993// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010994static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010995 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010996 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010997 Handle<Context> context,
10998 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010999 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011000 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11001 VariableMode mode;
11002 InitializationFlag init_flag;
11003 int context_index = scope_info->ContextSlotIndex(
11004 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011005
whesse@chromium.org7b260152011-06-20 15:33:18 +000011006 RETURN_IF_EMPTY_HANDLE_VALUE(
11007 isolate,
11008 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011009 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011010 Handle<Object>(context->get(context_index), isolate),
11011 NONE,
11012 kNonStrictMode),
11013 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011014 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011015
11016 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011017}
11018
11019
11020// Create a plain JSObject which materializes the local scope for the specified
11021// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011022static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011023 Isolate* isolate,
11024 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011025 FrameInspector* frame_inspector) {
11026 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011027 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011028 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011029
11030 // Allocate and initialize a JSObject with all the arguments, stack locals
11031 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011032 Handle<JSObject> local_scope =
11033 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011034
11035 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011036 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011037 Handle<Object> value(
11038 i < frame_inspector->GetParametersCount() ?
11039 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
11040
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011041 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011042 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011043 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011044 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011045 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011046 NONE,
11047 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011048 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011049 }
11050
11051 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011052 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011053 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011054 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011055 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011056 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011057 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011058 NONE,
11059 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011060 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011061 }
11062
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011063 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011064 // Third fill all context locals.
11065 Handle<Context> frame_context(Context::cast(frame->context()));
11066 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011067 if (!CopyContextLocalsToScopeObject(
11068 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011069 return Handle<JSObject>();
11070 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011071
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011072 // Finally copy any properties from the function context extension.
11073 // These will be variables introduced by eval.
11074 if (function_context->closure() == *function) {
11075 if (function_context->has_extension() &&
11076 !function_context->IsGlobalContext()) {
11077 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011078 bool threw = false;
11079 Handle<FixedArray> keys =
11080 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11081 if (threw) return Handle<JSObject>();
11082
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011083 for (int i = 0; i < keys->length(); i++) {
11084 // Names of variables introduced by eval are strings.
11085 ASSERT(keys->get(i)->IsString());
11086 Handle<String> key(String::cast(keys->get(i)));
11087 RETURN_IF_EMPTY_HANDLE_VALUE(
11088 isolate,
11089 SetProperty(local_scope,
11090 key,
11091 GetProperty(ext, key),
11092 NONE,
11093 kNonStrictMode),
11094 Handle<JSObject>());
11095 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011096 }
11097 }
11098 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011099
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011100 return local_scope;
11101}
11102
11103
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011104static Handle<JSObject> MaterializeLocalScope(
11105 Isolate* isolate,
11106 JavaScriptFrame* frame,
11107 int inlined_jsframe_index) {
11108 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11109 return MaterializeLocalScopeWithFrameInspector(isolate,
11110 frame,
11111 &frame_inspector);
11112}
11113
11114
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011115// Create a plain JSObject which materializes the closure content for the
11116// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11118 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011119 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011120
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011121 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011122 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011123
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011124 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011125 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011126 Handle<JSObject> closure_scope =
11127 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011128
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011129 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011130 if (!CopyContextLocalsToScopeObject(
11131 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011132 return Handle<JSObject>();
11133 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011134
11135 // Finally copy any properties from the function context extension. This will
11136 // be variables introduced by eval.
11137 if (context->has_extension()) {
11138 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011139 bool threw = false;
11140 Handle<FixedArray> keys =
11141 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11142 if (threw) return Handle<JSObject>();
11143
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011144 for (int i = 0; i < keys->length(); i++) {
11145 // Names of variables introduced by eval are strings.
11146 ASSERT(keys->get(i)->IsString());
11147 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011148 RETURN_IF_EMPTY_HANDLE_VALUE(
11149 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011150 SetProperty(closure_scope,
11151 key,
11152 GetProperty(ext, key),
11153 NONE,
11154 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011155 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011156 }
11157 }
11158
11159 return closure_scope;
11160}
11161
11162
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011163// Create a plain JSObject which materializes the scope for the specified
11164// catch context.
11165static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11166 Handle<Context> context) {
11167 ASSERT(context->IsCatchContext());
11168 Handle<String> name(String::cast(context->extension()));
11169 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11170 Handle<JSObject> catch_scope =
11171 isolate->factory()->NewJSObject(isolate->object_function());
11172 RETURN_IF_EMPTY_HANDLE_VALUE(
11173 isolate,
11174 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11175 Handle<JSObject>());
11176 return catch_scope;
11177}
11178
11179
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011180// Create a plain JSObject which materializes the block scope for the specified
11181// block context.
11182static Handle<JSObject> MaterializeBlockScope(
11183 Isolate* isolate,
11184 Handle<Context> context) {
11185 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011186 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011187
11188 // Allocate and initialize a JSObject with all the arguments, stack locals
11189 // heap locals and extension properties of the debugged function.
11190 Handle<JSObject> block_scope =
11191 isolate->factory()->NewJSObject(isolate->object_function());
11192
11193 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011194 if (!CopyContextLocalsToScopeObject(
11195 isolate, scope_info, context, block_scope)) {
11196 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011197 }
11198
11199 return block_scope;
11200}
11201
11202
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011203// Create a plain JSObject which materializes the module scope for the specified
11204// module context.
11205static Handle<JSObject> MaterializeModuleScope(
11206 Isolate* isolate,
11207 Handle<Context> context) {
11208 ASSERT(context->IsModuleContext());
11209 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11210
11211 // Allocate and initialize a JSObject with all the members of the debugged
11212 // module.
11213 Handle<JSObject> module_scope =
11214 isolate->factory()->NewJSObject(isolate->object_function());
11215
11216 // Fill all context locals.
11217 if (!CopyContextLocalsToScopeObject(
11218 isolate, scope_info, context, module_scope)) {
11219 return Handle<JSObject>();
11220 }
11221
11222 return module_scope;
11223}
11224
11225
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011226// Iterate over the actual scopes visible from a stack frame. The iteration
11227// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011228// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011229// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011230class ScopeIterator {
11231 public:
11232 enum ScopeType {
11233 ScopeTypeGlobal = 0,
11234 ScopeTypeLocal,
11235 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011236 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011237 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011238 ScopeTypeBlock,
11239 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011240 };
11241
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011242 ScopeIterator(Isolate* isolate,
11243 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011244 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011245 : isolate_(isolate),
11246 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011247 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011248 function_(JSFunction::cast(frame->function())),
11249 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011250 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011251
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011252 // Catch the case when the debugger stops in an internal function.
11253 Handle<SharedFunctionInfo> shared_info(function_->shared());
11254 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11255 if (shared_info->script() == isolate->heap()->undefined_value()) {
11256 while (context_->closure() == *function_) {
11257 context_ = Handle<Context>(context_->previous(), isolate_);
11258 }
11259 return;
11260 }
11261
11262 // Get the debug info (create it if it does not exist).
11263 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11264 // Return if ensuring debug info failed.
11265 return;
11266 }
11267 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11268
11269 // Find the break point where execution has stopped.
11270 BreakLocationIterator break_location_iterator(debug_info,
11271 ALL_BREAK_LOCATIONS);
11272 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11273 if (break_location_iterator.IsExit()) {
11274 // We are within the return sequence. At the momemt it is not possible to
11275 // get a source position which is consistent with the current scope chain.
11276 // Thus all nested with, catch and block contexts are skipped and we only
11277 // provide the function scope.
11278 if (scope_info->HasContext()) {
11279 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11280 } else {
11281 while (context_->closure() == *function_) {
11282 context_ = Handle<Context>(context_->previous(), isolate_);
11283 }
11284 }
11285 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11286 } else {
11287 // Reparse the code and analyze the scopes.
11288 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11289 Handle<Script> script(Script::cast(shared_info->script()));
11290 Scope* scope = NULL;
11291
11292 // Check whether we are in global, eval or function code.
11293 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11294 if (scope_info->Type() != FUNCTION_SCOPE) {
11295 // Global or eval code.
11296 CompilationInfo info(script);
11297 if (scope_info->Type() == GLOBAL_SCOPE) {
11298 info.MarkAsGlobal();
11299 } else {
11300 ASSERT(scope_info->Type() == EVAL_SCOPE);
11301 info.MarkAsEval();
11302 info.SetCallingContext(Handle<Context>(function_->context()));
11303 }
11304 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11305 scope = info.function()->scope();
11306 }
11307 } else {
11308 // Function code
11309 CompilationInfo info(shared_info);
11310 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11311 scope = info.function()->scope();
11312 }
11313 }
11314
11315 // Retrieve the scope chain for the current position.
11316 if (scope != NULL) {
11317 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11318 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11319 } else {
11320 // A failed reparse indicates that the preparser has diverged from the
11321 // parser or that the preparse data given to the initial parse has been
11322 // faulty. We fail in debug mode but in release mode we only provide the
11323 // information we get from the context chain but nothing about
11324 // completely stack allocated scopes or stack allocated locals.
11325 UNREACHABLE();
11326 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011327 }
11328 }
11329
11330 // More scopes?
11331 bool Done() { return context_.is_null(); }
11332
11333 // Move to the next scope.
11334 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011335 ScopeType scope_type = Type();
11336 if (scope_type == ScopeTypeGlobal) {
11337 // The global scope is always the last in the chain.
11338 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011339 context_ = Handle<Context>();
11340 return;
11341 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011342 if (nested_scope_chain_.is_empty()) {
11343 context_ = Handle<Context>(context_->previous(), isolate_);
11344 } else {
11345 if (nested_scope_chain_.last()->HasContext()) {
11346 ASSERT(context_->previous() != NULL);
11347 context_ = Handle<Context>(context_->previous(), isolate_);
11348 }
11349 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011350 }
11351 }
11352
11353 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011354 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011355 if (!nested_scope_chain_.is_empty()) {
11356 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11357 switch (scope_info->Type()) {
11358 case FUNCTION_SCOPE:
11359 ASSERT(context_->IsFunctionContext() ||
11360 !scope_info->HasContext());
11361 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011362 case MODULE_SCOPE:
11363 ASSERT(context_->IsModuleContext());
11364 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011365 case GLOBAL_SCOPE:
11366 ASSERT(context_->IsGlobalContext());
11367 return ScopeTypeGlobal;
11368 case WITH_SCOPE:
11369 ASSERT(context_->IsWithContext());
11370 return ScopeTypeWith;
11371 case CATCH_SCOPE:
11372 ASSERT(context_->IsCatchContext());
11373 return ScopeTypeCatch;
11374 case BLOCK_SCOPE:
11375 ASSERT(!scope_info->HasContext() ||
11376 context_->IsBlockContext());
11377 return ScopeTypeBlock;
11378 case EVAL_SCOPE:
11379 UNREACHABLE();
11380 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011381 }
11382 if (context_->IsGlobalContext()) {
11383 ASSERT(context_->global()->IsGlobalObject());
11384 return ScopeTypeGlobal;
11385 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011386 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011387 return ScopeTypeClosure;
11388 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011389 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011390 return ScopeTypeCatch;
11391 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011392 if (context_->IsBlockContext()) {
11393 return ScopeTypeBlock;
11394 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011395 if (context_->IsModuleContext()) {
11396 return ScopeTypeModule;
11397 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011398 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011399 return ScopeTypeWith;
11400 }
11401
11402 // Return the JavaScript object with the content of the current scope.
11403 Handle<JSObject> ScopeObject() {
11404 switch (Type()) {
11405 case ScopeIterator::ScopeTypeGlobal:
11406 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011407 case ScopeIterator::ScopeTypeLocal:
11408 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011409 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011410 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011411 case ScopeIterator::ScopeTypeWith:
11412 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011413 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11414 case ScopeIterator::ScopeTypeCatch:
11415 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011416 case ScopeIterator::ScopeTypeClosure:
11417 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011418 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011419 case ScopeIterator::ScopeTypeBlock:
11420 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011421 case ScopeIterator::ScopeTypeModule:
11422 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011423 }
11424 UNREACHABLE();
11425 return Handle<JSObject>();
11426 }
11427
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011428 Handle<ScopeInfo> CurrentScopeInfo() {
11429 if (!nested_scope_chain_.is_empty()) {
11430 return nested_scope_chain_.last();
11431 } else if (context_->IsBlockContext()) {
11432 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11433 } else if (context_->IsFunctionContext()) {
11434 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11435 }
11436 return Handle<ScopeInfo>::null();
11437 }
11438
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011439 // Return the context for this scope. For the local context there might not
11440 // be an actual context.
11441 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011442 if (Type() == ScopeTypeGlobal ||
11443 nested_scope_chain_.is_empty()) {
11444 return context_;
11445 } else if (nested_scope_chain_.last()->HasContext()) {
11446 return context_;
11447 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011448 return Handle<Context>();
11449 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011450 }
11451
11452#ifdef DEBUG
11453 // Debug print of the content of the current scope.
11454 void DebugPrint() {
11455 switch (Type()) {
11456 case ScopeIterator::ScopeTypeGlobal:
11457 PrintF("Global:\n");
11458 CurrentContext()->Print();
11459 break;
11460
11461 case ScopeIterator::ScopeTypeLocal: {
11462 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011463 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011464 if (!CurrentContext().is_null()) {
11465 CurrentContext()->Print();
11466 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011467 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011468 if (extension->IsJSContextExtensionObject()) {
11469 extension->Print();
11470 }
11471 }
11472 }
11473 break;
11474 }
11475
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011476 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011477 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011478 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011479 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011480
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011481 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011482 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011483 CurrentContext()->extension()->Print();
11484 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011485 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011486
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011487 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011488 PrintF("Closure:\n");
11489 CurrentContext()->Print();
11490 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011491 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011492 if (extension->IsJSContextExtensionObject()) {
11493 extension->Print();
11494 }
11495 }
11496 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011497
11498 default:
11499 UNREACHABLE();
11500 }
11501 PrintF("\n");
11502 }
11503#endif
11504
11505 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011506 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011507 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011508 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011509 Handle<JSFunction> function_;
11510 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011511 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011512
11513 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11514};
11515
11516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011517RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011518 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011519 ASSERT(args.length() == 2);
11520
11521 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011522 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011523 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11524 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011525 if (!maybe_check->ToObject(&check)) return maybe_check;
11526 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011527 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011528
11529 // Get the frame where the debugging is performed.
11530 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011531 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011532 JavaScriptFrame* frame = it.frame();
11533
11534 // Count the visible scopes.
11535 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011536 for (ScopeIterator it(isolate, frame, 0);
11537 !it.Done();
11538 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011539 n++;
11540 }
11541
11542 return Smi::FromInt(n);
11543}
11544
11545
11546static const int kScopeDetailsTypeIndex = 0;
11547static const int kScopeDetailsObjectIndex = 1;
11548static const int kScopeDetailsSize = 2;
11549
11550// Return an array with scope details
11551// args[0]: number: break id
11552// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011553// args[2]: number: inlined frame index
11554// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011555//
11556// The array returned contains the following information:
11557// 0: Scope type
11558// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011559RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011560 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011561 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011562
11563 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011564 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011565 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11566 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011567 if (!maybe_check->ToObject(&check)) return maybe_check;
11568 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011569 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011570 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011571 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011572
11573 // Get the frame where the debugging is performed.
11574 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011575 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011576 JavaScriptFrame* frame = frame_it.frame();
11577
11578 // Find the requested scope.
11579 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011580 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011581 for (; !it.Done() && n < index; it.Next()) {
11582 n++;
11583 }
11584 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011585 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011586 }
11587
11588 // Calculate the size of the result.
11589 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011591
11592 // Fill in scope details.
11593 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011594 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011595 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011596 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011597
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011598 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011599}
11600
11601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011602RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011603 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011604 ASSERT(args.length() == 0);
11605
11606#ifdef DEBUG
11607 // Print the scopes for the top frame.
11608 StackFrameLocator locator;
11609 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011610 for (ScopeIterator it(isolate, frame, 0);
11611 !it.Done();
11612 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011613 it.DebugPrint();
11614 }
11615#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011616 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011617}
11618
11619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011620RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011622 ASSERT(args.length() == 1);
11623
11624 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011625 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011626 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11627 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011628 if (!maybe_result->ToObject(&result)) return maybe_result;
11629 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011630
11631 // Count all archived V8 threads.
11632 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011633 for (ThreadState* thread =
11634 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011635 thread != NULL;
11636 thread = thread->Next()) {
11637 n++;
11638 }
11639
11640 // Total number of threads is current thread and archived threads.
11641 return Smi::FromInt(n + 1);
11642}
11643
11644
11645static const int kThreadDetailsCurrentThreadIndex = 0;
11646static const int kThreadDetailsThreadIdIndex = 1;
11647static const int kThreadDetailsSize = 2;
11648
11649// Return an array with thread details
11650// args[0]: number: break id
11651// args[1]: number: thread index
11652//
11653// The array returned contains the following information:
11654// 0: Is current thread?
11655// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011656RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011657 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011658 ASSERT(args.length() == 2);
11659
11660 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011661 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011662 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11663 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011664 if (!maybe_check->ToObject(&check)) return maybe_check;
11665 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011666 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11667
11668 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011669 Handle<FixedArray> details =
11670 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011671
11672 // Thread index 0 is current thread.
11673 if (index == 0) {
11674 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011675 details->set(kThreadDetailsCurrentThreadIndex,
11676 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011677 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011678 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011679 } else {
11680 // Find the thread with the requested index.
11681 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011682 ThreadState* thread =
11683 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011684 while (index != n && thread != NULL) {
11685 thread = thread->Next();
11686 n++;
11687 }
11688 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011689 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011690 }
11691
11692 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011693 details->set(kThreadDetailsCurrentThreadIndex,
11694 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011695 details->set(kThreadDetailsThreadIdIndex,
11696 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011697 }
11698
11699 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011700 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011701}
11702
11703
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011704// Sets the disable break state
11705// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011706RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011707 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011708 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011709 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011710 isolate->debug()->set_disable_break(disable_break);
11711 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011712}
11713
11714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011716 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011717 ASSERT(args.length() == 1);
11718
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011719 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011720 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011721 // Find the number of break points
11722 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011723 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011724 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011725 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011726 Handle<FixedArray>::cast(break_locations));
11727}
11728
11729
11730// Set a break point in a function
11731// args[0]: function
11732// args[1]: number: break source position (within the function source)
11733// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011734RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011735 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011736 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011737 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011738 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011739 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11740 RUNTIME_ASSERT(source_position >= 0);
11741 Handle<Object> break_point_object_arg = args.at<Object>(2);
11742
11743 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011744 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11745 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011746
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011747 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011748}
11749
11750
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011751Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11752 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011753 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011754 // Iterate the heap looking for SharedFunctionInfo generated from the
11755 // script. The inner most SharedFunctionInfo containing the source position
11756 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011757 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011758 // which is found is not compiled it is compiled and the heap is iterated
11759 // again as the compilation might create inner functions from the newly
11760 // compiled function and the actual requested break point might be in one of
11761 // these functions.
11762 bool done = false;
11763 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011764 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011765 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011766 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011767 { // Extra scope for iterator and no-allocation.
11768 isolate->heap()->EnsureHeapIsIterable();
11769 AssertNoAllocation no_alloc_during_heap_iteration;
11770 HeapIterator iterator;
11771 for (HeapObject* obj = iterator.next();
11772 obj != NULL; obj = iterator.next()) {
11773 if (obj->IsSharedFunctionInfo()) {
11774 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11775 if (shared->script() == *script) {
11776 // If the SharedFunctionInfo found has the requested script data and
11777 // contains the source position it is a candidate.
11778 int start_position = shared->function_token_position();
11779 if (start_position == RelocInfo::kNoPosition) {
11780 start_position = shared->start_position();
11781 }
11782 if (start_position <= position &&
11783 position <= shared->end_position()) {
11784 // If there is no candidate or this function is within the current
11785 // candidate this is the new candidate.
11786 if (target.is_null()) {
11787 target_start_position = start_position;
11788 target = shared;
11789 } else {
11790 if (target_start_position == start_position &&
11791 shared->end_position() == target->end_position()) {
11792 // If a top-level function contain only one function
11793 // declartion the source for the top-level and the
11794 // function is the same. In that case prefer the non
11795 // top-level function.
11796 if (!shared->is_toplevel()) {
11797 target_start_position = start_position;
11798 target = shared;
11799 }
11800 } else if (target_start_position <= start_position &&
11801 shared->end_position() <= target->end_position()) {
11802 // This containment check includes equality as a function
11803 // inside a top-level function can share either start or end
11804 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011805 target_start_position = start_position;
11806 target = shared;
11807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011808 }
11809 }
11810 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011811 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011812 } // End for loop.
11813 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011814
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011815 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011816 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011817 }
11818
11819 // If the candidate found is compiled we are done. NOTE: when lazy
11820 // compilation of inner functions is introduced some additional checking
11821 // needs to be done here to compile inner functions.
11822 done = target->is_compiled();
11823 if (!done) {
11824 // If the candidate is not compiled compile it to reveal any inner
11825 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011826 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011827 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011828 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011829
11830 return *target;
11831}
11832
11833
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011834// Changes the state of a break point in a script and returns source position
11835// where break point was set. NOTE: Regarding performance see the NOTE for
11836// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011837// args[0]: script to set break point in
11838// args[1]: number: break source position (within the script source)
11839// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011840RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011841 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011842 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011843 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011844 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11845 RUNTIME_ASSERT(source_position >= 0);
11846 Handle<Object> break_point_object_arg = args.at<Object>(2);
11847
11848 // Get the script from the script wrapper.
11849 RUNTIME_ASSERT(wrapper->value()->IsScript());
11850 Handle<Script> script(Script::cast(wrapper->value()));
11851
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011852 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011853 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011854 if (!result->IsUndefined()) {
11855 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11856 // Find position within function. The script position might be before the
11857 // source position of the first function.
11858 int position;
11859 if (shared->start_position() > source_position) {
11860 position = 0;
11861 } else {
11862 position = source_position - shared->start_position();
11863 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011864 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011865 position += shared->start_position();
11866 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011867 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011868 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011869}
11870
11871
11872// Clear a break point
11873// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011874RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011875 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011876 ASSERT(args.length() == 1);
11877 Handle<Object> break_point_object_arg = args.at<Object>(0);
11878
11879 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011880 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011882 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883}
11884
11885
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011886// Change the state of break on exceptions.
11887// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11888// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011889RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011890 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011891 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011892 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011893 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011894
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011895 // If the number doesn't match an enum value, the ChangeBreakOnException
11896 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011897 ExceptionBreakType type =
11898 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011899 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011900 isolate->debug()->ChangeBreakOnException(type, enable);
11901 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011902}
11903
11904
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011905// Returns the state of break on exceptions
11906// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011907RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011908 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011909 ASSERT(args.length() == 1);
11910 RUNTIME_ASSERT(args[0]->IsNumber());
11911
11912 ExceptionBreakType type =
11913 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011914 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011915 return Smi::FromInt(result);
11916}
11917
11918
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011919// Prepare for stepping
11920// args[0]: break id for checking execution state
11921// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011922// args[2]: number of times to perform the step, for step out it is the number
11923// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011924RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011925 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011926 ASSERT(args.length() == 3);
11927 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011928 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011929 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11930 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011931 if (!maybe_check->ToObject(&check)) return maybe_check;
11932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011933 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011934 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011935 }
11936
11937 // Get the step action and check validity.
11938 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11939 if (step_action != StepIn &&
11940 step_action != StepNext &&
11941 step_action != StepOut &&
11942 step_action != StepInMin &&
11943 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011944 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011945 }
11946
11947 // Get the number of steps.
11948 int step_count = NumberToInt32(args[2]);
11949 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011950 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011951 }
11952
ager@chromium.orga1645e22009-09-09 19:27:10 +000011953 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011954 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011956 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011957 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11958 step_count);
11959 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011960}
11961
11962
11963// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011964RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011965 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011966 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011967 isolate->debug()->ClearStepping();
11968 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011969}
11970
11971
11972// Creates a copy of the with context chain. The copy of the context chain is
11973// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011974static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11975 Handle<JSFunction> function,
11976 Handle<Context> base,
11977 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011978 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011979 HandleScope scope(isolate);
11980 List<Handle<ScopeInfo> > scope_chain;
11981 List<Handle<Context> > context_chain;
11982
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011983 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011984 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11985 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11986 ASSERT(!it.Done());
11987 scope_chain.Add(it.CurrentScopeInfo());
11988 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011989 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011990
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011991 // At the end of the chain. Return the base context to link to.
11992 Handle<Context> context = base;
11993
11994 // Iteratively copy and or materialize the nested contexts.
11995 while (!scope_chain.is_empty()) {
11996 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11997 Handle<Context> current = context_chain.RemoveLast();
11998 ASSERT(!(scope_info->HasContext() & current.is_null()));
11999
12000 if (scope_info->Type() == CATCH_SCOPE) {
12001 Handle<String> name(String::cast(current->extension()));
12002 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
12003 context =
12004 isolate->factory()->NewCatchContext(function,
12005 context,
12006 name,
12007 thrown_object);
12008 } else if (scope_info->Type() == BLOCK_SCOPE) {
12009 // Materialize the contents of the block scope into a JSObject.
12010 Handle<JSObject> block_scope_object =
12011 MaterializeBlockScope(isolate, current);
12012 if (block_scope_object.is_null()) {
12013 return Handle<Context>::null();
12014 }
12015 // Allocate a new function context for the debug evaluation and set the
12016 // extension object.
12017 Handle<Context> new_context =
12018 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12019 function);
12020 new_context->set_extension(*block_scope_object);
12021 new_context->set_previous(*context);
12022 context = new_context;
12023 } else {
12024 ASSERT(scope_info->Type() == WITH_SCOPE);
12025 ASSERT(current->IsWithContext());
12026 Handle<JSObject> extension(JSObject::cast(current->extension()));
12027 context =
12028 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000012029 }
erikcorry0ad885c2011-11-21 13:51:57 +000012030 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012031
12032 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012033}
12034
12035
12036// Helper function to find or create the arguments object for
12037// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012038static Handle<Object> GetArgumentsObject(Isolate* isolate,
12039 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012040 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012041 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012042 Handle<Context> function_context) {
12043 // Try to find the value of 'arguments' to pass as parameter. If it is not
12044 // found (that is the debugged function does not reference 'arguments' and
12045 // does not support eval) then create an 'arguments' object.
12046 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012047 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012048 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012049 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012050 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012051 }
12052 }
12053
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012054 if (scope_info->HasHeapAllocatedLocals()) {
12055 VariableMode mode;
12056 InitializationFlag init_flag;
12057 index = scope_info->ContextSlotIndex(
12058 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012059 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012060 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012061 }
12062 }
12063
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012064 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
12065 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012066 Handle<JSObject> arguments =
12067 isolate->factory()->NewArgumentsObject(function, length);
12068 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012069
12070 AssertNoAllocation no_gc;
12071 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012072 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012073 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012074 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012075 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012076 return arguments;
12077}
12078
12079
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012080static const char kSourceStr[] =
12081 "(function(arguments,__source__){return eval(__source__);})";
12082
12083
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012084// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012085// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012086// extension part has all the parameters and locals of the function on the
12087// stack frame. A function which calls eval with the code to evaluate is then
12088// compiled in this context and called in this context. As this context
12089// replaces the context of the function on the stack frame a new (empty)
12090// function is created as well to be used as the closure for the context.
12091// This function and the context acts as replacements for the function on the
12092// stack frame presenting the same view of the values of parameters and
12093// local variables as if the piece of JavaScript was evaluated at the point
12094// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012095RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012096 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012097
12098 // Check the execution state and decode arguments frame and source to be
12099 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012100 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012101 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012102 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12103 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012104 if (!maybe_check_result->ToObject(&check_result)) {
12105 return maybe_check_result;
12106 }
12107 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012108 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012109 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012110 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
12111 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012112 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012113
12114 // Handle the processing of break.
12115 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012116
12117 // Get the frame where the debugging is performed.
12118 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012119 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012120 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012121 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12122 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012123 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012124
12125 // Traverse the saved contexts chain to find the active context for the
12126 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012127 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12128
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012129 SaveContext savex(isolate);
12130 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012131
12132 // Create the (empty) function replacing the function on the stack frame for
12133 // the purpose of evaluating in the context created below. It is important
12134 // that this function does not describe any parameters and local variables
12135 // in the context. If it does then this will cause problems with the lookup
12136 // in Context::Lookup, where context slots for parameters and local variables
12137 // are looked at before the extension object.
12138 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012139 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12140 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012141 go_between->set_context(function->context());
12142#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012143 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12144 ASSERT(go_between_scope_info->ParameterCount() == 0);
12145 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012146#endif
12147
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012148 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012149 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
12150 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012151 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012152
12153 // Allocate a new context for the debug evaluation and set the extension
12154 // object build.
12155 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012156 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12157 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012158 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012159 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012160 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012161 Handle<Context> function_context;
12162 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012163 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012164 function_context = Handle<Context>(frame_context->declaration_context());
12165 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012166 context = CopyNestedScopeContextChain(isolate,
12167 go_between,
12168 context,
12169 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012170 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012171
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012172 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012173 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012174 context =
12175 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012176 }
12177
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012178 // Wrap the evaluation statement in a new function compiled in the newly
12179 // created context. The function has one parameter which has to be called
12180 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012181 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012182 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012183
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012185 isolate->factory()->NewStringFromAscii(
12186 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012187
12188 // Currently, the eval code will be executed in non-strict mode,
12189 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012190 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012191 Compiler::CompileEval(function_source,
12192 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012193 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012194 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012195 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012196 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012197 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012198 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012199
12200 // Invoke the result of the compilation to get the evaluation function.
12201 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012202 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012203 Handle<Object> evaluation_function =
12204 Execution::Call(compiled_function, receiver, 0, NULL,
12205 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012206 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012207
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012208 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012209 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012210 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012211 scope_info,
12212 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012213
12214 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012215 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012216 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012217 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12218 receiver,
12219 ARRAY_SIZE(argv),
12220 argv,
12221 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012222 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012223
12224 // Skip the global proxy as it has no properties and always delegates to the
12225 // real global object.
12226 if (result->IsJSGlobalProxy()) {
12227 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12228 }
12229
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012230 return *result;
12231}
12232
12233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012234RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012235 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012236
12237 // Check the execution state and decode arguments frame and source to be
12238 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012239 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012240 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012241 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12242 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012243 if (!maybe_check_result->ToObject(&check_result)) {
12244 return maybe_check_result;
12245 }
12246 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012247 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12248 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012249 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012250
12251 // Handle the processing of break.
12252 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012253
12254 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012255 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012256 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012257 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012258 top = top->prev();
12259 }
12260 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012261 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012262 }
12263
12264 // Get the global context now set to the top context from before the
12265 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012266 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012267
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012268 bool is_global = true;
12269
12270 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012271 // Create a new with context with the additional context information between
12272 // the context of the debugged function and the eval code to be executed.
12273 context = isolate->factory()->NewWithContext(
12274 Handle<JSFunction>(context->closure()),
12275 context,
12276 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012277 is_global = false;
12278 }
12279
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012280 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012281 // Currently, the eval code will be executed in non-strict mode,
12282 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012283 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012284 Compiler::CompileEval(source,
12285 context,
12286 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012287 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012288 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012289 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012290 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012291 Handle<JSFunction>(
12292 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12293 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012294
12295 // Invoke the result of the compilation to get the evaluation function.
12296 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012297 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012298 Handle<Object> result =
12299 Execution::Call(compiled_function, receiver, 0, NULL,
12300 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012301 // Clear the oneshot breakpoints so that the debugger does not step further.
12302 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012303 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012304 return *result;
12305}
12306
12307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012308RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012309 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012310 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012311
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012312 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012313 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012314
12315 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012316 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012317 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12318 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12319 // because using
12320 // instances->set(i, *GetScriptWrapper(script))
12321 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012322 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012323 Handle<JSValue> wrapper = GetScriptWrapper(script);
12324 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012325 }
12326
12327 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012328 Handle<JSObject> result =
12329 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012330 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012331 return *result;
12332}
12333
12334
12335// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012336static int DebugReferencedBy(HeapIterator* iterator,
12337 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012338 Object* instance_filter, int max_references,
12339 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012340 JSFunction* arguments_function) {
12341 NoHandleAllocation ha;
12342 AssertNoAllocation no_alloc;
12343
12344 // Iterate the heap.
12345 int count = 0;
12346 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012347 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012348 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012349 (max_references == 0 || count < max_references)) {
12350 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012351 if (heap_obj->IsJSObject()) {
12352 // Skip context extension objects and argument arrays as these are
12353 // checked in the context of functions using them.
12354 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012355 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012356 obj->map()->constructor() == arguments_function) {
12357 continue;
12358 }
12359
12360 // Check if the JS object has a reference to the object looked for.
12361 if (obj->ReferencesObject(target)) {
12362 // Check instance filter if supplied. This is normally used to avoid
12363 // references from mirror objects (see Runtime_IsInPrototypeChain).
12364 if (!instance_filter->IsUndefined()) {
12365 Object* V = obj;
12366 while (true) {
12367 Object* prototype = V->GetPrototype();
12368 if (prototype->IsNull()) {
12369 break;
12370 }
12371 if (instance_filter == prototype) {
12372 obj = NULL; // Don't add this object.
12373 break;
12374 }
12375 V = prototype;
12376 }
12377 }
12378
12379 if (obj != NULL) {
12380 // Valid reference found add to instance array if supplied an update
12381 // count.
12382 if (instances != NULL && count < instances_size) {
12383 instances->set(count, obj);
12384 }
12385 last = obj;
12386 count++;
12387 }
12388 }
12389 }
12390 }
12391
12392 // Check for circular reference only. This can happen when the object is only
12393 // referenced from mirrors and has a circular reference in which case the
12394 // object is not really alive and would have been garbage collected if not
12395 // referenced from the mirror.
12396 if (count == 1 && last == target) {
12397 count = 0;
12398 }
12399
12400 // Return the number of referencing objects found.
12401 return count;
12402}
12403
12404
12405// Scan the heap for objects with direct references to an object
12406// args[0]: the object to find references to
12407// args[1]: constructor function for instances to exclude (Mirror)
12408// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012409RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012410 ASSERT(args.length() == 3);
12411
12412 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012413 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12414 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012415 // The heap iterator reserves the right to do a GC to make the heap iterable.
12416 // Due to the GC above we know it won't need to do that, but it seems cleaner
12417 // to get the heap iterator constructed before we start having unprotected
12418 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012419
12420 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012421 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012422 Object* instance_filter = args[1];
12423 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12424 instance_filter->IsJSObject());
12425 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12426 RUNTIME_ASSERT(max_references >= 0);
12427
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012428
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012429 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012430 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012431 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012432 JSFunction* arguments_function =
12433 JSFunction::cast(arguments_boilerplate->map()->constructor());
12434
12435 // Get the number of referencing objects.
12436 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012437 HeapIterator heap_iterator;
12438 count = DebugReferencedBy(&heap_iterator,
12439 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012440 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012441
12442 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012443 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012444 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012445 if (!maybe_object->ToObject(&object)) return maybe_object;
12446 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012447 FixedArray* instances = FixedArray::cast(object);
12448
12449 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012450 // AllocateFixedArray above does not make the heap non-iterable.
12451 ASSERT(HEAP->IsHeapIterable());
12452 HeapIterator heap_iterator2;
12453 count = DebugReferencedBy(&heap_iterator2,
12454 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012455 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012456
12457 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012458 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012459 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012460 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012461 if (!maybe_result->ToObject(&result)) return maybe_result;
12462 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012463}
12464
12465
12466// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012467static int DebugConstructedBy(HeapIterator* iterator,
12468 JSFunction* constructor,
12469 int max_references,
12470 FixedArray* instances,
12471 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012472 AssertNoAllocation no_alloc;
12473
12474 // Iterate the heap.
12475 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012476 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012477 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012478 (max_references == 0 || count < max_references)) {
12479 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012480 if (heap_obj->IsJSObject()) {
12481 JSObject* obj = JSObject::cast(heap_obj);
12482 if (obj->map()->constructor() == constructor) {
12483 // Valid reference found add to instance array if supplied an update
12484 // count.
12485 if (instances != NULL && count < instances_size) {
12486 instances->set(count, obj);
12487 }
12488 count++;
12489 }
12490 }
12491 }
12492
12493 // Return the number of referencing objects found.
12494 return count;
12495}
12496
12497
12498// Scan the heap for objects constructed by a specific function.
12499// args[0]: the constructor to find instances of
12500// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012501RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012502 ASSERT(args.length() == 2);
12503
12504 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012505 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12506 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012507
12508 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012509 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012510 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12511 RUNTIME_ASSERT(max_references >= 0);
12512
12513 // Get the number of referencing objects.
12514 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012515 HeapIterator heap_iterator;
12516 count = DebugConstructedBy(&heap_iterator,
12517 constructor,
12518 max_references,
12519 NULL,
12520 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012521
12522 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012523 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012524 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012525 if (!maybe_object->ToObject(&object)) return maybe_object;
12526 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012527 FixedArray* instances = FixedArray::cast(object);
12528
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012529 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012530 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012531 HeapIterator heap_iterator2;
12532 count = DebugConstructedBy(&heap_iterator2,
12533 constructor,
12534 max_references,
12535 instances,
12536 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012537
12538 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012539 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012540 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12541 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012542 if (!maybe_result->ToObject(&result)) return maybe_result;
12543 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012544 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012545}
12546
12547
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012548// Find the effective prototype object as returned by __proto__.
12549// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012550RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012551 ASSERT(args.length() == 1);
12552
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012553 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012554
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012555 // Use the __proto__ accessor.
12556 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012557}
12558
12559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012560RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012561 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012562 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012563 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012564}
12565
12566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012567RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012568#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012569 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012570 ASSERT(args.length() == 1);
12571 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012572 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012573 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012574 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012575 return Failure::Exception();
12576 }
12577 func->code()->PrintLn();
12578#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012579 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012580}
ager@chromium.org9085a012009-05-11 19:22:57 +000012581
12582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012583RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012584#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012585 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012586 ASSERT(args.length() == 1);
12587 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012588 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012589 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012590 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012591 return Failure::Exception();
12592 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012593 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012594#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012595 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012596}
12597
12598
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012599RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012600 NoHandleAllocation ha;
12601 ASSERT(args.length() == 1);
12602
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012603 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012604 return f->shared()->inferred_name();
12605}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012606
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012607
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012608static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12609 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012610 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012611 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012612 int counter = 0;
12613 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012614 for (HeapObject* obj = iterator->next();
12615 obj != NULL;
12616 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012617 ASSERT(obj != NULL);
12618 if (!obj->IsSharedFunctionInfo()) {
12619 continue;
12620 }
12621 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12622 if (shared->script() != script) {
12623 continue;
12624 }
12625 if (counter < buffer_size) {
12626 buffer->set(counter, shared);
12627 }
12628 counter++;
12629 }
12630 return counter;
12631}
12632
12633// For a script finds all SharedFunctionInfo's in the heap that points
12634// to this script. Returns JSArray of SharedFunctionInfo wrapped
12635// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012636RUNTIME_FUNCTION(MaybeObject*,
12637 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012638 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012639 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012640 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012641
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012642
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012643 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12644
12645 const int kBufferSize = 32;
12646
12647 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012648 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012649 int number;
12650 {
12651 isolate->heap()->EnsureHeapIsIterable();
12652 AssertNoAllocation no_allocations;
12653 HeapIterator heap_iterator;
12654 Script* scr = *script;
12655 FixedArray* arr = *array;
12656 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12657 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012658 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012659 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012660 isolate->heap()->EnsureHeapIsIterable();
12661 AssertNoAllocation no_allocations;
12662 HeapIterator heap_iterator;
12663 Script* scr = *script;
12664 FixedArray* arr = *array;
12665 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012666 }
12667
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012668 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012669 result->set_length(Smi::FromInt(number));
12670
12671 LiveEdit::WrapSharedFunctionInfos(result);
12672
12673 return *result;
12674}
12675
12676// For a script calculates compilation information about all its functions.
12677// The script source is explicitly specified by the second argument.
12678// The source of the actual script is not used, however it is important that
12679// all generated code keeps references to this particular instance of script.
12680// Returns a JSArray of compilation infos. The array is ordered so that
12681// each function with all its descendant is always stored in a continues range
12682// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012683RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012684 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012685 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012686 CONVERT_ARG_CHECKED(JSValue, script, 0);
12687 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012688 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12689
12690 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012692 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012693 return Failure::Exception();
12694 }
12695
12696 return result;
12697}
12698
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012699// Changes the source of the script to a new_source.
12700// If old_script_name is provided (i.e. is a String), also creates a copy of
12701// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012702RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012703 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012704 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012705 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12706 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012707 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012708
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012709 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12710 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012711
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012712 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12713 new_source,
12714 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012715
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012716 if (old_script->IsScript()) {
12717 Handle<Script> script_handle(Script::cast(old_script));
12718 return *(GetScriptWrapper(script_handle));
12719 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012720 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012721 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012722}
12723
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012724
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012725RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012726 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012727 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012728 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012729 return LiveEdit::FunctionSourceUpdated(shared_info);
12730}
12731
12732
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012733// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012734RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012735 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012736 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012737 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12738 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012739
ager@chromium.orgac091b72010-05-05 07:34:42 +000012740 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012741}
12742
12743// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012744RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012745 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012746 HandleScope scope(isolate);
12747 Handle<Object> function_object(args[0], isolate);
12748 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012749
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012750 if (function_object->IsJSValue()) {
12751 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12752 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012753 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12754 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012755 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012756 }
12757
12758 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12759 } else {
12760 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12761 // and we check it in this function.
12762 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012763
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012764 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012765}
12766
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012767
12768// In a code of a parent function replaces original function as embedded object
12769// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012770RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012771 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012772 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012773
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012774 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12775 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12776 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012777
12778 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12779 subst_wrapper);
12780
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012781 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012782}
12783
12784
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012785// Updates positions of a shared function info (first parameter) according
12786// to script source change. Text change is described in second parameter as
12787// array of groups of 3 numbers:
12788// (change_begin, change_end, change_end_new_position).
12789// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012790RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012791 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012792 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012793 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12794 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012795
ager@chromium.orgac091b72010-05-05 07:34:42 +000012796 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012797}
12798
12799
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012800// For array of SharedFunctionInfo's (each wrapped in JSValue)
12801// checks that none of them have activations on stacks (of any thread).
12802// Returns array of the same length with corresponding results of
12803// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012804RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012805 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012806 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012807 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12808 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012809
ager@chromium.org357bf652010-04-12 11:30:10 +000012810 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012811}
12812
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012813// Compares 2 strings line-by-line, then token-wise and returns diff in form
12814// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12815// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012816RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012817 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012818 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012819 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12820 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012821
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012822 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012823}
12824
12825
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012826// A testing entry. Returns statement position which is the closest to
12827// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012828RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012829 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012830 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012831 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012832 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12833
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012834 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012835
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012836 if (code->kind() != Code::FUNCTION &&
12837 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012838 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012839 }
12840
12841 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012842 int closest_pc = 0;
12843 int distance = kMaxInt;
12844 while (!it.done()) {
12845 int statement_position = static_cast<int>(it.rinfo()->data());
12846 // Check if this break point is closer that what was previously found.
12847 if (source_position <= statement_position &&
12848 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012849 closest_pc =
12850 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012851 distance = statement_position - source_position;
12852 // Check whether we can't get any closer.
12853 if (distance == 0) break;
12854 }
12855 it.next();
12856 }
12857
12858 return Smi::FromInt(closest_pc);
12859}
12860
12861
ager@chromium.org357bf652010-04-12 11:30:10 +000012862// Calls specified function with or without entering the debugger.
12863// This is used in unit tests to run code as if debugger is entered or simply
12864// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012865RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012866 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012867 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012868 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12869 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012870
12871 Handle<Object> result;
12872 bool pending_exception;
12873 {
12874 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012875 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012876 &pending_exception);
12877 } else {
12878 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012879 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012880 &pending_exception);
12881 }
12882 }
12883 if (!pending_exception) {
12884 return *result;
12885 } else {
12886 return Failure::Exception();
12887 }
12888}
12889
12890
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012891// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012892RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012893 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012894 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012895 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12896 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012897 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012898}
12899
12900
12901// Performs a GC.
12902// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012903RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012904 isolate->heap()->CollectAllGarbage(true, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012905 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012906}
12907
12908
12909// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012910RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012911 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012912 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012913 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012914 }
12915 return Smi::FromInt(usage);
12916}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012917
12918
12919// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012920RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012921#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012922 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012923#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012924 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012925#endif
12926}
12927
12928
12929// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012930RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012931#ifdef LIVE_OBJECT_LIST
12932 return LiveObjectList::Capture();
12933#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012934 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012935#endif
12936}
12937
12938
12939// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012940RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012941#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012942 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012943 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012944 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012945#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012946 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012947#endif
12948}
12949
12950
12951// Generates the response to a debugger request for a dump of the objects
12952// contained in the difference between the captured live object lists
12953// specified by id1 and id2.
12954// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12955// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012956RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012957#ifdef LIVE_OBJECT_LIST
12958 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012959 CONVERT_SMI_ARG_CHECKED(id1, 0);
12960 CONVERT_SMI_ARG_CHECKED(id2, 1);
12961 CONVERT_SMI_ARG_CHECKED(start, 2);
12962 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012963 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012964 EnterDebugger enter_debugger;
12965 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12966#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012967 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012968#endif
12969}
12970
12971
12972// Gets the specified object as requested by the debugger.
12973// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012974RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012975#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012976 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012977 Object* result = LiveObjectList::GetObj(obj_id);
12978 return result;
12979#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012980 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012981#endif
12982}
12983
12984
12985// Gets the obj id for the specified address if valid.
12986// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012987RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012988#ifdef LIVE_OBJECT_LIST
12989 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012990 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012991 Object* result = LiveObjectList::GetObjId(address);
12992 return result;
12993#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012994 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012995#endif
12996}
12997
12998
12999// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013000RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013001#ifdef LIVE_OBJECT_LIST
13002 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013003 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013004 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
13005 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
13006 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
13007 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013008 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013009
13010 Handle<JSObject> instance_filter;
13011 if (args[1]->IsJSObject()) {
13012 instance_filter = args.at<JSObject>(1);
13013 }
13014 bool verbose = false;
13015 if (args[2]->IsBoolean()) {
13016 verbose = args[2]->IsTrue();
13017 }
13018 int start = 0;
13019 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013020 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013021 }
13022 int limit = Smi::kMaxValue;
13023 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013024 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013025 }
13026
13027 return LiveObjectList::GetObjRetainers(obj_id,
13028 instance_filter,
13029 verbose,
13030 start,
13031 limit,
13032 filter_obj);
13033#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013034 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013035#endif
13036}
13037
13038
13039// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013040RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013041#ifdef LIVE_OBJECT_LIST
13042 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013043 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13044 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013045 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13046
13047 Handle<JSObject> instance_filter;
13048 if (args[2]->IsJSObject()) {
13049 instance_filter = args.at<JSObject>(2);
13050 }
13051
13052 Object* result =
13053 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13054 return result;
13055#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013056 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013057#endif
13058}
13059
13060
13061// Generates the response to a debugger request for a list of all
13062// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013063RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013064#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013065 CONVERT_SMI_ARG_CHECKED(start, 0);
13066 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013067 return LiveObjectList::Info(start, count);
13068#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013069 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013070#endif
13071}
13072
13073
13074// Gets a dump of the specified object as requested by the debugger.
13075// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013076RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013077#ifdef LIVE_OBJECT_LIST
13078 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013079 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013080 Object* result = LiveObjectList::PrintObj(obj_id);
13081 return result;
13082#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013083 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013084#endif
13085}
13086
13087
13088// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013089RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013090#ifdef LIVE_OBJECT_LIST
13091 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013092 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013093#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013094 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013095#endif
13096}
13097
13098
13099// Generates the response to a debugger request for a summary of the types
13100// of objects in the difference between the captured live object lists
13101// specified by id1 and id2.
13102// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13103// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013104RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013105#ifdef LIVE_OBJECT_LIST
13106 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013107 CONVERT_SMI_ARG_CHECKED(id1, 0);
13108 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013109 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013110
13111 EnterDebugger enter_debugger;
13112 return LiveObjectList::Summarize(id1, id2, filter_obj);
13113#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013114 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013115#endif
13116}
13117
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013118#endif // ENABLE_DEBUGGER_SUPPORT
13119
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013121RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013122 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013123 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013124 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013125}
13126
13127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013128RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013129 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013130 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013131 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013132}
13133
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013134
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013135// Finds the script object from the script data. NOTE: This operation uses
13136// heap traversal to find the function generated for the source position
13137// for the requested break point. For lazily compiled functions several heap
13138// traversals might be required rendering this operation as a rather slow
13139// operation. However for setting break points which is normally done through
13140// some kind of user interaction the performance is not crucial.
13141static Handle<Object> Runtime_GetScriptFromScriptName(
13142 Handle<String> script_name) {
13143 // Scan the heap for Script objects to find the script with the requested
13144 // script data.
13145 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013146 script_name->GetHeap()->EnsureHeapIsIterable();
13147 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013148 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013149 HeapObject* obj = NULL;
13150 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013151 // If a script is found check if it has the script data requested.
13152 if (obj->IsScript()) {
13153 if (Script::cast(obj)->name()->IsString()) {
13154 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13155 script = Handle<Script>(Script::cast(obj));
13156 }
13157 }
13158 }
13159 }
13160
13161 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013162 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013163
13164 // Return the script found.
13165 return GetScriptWrapper(script);
13166}
13167
13168
13169// Get the script object from script data. NOTE: Regarding performance
13170// see the NOTE for GetScriptFromScriptData.
13171// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013172RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013173 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013174
13175 ASSERT(args.length() == 1);
13176
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013177 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013178
13179 // Find the requested script.
13180 Handle<Object> result =
13181 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13182 return *result;
13183}
13184
13185
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013186// Determines whether the given stack frame should be displayed in
13187// a stack trace. The caller is the error constructor that asked
13188// for the stack trace to be collected. The first time a construct
13189// call to this function is encountered it is skipped. The seen_caller
13190// in/out parameter is used to remember if the caller has been seen
13191// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013192static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13193 Object* caller,
13194 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013195 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013196 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013197 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013198 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013199 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13200 Object* raw_fun = frame->function();
13201 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013202 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013203 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013204 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013205 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013206 *seen_caller = true;
13207 return false;
13208 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013209 // Skip all frames until we've seen the caller.
13210 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013211 // Also, skip non-visible built-in functions and any call with the builtins
13212 // object as receiver, so as to not reveal either the builtins object or
13213 // an internal function.
13214 // The --builtins-in-stack-traces command line flag allows including
13215 // internal call sites in the stack trace for debugging purposes.
13216 if (!FLAG_builtins_in_stack_traces) {
13217 JSFunction* fun = JSFunction::cast(raw_fun);
13218 if (frame->receiver()->IsJSBuiltinsObject() ||
13219 (fun->IsBuiltin() && !fun->shared()->native())) {
13220 return false;
13221 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013222 }
13223 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013224}
13225
13226
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013227// Collect the raw data for a stack trace. Returns an array of 4
13228// element segments each containing a receiver, function, code and
13229// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013230RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013231 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013232 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013233 Handle<Object> caller = args.at<Object>(1);
13234 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013235
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013236 HandleScope scope(isolate);
13237 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013238
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013239 limit = Max(limit, 0); // Ensure that limit is not negative.
13240 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013241 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013242 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013243
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013244 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013245 // If the caller parameter is a function we skip frames until we're
13246 // under it before starting to collect.
13247 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013248 int cursor = 0;
13249 int frames_seen = 0;
13250 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013251 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013252 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013253 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013254 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013255 // Set initial size to the maximum inlining level + 1 for the outermost
13256 // function.
13257 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013258 frame->Summarize(&frames);
13259 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013260 if (cursor + 4 > elements->length()) {
13261 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13262 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013263 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013264 for (int i = 0; i < cursor; i++) {
13265 new_elements->set(i, elements->get(i));
13266 }
13267 elements = new_elements;
13268 }
13269 ASSERT(cursor + 4 <= elements->length());
13270
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013271 Handle<Object> recv = frames[i].receiver();
13272 Handle<JSFunction> fun = frames[i].function();
13273 Handle<Code> code = frames[i].code();
13274 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013275 elements->set(cursor++, *recv);
13276 elements->set(cursor++, *fun);
13277 elements->set(cursor++, *code);
13278 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013279 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013280 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013281 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013282 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013283 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013284 // Capture and attach a more detailed stack trace if necessary.
13285 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013286 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013287 return *result;
13288}
13289
13290
ager@chromium.org3811b432009-10-28 14:53:37 +000013291// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013292RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013293 ASSERT_EQ(args.length(), 0);
13294
13295 NoHandleAllocation ha;
13296
13297 const char* version_string = v8::V8::GetVersion();
13298
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013299 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13300 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013301}
13302
13303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013304RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013305 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013306 OS::PrintError("abort: %s\n",
13307 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013308 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013309 OS::Abort();
13310 UNREACHABLE();
13311 return NULL;
13312}
13313
13314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013315RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013316 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013317 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013318 Object* key = args[1];
13319
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013320 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013321 Object* o = cache->get(finger_index);
13322 if (o == key) {
13323 // The fastest case: hit the same place again.
13324 return cache->get(finger_index + 1);
13325 }
13326
13327 for (int i = finger_index - 2;
13328 i >= JSFunctionResultCache::kEntriesIndex;
13329 i -= 2) {
13330 o = cache->get(i);
13331 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013332 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013333 return cache->get(i + 1);
13334 }
13335 }
13336
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013337 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013338 ASSERT(size <= cache->length());
13339
13340 for (int i = size - 2; i > finger_index; i -= 2) {
13341 o = cache->get(i);
13342 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013343 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013344 return cache->get(i + 1);
13345 }
13346 }
13347
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013348 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013349 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013350
13351 Handle<JSFunctionResultCache> cache_handle(cache);
13352 Handle<Object> key_handle(key);
13353 Handle<Object> value;
13354 {
13355 Handle<JSFunction> factory(JSFunction::cast(
13356 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13357 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013358 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013359 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013360 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013361 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013362 value = Execution::Call(factory,
13363 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013364 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013365 argv,
13366 &pending_exception);
13367 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013368 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013369
13370#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013371 if (FLAG_verify_heap) {
13372 cache_handle->JSFunctionResultCacheVerify();
13373 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013374#endif
13375
13376 // Function invocation may have cleared the cache. Reread all the data.
13377 finger_index = cache_handle->finger_index();
13378 size = cache_handle->size();
13379
13380 // If we have spare room, put new data into it, otherwise evict post finger
13381 // entry which is likely to be the least recently used.
13382 int index = -1;
13383 if (size < cache_handle->length()) {
13384 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13385 index = size;
13386 } else {
13387 index = finger_index + JSFunctionResultCache::kEntrySize;
13388 if (index == cache_handle->length()) {
13389 index = JSFunctionResultCache::kEntriesIndex;
13390 }
13391 }
13392
13393 ASSERT(index % 2 == 0);
13394 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13395 ASSERT(index < cache_handle->length());
13396
13397 cache_handle->set(index, *key_handle);
13398 cache_handle->set(index + 1, *value);
13399 cache_handle->set_finger_index(index);
13400
13401#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013402 if (FLAG_verify_heap) {
13403 cache_handle->JSFunctionResultCacheVerify();
13404 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013405#endif
13406
13407 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013408}
13409
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013410
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013411RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013412 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013413 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13414 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013415 return *isolate->factory()->NewJSMessageObject(
13416 type,
13417 arguments,
13418 0,
13419 0,
13420 isolate->factory()->undefined_value(),
13421 isolate->factory()->undefined_value(),
13422 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013423}
13424
13425
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013426RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013427 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013428 return message->type();
13429}
13430
13431
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013432RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013433 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013434 return message->arguments();
13435}
13436
13437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013438RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013439 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013440 return Smi::FromInt(message->start_position());
13441}
13442
13443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013444RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013445 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013446 return message->script();
13447}
13448
13449
kasper.lund44510672008-07-25 07:37:58 +000013450#ifdef DEBUG
13451// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13452// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013453RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013454 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013455 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013456#define COUNT_ENTRY(Name, argc, ressize) + 1
13457 int entry_count = 0
13458 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13459 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13460 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13461#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013462 Factory* factory = isolate->factory();
13463 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013464 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013465 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013466#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013467 { \
13468 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013469 Handle<String> name; \
13470 /* Inline runtime functions have an underscore in front of the name. */ \
13471 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013472 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013473 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13474 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013475 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013476 Vector<const char>(#Name, StrLength(#Name))); \
13477 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013478 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013479 pair_elements->set(0, *name); \
13480 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013481 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013482 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013483 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013484 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013485 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013486 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013487 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013488 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013489#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013490 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013491 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013492 return *result;
13493}
kasper.lund44510672008-07-25 07:37:58 +000013494#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013495
13496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013497RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013498 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013499 CONVERT_ARG_CHECKED(String, format, 0);
13500 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013501 String::FlatContent format_content = format->GetFlatContent();
13502 RUNTIME_ASSERT(format_content.IsAscii());
13503 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013504 LOGGER->LogRuntime(chars, elms);
13505 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013506}
13507
13508
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013509RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013510 UNREACHABLE(); // implemented as macro in the parser
13511 return NULL;
13512}
13513
13514
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013515#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13516 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013517 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013518 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13519 }
13520
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013521ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013522ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13523ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13524ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13525ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13526ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13527ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13528ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13529ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13530ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13531ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13532ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13533ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13534ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13535
13536#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13537
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013538
13539RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13540 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013541 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13542 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013543 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13544}
13545
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013546// ----------------------------------------------------------------------------
13547// Implementation of Runtime
13548
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013549#define F(name, number_of_args, result_size) \
13550 { Runtime::k##name, Runtime::RUNTIME, #name, \
13551 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013552
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013553
13554#define I(name, number_of_args, result_size) \
13555 { Runtime::kInline##name, Runtime::INLINE, \
13556 "_" #name, NULL, number_of_args, result_size },
13557
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013558static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013559 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013560 INLINE_FUNCTION_LIST(I)
13561 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013562};
13563
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013564
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013565MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13566 Object* dictionary) {
13567 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013568 ASSERT(dictionary != NULL);
13569 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13570 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013571 Object* name_symbol;
13572 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013573 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013574 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13575 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013576 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013577 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13578 String::cast(name_symbol),
13579 Smi::FromInt(i),
13580 PropertyDetails(NONE, NORMAL));
13581 if (!maybe_dictionary->ToObject(&dictionary)) {
13582 // Non-recoverable failure. Calling code must restart heap
13583 // initialization.
13584 return maybe_dictionary;
13585 }
13586 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013587 }
13588 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013589}
13590
13591
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013592const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13593 Heap* heap = name->GetHeap();
13594 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013595 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013596 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013597 int function_index = Smi::cast(smi_index)->value();
13598 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013599 }
13600 return NULL;
13601}
13602
13603
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013604const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013605 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13606}
13607
13608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013609void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013610 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013611 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013612 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013613 if (isolate->heap()->new_space()->AddFreshPage()) {
13614 return;
13615 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013616 // Try to do a garbage collection; ignore it if it fails. The C
13617 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013618 isolate->heap()->CollectGarbage(failure->allocation_space(),
13619 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013620 } else {
13621 // Handle last resort GC and make sure to allow future allocations
13622 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013623 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013624 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13625 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013626 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013627}
13628
13629
13630} } // namespace v8::internal