blob: 544b210c0b6f1520ecb2a161608fe81970cb8fd9 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 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.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
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.orgc3b37122011-11-07 10:14:12 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000119// Assert that the given argument has a valid value for a LanguageMode
120// and store it in a LanguageMode variable with the given name.
121#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
122 ASSERT(args[index]->IsSmi()); \
123 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
124 args.smi_at(index) == STRICT_MODE || \
125 args.smi_at(index) == EXTENDED_MODE); \
126 LanguageMode name = \
127 static_cast<LanguageMode>(args.smi_at(index));
128
129
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000130MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
131 JSObject* boilerplate) {
132 StackLimitCheck check(isolate);
133 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 JSObject* copy = JSObject::cast(result);
141
142 // Deep copy local properties.
143 if (copy->HasFastProperties()) {
144 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 for (int i = 0; i < properties->length(); i++) {
146 Object* value = properties->get(i);
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000155 int nof = copy->map()->inobject_properties();
156 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 Object* value = copy->InObjectPropertyAt(i);
158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000164 }
165 }
166 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 FixedArray* names = FixedArray::cast(result);
172 copy->GetLocalPropertyNames(names, 0);
173 for (int i = 0; i < names->length(); i++) {
174 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000175 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000176 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000177 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000178 // Only deep copy fields from the object literal expression.
179 // In particular, don't try to copy the length attribute of
180 // an array.
181 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000182 Object* value =
183 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000186 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000187 if (!maybe_result->ToObject(&result)) return maybe_result;
188 }
189 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000190 // Creating object copy for literals. No strict mode needed.
191 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000194 }
195 }
196 }
197
198 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000200 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000202 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000203 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000204 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000205 if (elements->map() == heap->fixed_cow_array_map()) {
206 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207#ifdef DEBUG
208 for (int i = 0; i < elements->length(); i++) {
209 ASSERT(!elements->get(i)->IsJSObject());
210 }
211#endif
212 } else {
213 for (int i = 0; i < elements->length(); i++) {
214 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000215 ASSERT(value->IsSmi() ||
216 value->IsTheHole() ||
217 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000218 if (value->IsJSObject()) {
219 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000220 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
221 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000222 if (!maybe_result->ToObject(&result)) return maybe_result;
223 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000224 elements->set(i, result);
225 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000226 }
227 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000228 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000230 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000231 NumberDictionary* element_dictionary = copy->element_dictionary();
232 int capacity = element_dictionary->Capacity();
233 for (int i = 0; i < capacity; i++) {
234 Object* k = element_dictionary->KeyAt(i);
235 if (element_dictionary->IsKey(k)) {
236 Object* value = element_dictionary->ValueAt(i);
237 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000238 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
240 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000241 if (!maybe_result->ToObject(&result)) return maybe_result;
242 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000243 element_dictionary->ValueAtPut(i, result);
244 }
245 }
246 }
247 break;
248 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000249 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000250 UNIMPLEMENTED();
251 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000252 case EXTERNAL_PIXEL_ELEMENTS:
253 case EXTERNAL_BYTE_ELEMENTS:
254 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
255 case EXTERNAL_SHORT_ELEMENTS:
256 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
257 case EXTERNAL_INT_ELEMENTS:
258 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
259 case EXTERNAL_FLOAT_ELEMENTS:
260 case EXTERNAL_DOUBLE_ELEMENTS:
261 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000262 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000263 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000264 }
265 return copy;
266}
267
268
ager@chromium.org236ad962008-09-25 09:45:57 +0000269static Handle<Map> ComputeObjectLiteralMap(
270 Handle<Context> context,
271 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000272 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000273 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 int properties_length = constant_properties->length();
275 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000276 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000277 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 for (int p = 0; p != properties_length; p += 2) {
280 Object* key = constant_properties->get(p);
281 uint32_t element_index = 0;
282 if (key->IsSymbol()) {
283 number_of_symbol_keys++;
284 } else if (key->ToArrayIndex(&element_index)) {
285 // An index key does not require space in the property backing store.
286 number_of_properties--;
287 } else {
288 // Bail out as a non-symbol non-index key makes caching impossible.
289 // ASSERT to make sure that the if condition after the loop is false.
290 ASSERT(number_of_symbol_keys != number_of_properties);
291 break;
292 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000293 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000294 // If we only have symbols and array indices among keys then we can
295 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 if ((number_of_symbol_keys == number_of_properties) &&
298 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Handle<FixedArray> keys =
301 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000302 if (number_of_symbol_keys > 0) {
303 int index = 0;
304 for (int p = 0; p < properties_length; p += 2) {
305 Object* key = constant_properties->get(p);
306 if (key->IsSymbol()) {
307 keys->set(index++, key);
308 }
309 }
310 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000312 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000313 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 }
315 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000316 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000317 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000318 Handle<Map>(context->object_function()->initial_map()),
319 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000320}
321
322
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000325 Handle<FixedArray> literals,
326 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000327
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000328
329static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000332 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 bool should_have_fast_elements,
334 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000335 // Get the global context from the literals array. This is the
336 // context in which the function was created and we use the object
337 // function from this context to create the object literal. We do
338 // not use the object function from the current global context
339 // because this might be the object function from another context
340 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000341 Handle<Context> context =
342 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000344 // In case we have function literals, we want the object to be in
345 // slow properties mode for now. We don't go in the map cache because
346 // maps with constant functions can't be shared if the functions are
347 // not the same (which is the common case).
348 bool is_result_from_cache = false;
349 Handle<Map> map = has_function_literal
350 ? Handle<Map>(context->object_function()->initial_map())
351 : ComputeObjectLiteralMap(context,
352 constant_properties,
353 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000355 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000356
357 // Normalize the elements of the boilerplate to save space if needed.
358 if (!should_have_fast_elements) NormalizeElements(boilerplate);
359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 // Add the constant properties to the boilerplate.
361 int length = constant_properties->length();
362 bool should_transform =
363 !is_result_from_cache && boilerplate->HasFastProperties();
364 if (should_transform || has_function_literal) {
365 // Normalize the properties of object to avoid n^2 behavior
366 // when extending the object multiple properties. Indicate the number of
367 // properties to be added.
368 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
369 }
370
371 for (int index = 0; index < length; index +=2) {
372 Handle<Object> key(constant_properties->get(index+0), isolate);
373 Handle<Object> value(constant_properties->get(index+1), isolate);
374 if (value->IsFixedArray()) {
375 // The value contains the constant_properties of a
376 // simple object or array literal.
377 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
378 value = CreateLiteralBoilerplate(isolate, literals, array);
379 if (value.is_null()) return value;
380 }
381 Handle<Object> result;
382 uint32_t element_index = 0;
383 if (key->IsSymbol()) {
384 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
385 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000386 result = SetOwnElement(boilerplate,
387 element_index,
388 value,
389 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000390 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000391 Handle<String> name(String::cast(*key));
392 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000393 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
394 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 } else if (key->ToArrayIndex(&element_index)) {
397 // Array index (uint32).
398 result = SetOwnElement(boilerplate,
399 element_index,
400 value,
401 kNonStrictMode);
402 } else {
403 // Non-uint32 number.
404 ASSERT(key->IsNumber());
405 double num = key->Number();
406 char arr[100];
407 Vector<char> buffer(arr, ARRAY_SIZE(arr));
408 const char* str = DoubleToCString(num, buffer);
409 Handle<String> name =
410 isolate->factory()->NewStringFromAscii(CStrVector(str));
411 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
412 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 // If setting the property on the boilerplate throws an
415 // exception, the exception is converted to an empty handle in
416 // the handle based operations. In that case, we need to
417 // convert back to an exception.
418 if (result.is_null()) return result;
419 }
420
421 // Transform to fast properties if necessary. For object literals with
422 // containing function literals we defer this operation until after all
423 // computed properties have been assigned so that we can generate
424 // constant function properties.
425 if (should_transform && !has_function_literal) {
426 TransformToFastProperties(boilerplate,
427 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 }
429
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000430 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000431}
432
433
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000434static const int kSmiOnlyLiteralMinimumLength = 1024;
435
436
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000437// static
438Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 Handle<FixedArray> literals,
441 Handle<FixedArray> elements) {
442 // Create the JSArray.
443 Handle<JSFunction> constructor(
444 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000445 Handle<JSArray> object =
446 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000447
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000448 ElementsKind constant_elements_kind =
449 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
450 Handle<FixedArrayBase> constant_elements_values(
451 FixedArrayBase::cast(elements->get(1)));
452
453 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
454 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
455 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
456 constant_elements_kind > object->GetElementsKind();
457
458 if (!FLAG_smi_only_arrays &&
459 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
460 constant_elements_kind != object->GetElementsKind()) {
461 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000462 }
463
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 // If the ElementsKind of the constant values of the array literal are less
465 // specific than the ElementsKind of the boilerplate array object, change the
466 // boilerplate array object's map to reflect that kind.
467 if (allow_literal_kind_transition) {
468 Handle<Map> transitioned_array_map =
469 isolate->factory()->GetElementsTransitionMap(object,
470 constant_elements_kind);
471 object->set_map(*transitioned_array_map);
472 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000473
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000474 Handle<FixedArrayBase> copied_elements_values;
475 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 ASSERT(FLAG_smi_only_arrays);
477 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
478 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000479 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
481 constant_elements_kind == FAST_ELEMENTS);
482 const bool is_cow =
483 (constant_elements_values->map() ==
484 isolate->heap()->fixed_cow_array_map());
485 if (is_cow) {
486 copied_elements_values = constant_elements_values;
487#if DEBUG
488 Handle<FixedArray> fixed_array_values =
489 Handle<FixedArray>::cast(copied_elements_values);
490 for (int i = 0; i < fixed_array_values->length(); i++) {
491 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
492 }
493#endif
494 } else {
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(constant_elements_values);
497 Handle<FixedArray> fixed_array_values_copy =
498 isolate->factory()->CopyFixedArray(fixed_array_values);
499 copied_elements_values = fixed_array_values_copy;
500 for (int i = 0; i < fixed_array_values->length(); i++) {
501 Object* current = fixed_array_values->get(i);
502 if (current->IsFixedArray()) {
503 // The value contains the constant_properties of a
504 // simple object or array literal.
505 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
506 Handle<Object> result =
507 CreateLiteralBoilerplate(isolate, literals, fa);
508 if (result.is_null()) return result;
509 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000510 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000511 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 }
513 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000514 object->set_elements(*copied_elements_values);
515 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 return object;
517}
518
519
520static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 Handle<FixedArray> literals,
523 Handle<FixedArray> array) {
524 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000526 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 return CreateObjectLiteralBoilerplate(isolate,
529 literals,
530 elements,
531 true,
532 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000533 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return CreateObjectLiteralBoilerplate(isolate,
535 literals,
536 elements,
537 false,
538 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000540 return Runtime::CreateArrayLiteralBoilerplate(
541 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000542 default:
543 UNREACHABLE();
544 return Handle<Object>::null();
545 }
546}
547
548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000549RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000550 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000551 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000553 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000555 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
557 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000558
559 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 Handle<Object> boilerplate(literals->get(literals_index), isolate);
561 if (*boilerplate == isolate->heap()->undefined_value()) {
562 boilerplate = CreateObjectLiteralBoilerplate(isolate,
563 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000564 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 should_have_fast_elements,
566 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000567 if (boilerplate.is_null()) return Failure::Exception();
568 // Update the functions literal and return the boilerplate.
569 literals->set(literals_index, *boilerplate);
570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000572}
573
574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000575RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000577 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000579 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000581 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
583 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584
585 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 Handle<Object> boilerplate(literals->get(literals_index), isolate);
587 if (*boilerplate == isolate->heap()->undefined_value()) {
588 boilerplate = CreateObjectLiteralBoilerplate(isolate,
589 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000590 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000591 should_have_fast_elements,
592 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593 if (boilerplate.is_null()) return Failure::Exception();
594 // Update the functions literal and return the boilerplate.
595 literals->set(literals_index, *boilerplate);
596 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000598}
599
600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000601RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000603 ASSERT(args.length() == 3);
604 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000605 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000606 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
607
608 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 Handle<Object> boilerplate(literals->get(literals_index), isolate);
610 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000611 boilerplate =
612 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000613 if (boilerplate.is_null()) return Failure::Exception();
614 // Update the functions literal and return the boilerplate.
615 literals->set(literals_index, *boilerplate);
616 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000617 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000618}
619
620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000621RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000622 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000623 ASSERT(args.length() == 3);
624 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000625 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000626 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
627
628 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000629 Handle<Object> boilerplate(literals->get(literals_index), isolate);
630 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000631 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000632 boilerplate =
633 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000634 if (boilerplate.is_null()) return Failure::Exception();
635 // Update the functions literal and return the boilerplate.
636 literals->set(literals_index, *boilerplate);
637 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000638 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000640 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000641 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000643}
644
645
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000646RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
647 ASSERT(args.length() == 2);
648 Object* handler = args[0];
649 Object* prototype = args[1];
650 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000651 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000652 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
653}
654
655
lrn@chromium.org34e60782011-09-15 07:25:40 +0000656RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
657 ASSERT(args.length() == 4);
658 Object* handler = args[0];
659 Object* call_trap = args[1];
660 Object* construct_trap = args[2];
661 Object* prototype = args[3];
662 Object* used_prototype =
663 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
664 return isolate->heap()->AllocateJSFunctionProxy(
665 handler, call_trap, construct_trap, used_prototype);
666}
667
668
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
670 ASSERT(args.length() == 1);
671 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000672 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000673}
674
675
lrn@chromium.org34e60782011-09-15 07:25:40 +0000676RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
677 ASSERT(args.length() == 1);
678 Object* obj = args[0];
679 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
680}
681
682
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000683RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
684 ASSERT(args.length() == 1);
685 CONVERT_CHECKED(JSProxy, proxy, args[0]);
686 return proxy->handler();
687}
688
689
lrn@chromium.org34e60782011-09-15 07:25:40 +0000690RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
691 ASSERT(args.length() == 1);
692 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
693 return proxy->call_trap();
694}
695
696
697RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
698 ASSERT(args.length() == 1);
699 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
700 return proxy->construct_trap();
701}
702
703
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000704RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
705 ASSERT(args.length() == 1);
706 CONVERT_CHECKED(JSProxy, proxy, args[0]);
707 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000708 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000709}
710
711
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000712RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
713 HandleScope scope(isolate);
714 ASSERT(args.length() == 1);
715 CONVERT_ARG_CHECKED(JSSet, holder, 0);
716 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
717 holder->set_table(*table);
718 return *holder;
719}
720
721
722RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
723 HandleScope scope(isolate);
724 ASSERT(args.length() == 2);
725 CONVERT_ARG_CHECKED(JSSet, holder, 0);
726 Handle<Object> key(args[1]);
727 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
728 table = ObjectHashSetAdd(table, key);
729 holder->set_table(*table);
730 return isolate->heap()->undefined_symbol();
731}
732
733
734RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
735 HandleScope scope(isolate);
736 ASSERT(args.length() == 2);
737 CONVERT_ARG_CHECKED(JSSet, holder, 0);
738 Handle<Object> key(args[1]);
739 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
740 return isolate->heap()->ToBoolean(table->Contains(*key));
741}
742
743
744RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
745 HandleScope scope(isolate);
746 ASSERT(args.length() == 2);
747 CONVERT_ARG_CHECKED(JSSet, holder, 0);
748 Handle<Object> key(args[1]);
749 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
750 table = ObjectHashSetRemove(table, key);
751 holder->set_table(*table);
752 return isolate->heap()->undefined_symbol();
753}
754
755
756RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
757 HandleScope scope(isolate);
758 ASSERT(args.length() == 1);
759 CONVERT_ARG_CHECKED(JSMap, holder, 0);
760 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
761 holder->set_table(*table);
762 return *holder;
763}
764
765
766RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
767 HandleScope scope(isolate);
768 ASSERT(args.length() == 2);
769 CONVERT_ARG_CHECKED(JSMap, holder, 0);
770 Handle<Object> key(args[1]);
771 return ObjectHashTable::cast(holder->table())->Lookup(*key);
772}
773
774
775RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
776 HandleScope scope(isolate);
777 ASSERT(args.length() == 3);
778 CONVERT_ARG_CHECKED(JSMap, holder, 0);
779 Handle<Object> key(args[1]);
780 Handle<Object> value(args[2]);
781 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
782 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
783 holder->set_table(*new_table);
784 return *value;
785}
786
787
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000788RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
789 HandleScope scope(isolate);
790 ASSERT(args.length() == 1);
791 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
792 ASSERT(weakmap->map()->inobject_properties() == 0);
793 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
794 weakmap->set_table(*table);
795 weakmap->set_next(Smi::FromInt(0));
796 return *weakmap;
797}
798
799
800RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
801 NoHandleAllocation ha;
802 ASSERT(args.length() == 2);
803 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000804 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
805 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806}
807
808
809RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
810 HandleScope scope(isolate);
811 ASSERT(args.length() == 3);
812 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000813 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000814 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000815 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000816 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
817 weakmap->set_table(*new_table);
818 return *value;
819}
820
821
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000822RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 NoHandleAllocation ha;
824 ASSERT(args.length() == 1);
825 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000826 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827 return JSObject::cast(obj)->class_name();
828}
829
ager@chromium.org7c537e22008-10-16 08:43:32 +0000830
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000831RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
832 NoHandleAllocation ha;
833 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000834 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
835 Object* obj = input_obj;
836 // We don't expect access checks to be needed on JSProxy objects.
837 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000838 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000839 if (obj->IsAccessCheckNeeded() &&
840 !isolate->MayNamedAccess(JSObject::cast(obj),
841 isolate->heap()->Proto_symbol(),
842 v8::ACCESS_GET)) {
843 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
844 return isolate->heap()->undefined_value();
845 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000846 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000847 } while (obj->IsJSObject() &&
848 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849 return obj;
850}
851
852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000853RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000854 NoHandleAllocation ha;
855 ASSERT(args.length() == 2);
856 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
857 Object* O = args[0];
858 Object* V = args[1];
859 while (true) {
860 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 if (prototype->IsNull()) return isolate->heap()->false_value();
862 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 V = prototype;
864 }
865}
866
867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000868RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000870 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000871 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873}
874
875
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000876// Recursively traverses hidden prototypes if property is not found
877static void GetOwnPropertyImplementation(JSObject* obj,
878 String* name,
879 LookupResult* result) {
880 obj->LocalLookupRealNamedProperty(name, result);
881
882 if (!result->IsProperty()) {
883 Object* proto = obj->GetPrototype();
884 if (proto->IsJSObject() &&
885 JSObject::cast(proto)->map()->is_hidden_prototype())
886 GetOwnPropertyImplementation(JSObject::cast(proto),
887 name, result);
888 }
889}
890
891
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000892static bool CheckAccessException(LookupResult* result,
893 v8::AccessType access_type) {
894 if (result->type() == CALLBACKS) {
895 Object* callback = result->GetCallbackObject();
896 if (callback->IsAccessorInfo()) {
897 AccessorInfo* info = AccessorInfo::cast(callback);
898 bool can_access =
899 (access_type == v8::ACCESS_HAS &&
900 (info->all_can_read() || info->all_can_write())) ||
901 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
902 (access_type == v8::ACCESS_SET && info->all_can_write());
903 return can_access;
904 }
905 }
906
907 return false;
908}
909
910
911static bool CheckAccess(JSObject* obj,
912 String* name,
913 LookupResult* result,
914 v8::AccessType access_type) {
915 ASSERT(result->IsProperty());
916
917 JSObject* holder = result->holder();
918 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000920 while (true) {
921 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000922 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000923 // Access check callback denied the access, but some properties
924 // can have a special permissions which override callbacks descision
925 // (currently see v8::AccessControl).
926 break;
927 }
928
929 if (current == holder) {
930 return true;
931 }
932
933 current = JSObject::cast(current->GetPrototype());
934 }
935
936 // API callbacks can have per callback access exceptions.
937 switch (result->type()) {
938 case CALLBACKS: {
939 if (CheckAccessException(result, access_type)) {
940 return true;
941 }
942 break;
943 }
944 case INTERCEPTOR: {
945 // If the object has an interceptor, try real named properties.
946 // Overwrite the result to fetch the correct property later.
947 holder->LookupRealNamedProperty(name, result);
948 if (result->IsProperty()) {
949 if (CheckAccessException(result, access_type)) {
950 return true;
951 }
952 }
953 break;
954 }
955 default:
956 break;
957 }
958
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000959 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000960 return false;
961}
962
963
964// TODO(1095): we should traverse hidden prototype hierachy as well.
965static bool CheckElementAccess(JSObject* obj,
966 uint32_t index,
967 v8::AccessType access_type) {
968 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000970 return false;
971 }
972
973 return true;
974}
975
976
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000977// Enumerator used as indices into the array returned from GetOwnProperty
978enum PropertyDescriptorIndices {
979 IS_ACCESSOR_INDEX,
980 VALUE_INDEX,
981 GETTER_INDEX,
982 SETTER_INDEX,
983 WRITABLE_INDEX,
984 ENUMERABLE_INDEX,
985 CONFIGURABLE_INDEX,
986 DESCRIPTOR_SIZE
987};
988
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000989// Returns an array with the property description:
990// if args[1] is not a property on args[0]
991// returns undefined
992// if args[1] is a data property on args[0]
993// [false, value, Writeable, Enumerable, Configurable]
994// if args[1] is an accessor on args[0]
995// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000996RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000997 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 Heap* heap = isolate->heap();
999 HandleScope scope(isolate);
1000 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1001 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001002 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001003 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1004 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001005
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001006 // This could be an element.
1007 uint32_t index;
1008 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001009 switch (obj->HasLocalElement(index)) {
1010 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001012
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001013 case JSObject::STRING_CHARACTER_ELEMENT: {
1014 // Special handling of string objects according to ECMAScript 5
1015 // 15.5.5.2. Note that this might be a string object with elements
1016 // other than the actual string value. This is covered by the
1017 // subsequent cases.
1018 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1019 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001020 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001022 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001023 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001024 elms->set(WRITABLE_INDEX, heap->false_value());
1025 elms->set(ENUMERABLE_INDEX, heap->false_value());
1026 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001027 return *desc;
1028 }
1029
1030 case JSObject::INTERCEPTED_ELEMENT:
1031 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001033 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001034 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001035 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001036 elms->set(WRITABLE_INDEX, heap->true_value());
1037 elms->set(ENUMERABLE_INDEX, heap->true_value());
1038 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001039 return *desc;
1040 }
1041
1042 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001043 Handle<JSObject> holder = obj;
1044 if (obj->IsJSGlobalProxy()) {
1045 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001046 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001047 ASSERT(proto->IsJSGlobalObject());
1048 holder = Handle<JSObject>(JSObject::cast(proto));
1049 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001050 FixedArray* elements = FixedArray::cast(holder->elements());
1051 NumberDictionary* dictionary = NULL;
1052 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1053 dictionary = NumberDictionary::cast(elements->get(1));
1054 } else {
1055 dictionary = NumberDictionary::cast(elements);
1056 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001057 int entry = dictionary->FindEntry(index);
1058 ASSERT(entry != NumberDictionary::kNotFound);
1059 PropertyDetails details = dictionary->DetailsAt(entry);
1060 switch (details.type()) {
1061 case CALLBACKS: {
1062 // This is an accessor property with getter and/or setter.
1063 FixedArray* callbacks =
1064 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001065 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001066 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1067 elms->set(GETTER_INDEX, callbacks->get(0));
1068 }
1069 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1070 elms->set(SETTER_INDEX, callbacks->get(1));
1071 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001072 break;
1073 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001074 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001075 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001077 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001078 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001079 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001080 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001081 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001082 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001083 default:
1084 UNREACHABLE();
1085 break;
1086 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1088 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001089 return *desc;
1090 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001091 }
1092 }
1093
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001094 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001095 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001096
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001097 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001099 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001100
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001101 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001103 }
1104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001105 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1106 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001107
1108 bool is_js_accessor = (result.type() == CALLBACKS) &&
1109 (result.GetCallbackObject()->IsFixedArray());
1110
1111 if (is_js_accessor) {
1112 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001114
1115 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1116 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1117 elms->set(GETTER_INDEX, structure->get(0));
1118 }
1119 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1120 elms->set(SETTER_INDEX, structure->get(1));
1121 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001122 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001123 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1124 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001125
1126 PropertyAttributes attrs;
1127 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001128 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001129 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1130 if (!maybe_value->ToObject(&value)) return maybe_value;
1131 }
1132 elms->set(VALUE_INDEX, value);
1133 }
1134
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001135 return *desc;
1136}
1137
1138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001139RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001140 ASSERT(args.length() == 1);
1141 CONVERT_CHECKED(JSObject, obj, args[0]);
1142 return obj->PreventExtensions();
1143}
1144
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001146RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001147 ASSERT(args.length() == 1);
1148 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001149 if (obj->IsJSGlobalProxy()) {
1150 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001151 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001152 ASSERT(proto->IsJSGlobalObject());
1153 obj = JSObject::cast(proto);
1154 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001155 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001156}
1157
1158
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001159RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001162 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1163 CONVERT_ARG_CHECKED(String, pattern, 1);
1164 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001165 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1166 if (result.is_null()) return Failure::Exception();
1167 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168}
1169
1170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001171RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001174 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001175 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176}
1177
1178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001179RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180 ASSERT(args.length() == 1);
1181 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001182 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001183 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184}
1185
1186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001187RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 ASSERT(args.length() == 2);
1189 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001191 int index = field->value();
1192 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1193 InstanceType type = templ->map()->instance_type();
1194 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1195 type == OBJECT_TEMPLATE_INFO_TYPE);
1196 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001197 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001198 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1199 } else {
1200 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1201 }
1202 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203}
1204
1205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001206RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001207 ASSERT(args.length() == 1);
1208 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001209 Map* old_map = object->map();
1210 bool needs_access_checks = old_map->is_access_check_needed();
1211 if (needs_access_checks) {
1212 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001213 Object* new_map;
1214 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1215 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1216 }
ager@chromium.org32912102009-01-16 10:38:43 +00001217
1218 Map::cast(new_map)->set_is_access_check_needed(false);
1219 object->set_map(Map::cast(new_map));
1220 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001221 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001222}
1223
1224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001225RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001226 ASSERT(args.length() == 1);
1227 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001228 Map* old_map = object->map();
1229 if (!old_map->is_access_check_needed()) {
1230 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001231 Object* new_map;
1232 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1233 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1234 }
ager@chromium.org32912102009-01-16 10:38:43 +00001235
1236 Map::cast(new_map)->set_is_access_check_needed(true);
1237 object->set_map(Map::cast(new_map));
1238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001239 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001240}
1241
1242
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001243static Failure* ThrowRedeclarationError(Isolate* isolate,
1244 const char* type,
1245 Handle<String> name) {
1246 HandleScope scope(isolate);
1247 Handle<Object> type_handle =
1248 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 Handle<Object> args[2] = { type_handle, name };
1250 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001251 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1252 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253}
1254
1255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001256RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001257 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001258 HandleScope scope(isolate);
1259 Handle<GlobalObject> global = Handle<GlobalObject>(
1260 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261
ager@chromium.org3811b432009-10-28 14:53:37 +00001262 Handle<Context> context = args.at<Context>(0);
1263 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001264 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 // Traverse the name/value pairs and set the properties.
1267 int length = pairs->length();
1268 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001271 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272
1273 // We have to declare a global const property. To capture we only
1274 // assign to it when evaluating the assignment for "const x =
1275 // <expr>" the initial value is the hole.
1276 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001277 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 if (value->IsUndefined() || is_const_property) {
1279 // Lookup the property in the global object, and don't set the
1280 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001281 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 global->Lookup(*name, &lookup);
1283 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001284 // We found an existing property. Unless it was an interceptor
1285 // that claims the property is absent, skip this declaration.
1286 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287 continue;
1288 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001289 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1290 if (attributes != ABSENT) {
1291 continue;
1292 }
1293 // Fall-through and introduce the absent property by using
1294 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295 }
1296 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001297 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001299 Handle<SharedFunctionInfo> shared =
1300 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1303 context,
1304 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 value = function;
1306 }
1307
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001308 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309 global->LocalLookup(*name, &lookup);
1310
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001311 // Compute the property attributes. According to ECMA-262, section
1312 // 13, page 71, the property must be read-only and
1313 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1314 // property as read-only, so we don't either.
1315 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001316 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001317 attr |= DONT_DELETE;
1318 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001319 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001320 if (is_const_property || (is_native && is_function_declaration)) {
1321 attr |= READ_ONLY;
1322 }
1323
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001324 // Safari does not allow the invocation of callback setters for
1325 // function declarations. To mimic this behavior, we do not allow
1326 // the invocation of setters for function values. This makes a
1327 // difference for global functions with the same names as event
1328 // handlers such as "function onload() {}". Firefox does call the
1329 // onload setter in those case and Safari does not. We follow
1330 // Safari for compatibility.
1331 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001332 // Do not change DONT_DELETE to false from true.
1333 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001334 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001335 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001336 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1337
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001338 RETURN_IF_EMPTY_HANDLE(isolate,
1339 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 name,
1341 value,
1342 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001344 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1345 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1346 ? kNonStrictMode : kStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001347 RETURN_IF_EMPTY_HANDLE(isolate,
1348 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001349 name,
1350 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001351 static_cast<PropertyAttributes>(attr),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001352 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353 }
1354 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001356 ASSERT(!isolate->has_pending_exception());
1357 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358}
1359
1360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001361RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001362 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001363 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001365 // Declarations are always made in a function or global context. In the
1366 // case of eval code, the context passed is the context of the caller,
1367 // which may be some nested context and not the declaration context.
1368 RUNTIME_ASSERT(args[0]->IsContext());
1369 Handle<Context> context(Context::cast(args[0])->declaration_context());
1370
ager@chromium.org7c537e22008-10-16 08:43:32 +00001371 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001372 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001373 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001375
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 int index;
1377 PropertyAttributes attributes;
1378 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001379 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001380 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001381 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382
1383 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001384 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1386 // Functions are not read-only.
1387 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1388 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001389 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 }
1391
1392 // Initialize it if necessary.
1393 if (*initial_value != NULL) {
1394 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001395 ASSERT(holder.is_identical_to(context));
1396 if (((attributes & READ_ONLY) == 0) ||
1397 context->get(index)->IsTheHole()) {
1398 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 }
1400 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 // Slow case: The property is in the context extension object of a
1402 // function context or the global object of a global context.
1403 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001404 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001406 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407 }
1408 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001411 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001412 // "declared" in the function context's extension context or as a
1413 // property of the the global object.
1414 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001415 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001416 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001417 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001418 // Context extension objects are allocated lazily.
1419 ASSERT(context->IsFunctionContext());
1420 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001422 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001423 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 // Declare the property by setting it to the initial value if provided,
1427 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1428 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001429 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001430 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001431 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001432 // Declaring a const context slot is a conflicting declaration if
1433 // there is a callback with that name in a prototype. It is
1434 // allowed to introduce const variables in
1435 // JSContextExtensionObjects. They are treated specially in
1436 // SetProperty and no setters are invoked for those since they are
1437 // not real JSObjects.
1438 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001439 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001440 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001441 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001442 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001444 }
1445 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001447 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001448 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001449 }
1450
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452}
1453
1454
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001455RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001457 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001458 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001459 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 // Determine if we need to assign to the variable if it already
1462 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1464 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465
1466 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001467 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001468 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001469 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1470 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1471 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472
1473 // According to ECMA-262, section 12.2, page 62, the property must
1474 // not be deletable.
1475 PropertyAttributes attributes = DONT_DELETE;
1476
1477 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001478 // there, there is a property with this name in the prototype chain.
1479 // We follow Safari and Firefox behavior and only set the property
1480 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001481 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001482 // Note that objects can have hidden prototypes, so we need to traverse
1483 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001484 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001485 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001486 while (object->IsJSObject() &&
1487 JSObject::cast(object)->map()->is_hidden_prototype()) {
1488 JSObject* raw_holder = JSObject::cast(object);
1489 raw_holder->LocalLookup(*name, &lookup);
1490 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1491 HandleScope handle_scope(isolate);
1492 Handle<JSObject> holder(raw_holder);
1493 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1494 // Update the raw pointer in case it's changed due to GC.
1495 raw_holder = *holder;
1496 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1497 // Found an interceptor that's not read only.
1498 if (assign) {
1499 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001500 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 } else {
1502 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001503 }
1504 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001505 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507 }
1508
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001509 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001510 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001511 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001512 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001513 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001514 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515}
1516
1517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001518RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519 // All constants are declared with an initial value. The name
1520 // of the constant is the first argument and the initial value
1521 // is the second.
1522 RUNTIME_ASSERT(args.length() == 2);
1523 CONVERT_ARG_CHECKED(String, name, 0);
1524 Handle<Object> value = args.at<Object>(1);
1525
1526 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001527 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528
1529 // According to ECMA-262, section 12.2, page 62, the property must
1530 // not be deletable. Since it's a const, it must be READ_ONLY too.
1531 PropertyAttributes attributes =
1532 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1533
1534 // Lookup the property locally in the global object. If it isn't
1535 // there, we add the property and take special precautions to always
1536 // add it as a local property even in case of callbacks in the
1537 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001538 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001539 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 global->LocalLookup(*name, &lookup);
1541 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001542 return global->SetLocalPropertyIgnoreAttributes(*name,
1543 *value,
1544 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545 }
1546
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001549 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001550 HandleScope handle_scope(isolate);
1551 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001553 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 // property through an interceptor and only do it if it's
1555 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001556 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 RETURN_IF_EMPTY_HANDLE(isolate,
1558 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001559 name,
1560 value,
1561 attributes,
1562 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 return *value;
1564 }
1565
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001566 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001567 // constant. For now, we determine this by checking if the
1568 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001569 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 PropertyType type = lookup.type();
1571 if (type == FIELD) {
1572 FixedArray* properties = global->properties();
1573 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001574 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575 properties->set(index, *value);
1576 }
1577 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001578 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1579 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001580 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 }
1582 } else {
1583 // Ignore re-initialization of constants that have already been
1584 // assigned a function value.
1585 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1586 }
1587
1588 // Use the set value as the result of the operation.
1589 return *value;
1590}
1591
1592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001593RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 ASSERT(args.length() == 3);
1596
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001597 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001599
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001600 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001601 RUNTIME_ASSERT(args[1]->IsContext());
1602 Handle<Context> context(Context::cast(args[1])->declaration_context());
1603
1604 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
1606 int index;
1607 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001608 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001609 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001610 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001611 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001614 ASSERT(holder->IsContext());
1615 // Property was found in a context. Perform the assignment if we
1616 // found some non-constant or an uninitialized constant.
1617 Handle<Context> context = Handle<Context>::cast(holder);
1618 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1619 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 }
1621 return *value;
1622 }
1623
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001624 // The property could not be found, we introduce it as a property of the
1625 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001626 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001627 Handle<JSObject> global = Handle<JSObject>(
1628 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001629 // Strict mode not needed (const disallowed in strict mode).
1630 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001631 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001632 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001633 return *value;
1634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001636 // The property was present in some function's context extension object,
1637 // as a property on the subject of a with, or as a property of the global
1638 // object.
1639 //
1640 // In most situations, eval-introduced consts should still be present in
1641 // the context extension object. However, because declaration and
1642 // initialization are separate, the property might have been deleted
1643 // before we reach the initialization point.
1644 //
1645 // Example:
1646 //
1647 // function f() { eval("delete x; const x;"); }
1648 //
1649 // In that case, the initialization behaves like a normal assignment.
1650 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001652 if (*object == context->extension()) {
1653 // This is the property that was introduced by the const declaration.
1654 // Set it if it hasn't been set before. NOTE: We cannot use
1655 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001656 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001657 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001658 ASSERT(lookup.IsProperty()); // the property was declared
1659 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1660
1661 PropertyType type = lookup.type();
1662 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001663 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001664 int index = lookup.GetFieldIndex();
1665 if (properties->get(index)->IsTheHole()) {
1666 properties->set(index, *value);
1667 }
1668 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001669 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1670 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001671 }
1672 } else {
1673 // We should not reach here. Any real, named property should be
1674 // either a field or a dictionary slot.
1675 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001676 }
1677 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001678 // The property was found on some other object. Set it if it is not a
1679 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001680 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001681 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001682 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001683 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001684 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001685 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001686 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001687
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001688 return *value;
1689}
1690
1691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001692RUNTIME_FUNCTION(MaybeObject*,
1693 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001694 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001695 ASSERT(args.length() == 2);
1696 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001697 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001698 if (object->HasFastProperties()) {
1699 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1700 }
1701 return *object;
1702}
1703
1704
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001705RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001706 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001707 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001708 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1709 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001710 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001711 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001712 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001713 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001714 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001715 RUNTIME_ASSERT(index >= 0);
1716 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001718 Handle<Object> result = RegExpImpl::Exec(regexp,
1719 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001720 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001721 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001722 if (result.is_null()) return Failure::Exception();
1723 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001724}
1725
1726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001727RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001728 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001729 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001730 if (elements_count < 0 ||
1731 elements_count > FixedArray::kMaxLength ||
1732 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001733 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001734 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001735 Object* new_object;
1736 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001738 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1739 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001740 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1742 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1744 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001745 {
1746 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001748 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001749 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001750 }
1751 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001752 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001753 array->set_elements(elements);
1754 array->set_length(Smi::FromInt(elements_count));
1755 // Write in-object properties after the length of the array.
1756 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1757 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1758 return array;
1759}
1760
1761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001762RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001763 AssertNoAllocation no_alloc;
1764 ASSERT(args.length() == 5);
1765 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1766 CONVERT_CHECKED(String, source, args[1]);
1767
1768 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001770
1771 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001773
1774 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001776
1777 Map* map = regexp->map();
1778 Object* constructor = map->constructor();
1779 if (constructor->IsJSFunction() &&
1780 JSFunction::cast(constructor)->initial_map() == map) {
1781 // If we still have the original map, set in-object properties directly.
1782 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001783 // Both true and false are immovable immortal objects so no need for write
1784 // barrier.
1785 regexp->InObjectPropertyAtPut(
1786 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1787 regexp->InObjectPropertyAtPut(
1788 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1789 regexp->InObjectPropertyAtPut(
1790 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001791 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1792 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001793 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001794 return regexp;
1795 }
1796
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001797 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001798 PropertyAttributes final =
1799 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1800 PropertyAttributes writable =
1801 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001802 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001803 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001805 source,
1806 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001807 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001809 global,
1810 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001811 ASSERT(!result->IsFailure());
1812 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001814 ignoreCase,
1815 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001816 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001818 multiline,
1819 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001820 ASSERT(!result->IsFailure());
1821 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001823 Smi::FromInt(0),
1824 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825 ASSERT(!result->IsFailure());
1826 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001827 return regexp;
1828}
1829
1830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001831RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001833 ASSERT(args.length() == 1);
1834 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1835 // This is necessary to enable fast checks for absence of elements
1836 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001837 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001838 return Smi::FromInt(0);
1839}
1840
1841
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001842static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1843 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001844 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001845 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001846 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1847 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1848 Handle<JSFunction> optimized =
1849 isolate->factory()->NewFunction(key,
1850 JS_OBJECT_TYPE,
1851 JSObject::kHeaderSize,
1852 code,
1853 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001854 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001855 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001856 return optimized;
1857}
1858
1859
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001860RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001862 ASSERT(args.length() == 1);
1863 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1864
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001865 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1866 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1867 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1868 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1869 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1870 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1871 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001872
1873 return *holder;
1874}
1875
1876
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001877RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1878 NoHandleAllocation handle_free;
1879 ASSERT(args.length() == 1);
1880 CONVERT_CHECKED(JSFunction, function, args[0]);
1881 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001882 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001883 return isolate->heap()->undefined_value();
1884 }
1885 // Returns undefined for strict or native functions, or
1886 // the associated global receiver for "normal" functions.
1887
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001888 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001889 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001890 return global_context->global()->global_receiver();
1891}
1892
1893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001894RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001895 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 ASSERT(args.length() == 4);
1897 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001898 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001899 Handle<String> pattern = args.at<String>(2);
1900 Handle<String> flags = args.at<String>(3);
1901
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001902 // Get the RegExp function from the context in the literals array.
1903 // This is the RegExp function from the context in which the
1904 // function was created. We do not use the RegExp function from the
1905 // current global context because this might be the RegExp function
1906 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001907 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001908 Handle<JSFunction>(
1909 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001910 // Compute the regular expression literal.
1911 bool has_pending_exception;
1912 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001913 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1914 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001916 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001917 return Failure::Exception();
1918 }
1919 literals->set(index, *regexp);
1920 return *regexp;
1921}
1922
1923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001924RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 NoHandleAllocation ha;
1926 ASSERT(args.length() == 1);
1927
1928 CONVERT_CHECKED(JSFunction, f, args[0]);
1929 return f->shared()->name();
1930}
1931
1932
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001933RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001934 NoHandleAllocation ha;
1935 ASSERT(args.length() == 2);
1936
1937 CONVERT_CHECKED(JSFunction, f, args[0]);
1938 CONVERT_CHECKED(String, name, args[1]);
1939 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001940 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001941}
1942
1943
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001944RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1945 NoHandleAllocation ha;
1946 ASSERT(args.length() == 1);
1947 CONVERT_CHECKED(JSFunction, f, args[0]);
1948 return isolate->heap()->ToBoolean(
1949 f->shared()->name_should_print_as_anonymous());
1950}
1951
1952
1953RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1954 NoHandleAllocation ha;
1955 ASSERT(args.length() == 1);
1956 CONVERT_CHECKED(JSFunction, f, args[0]);
1957 f->shared()->set_name_should_print_as_anonymous(true);
1958 return isolate->heap()->undefined_value();
1959}
1960
1961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001962RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001963 NoHandleAllocation ha;
1964 ASSERT(args.length() == 1);
1965
1966 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001967 Object* obj = f->RemovePrototype();
1968 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001969
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001970 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001971}
1972
1973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001974RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001975 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976 ASSERT(args.length() == 1);
1977
1978 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001979 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1980 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001981
1982 return *GetScriptWrapper(Handle<Script>::cast(script));
1983}
1984
1985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
1989
1990 CONVERT_CHECKED(JSFunction, f, args[0]);
1991 return f->shared()->GetSourceCode();
1992}
1993
1994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001995RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001996 NoHandleAllocation ha;
1997 ASSERT(args.length() == 1);
1998
1999 CONVERT_CHECKED(JSFunction, fun, args[0]);
2000 int pos = fun->shared()->start_position();
2001 return Smi::FromInt(pos);
2002}
2003
2004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002005RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002006 ASSERT(args.length() == 2);
2007
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002009 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2010
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002011 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2012
2013 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002014 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002015}
2016
2017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002018RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002019 NoHandleAllocation ha;
2020 ASSERT(args.length() == 2);
2021
2022 CONVERT_CHECKED(JSFunction, fun, args[0]);
2023 CONVERT_CHECKED(String, name, args[1]);
2024 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002025 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026}
2027
2028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002029RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 NoHandleAllocation ha;
2031 ASSERT(args.length() == 2);
2032
2033 CONVERT_CHECKED(JSFunction, fun, args[0]);
2034 CONVERT_CHECKED(Smi, length, args[1]);
2035 fun->shared()->set_length(length->value());
2036 return length;
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002041 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002042 ASSERT(args.length() == 2);
2043
2044 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002045 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002046 Object* obj;
2047 { MaybeObject* maybe_obj =
2048 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2049 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2050 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051 return args[0]; // return TOS
2052}
2053
2054
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002055RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2056 NoHandleAllocation ha;
2057 RUNTIME_ASSERT(args.length() == 1);
2058 CONVERT_CHECKED(JSFunction, function, args[0]);
2059
2060 MaybeObject* maybe_name =
2061 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2062 String* name;
2063 if (!maybe_name->To(&name)) return maybe_name;
2064
2065 if (function->HasFastProperties()) {
2066 // Construct a new field descriptor with updated attributes.
2067 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2068 int index = instance_desc->Search(name);
2069 ASSERT(index != DescriptorArray::kNotFound);
2070 PropertyDetails details(instance_desc->GetDetails(index));
2071 CallbacksDescriptor new_desc(name,
2072 instance_desc->GetValue(index),
2073 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2074 details.index());
2075 // Construct a new field descriptors array containing the new descriptor.
2076 Object* descriptors_unchecked;
2077 { MaybeObject* maybe_descriptors_unchecked =
2078 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2079 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2080 return maybe_descriptors_unchecked;
2081 }
2082 }
2083 DescriptorArray* new_descriptors =
2084 DescriptorArray::cast(descriptors_unchecked);
2085 // Create a new map featuring the new field descriptors array.
2086 Object* map_unchecked;
2087 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2088 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2089 return maybe_map_unchecked;
2090 }
2091 }
2092 Map* new_map = Map::cast(map_unchecked);
2093 new_map->set_instance_descriptors(new_descriptors);
2094 function->set_map(new_map);
2095 } else { // Dictionary properties.
2096 // Directly manipulate the property details.
2097 int entry = function->property_dictionary()->FindEntry(name);
2098 ASSERT(entry != StringDictionary::kNotFound);
2099 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2100 PropertyDetails new_details(
2101 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2102 details.type(),
2103 details.index());
2104 function->property_dictionary()->DetailsAtPut(entry, new_details);
2105 }
2106 return function;
2107}
2108
2109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002110RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002111 NoHandleAllocation ha;
2112 ASSERT(args.length() == 1);
2113
2114 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002115 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002116}
2117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002119RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002120 NoHandleAllocation ha;
2121 ASSERT(args.length() == 1);
2122
2123 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002124 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002125}
2126
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002128RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002129 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002130 ASSERT(args.length() == 2);
2131
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002132 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002133 Handle<Object> code = args.at<Object>(1);
2134
2135 Handle<Context> context(target->context());
2136
2137 if (!code->IsNull()) {
2138 RUNTIME_ASSERT(code->IsJSFunction());
2139 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002140 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002141
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002142 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002143 return Failure::Exception();
2144 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002145 // Since we don't store the source for this we should never
2146 // optimize this.
2147 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002148 // Set the code, scope info, formal parameter count,
2149 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002150 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002151 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002152 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002153 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002155 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002156 // Set the source code of the target function to undefined.
2157 // SetCode is only used for built-in constructors like String,
2158 // Array, and Object, and some web code
2159 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002160 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002161 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002162 // Clear the optimization hints related to the compiled code as these are no
2163 // longer valid when the code is overwritten.
2164 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002165 context = Handle<Context>(fun->context());
2166
2167 // Make sure we get a fresh copy of the literal vector to avoid
2168 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002169 int number_of_literals = fun->NumberOfLiterals();
2170 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002171 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002173 // Insert the object, regexp and array functions in the literals
2174 // array prefix. These are the functions that will be used when
2175 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002176 literals->set(JSFunction::kLiteralGlobalContextIndex,
2177 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002178 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002179 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002180 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002181
2182 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2183 isolate->logger()->LogExistingFunction(
2184 shared, Handle<Code>(shared->code()));
2185 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002186 }
2187
2188 target->set_context(*context);
2189 return *target;
2190}
2191
2192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002193RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002195 ASSERT(args.length() == 2);
2196 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002197 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002198 RUNTIME_ASSERT(num >= 0);
2199 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002200 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002201}
2202
2203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002204MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2205 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002206 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002207 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002208 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002209 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002210 }
2211 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002212 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002213}
2214
2215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002216RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002217 NoHandleAllocation ha;
2218 ASSERT(args.length() == 2);
2219
2220 CONVERT_CHECKED(String, subject, args[0]);
2221 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002222 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002223
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002224 uint32_t i = 0;
2225 if (index->IsSmi()) {
2226 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002227 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002228 i = value;
2229 } else {
2230 ASSERT(index->IsHeapNumber());
2231 double value = HeapNumber::cast(index)->value();
2232 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002233 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002234
2235 // Flatten the string. If someone wants to get a char at an index
2236 // in a cons string, it is likely that more indices will be
2237 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002238 Object* flat;
2239 { MaybeObject* maybe_flat = subject->TryFlatten();
2240 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2241 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002242 subject = String::cast(flat);
2243
2244 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002245 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002246 }
2247
2248 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002249}
2250
2251
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002252RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002253 NoHandleAllocation ha;
2254 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002255 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002256}
2257
lrn@chromium.org25156de2010-04-06 13:10:27 +00002258
2259class FixedArrayBuilder {
2260 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002261 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2262 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002263 length_(0),
2264 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002265 // Require a non-zero initial size. Ensures that doubling the size to
2266 // extend the array will work.
2267 ASSERT(initial_capacity > 0);
2268 }
2269
2270 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2271 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002272 length_(0),
2273 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002274 // Require a non-zero initial size. Ensures that doubling the size to
2275 // extend the array will work.
2276 ASSERT(backing_store->length() > 0);
2277 }
2278
2279 bool HasCapacity(int elements) {
2280 int length = array_->length();
2281 int required_length = length_ + elements;
2282 return (length >= required_length);
2283 }
2284
2285 void EnsureCapacity(int elements) {
2286 int length = array_->length();
2287 int required_length = length_ + elements;
2288 if (length < required_length) {
2289 int new_length = length;
2290 do {
2291 new_length *= 2;
2292 } while (new_length < required_length);
2293 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002294 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002295 array_->CopyTo(0, *extended_array, 0, length_);
2296 array_ = extended_array;
2297 }
2298 }
2299
2300 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002301 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002302 ASSERT(length_ < capacity());
2303 array_->set(length_, value);
2304 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002305 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002306 }
2307
2308 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002309 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002310 ASSERT(length_ < capacity());
2311 array_->set(length_, value);
2312 length_++;
2313 }
2314
2315 Handle<FixedArray> array() {
2316 return array_;
2317 }
2318
2319 int length() {
2320 return length_;
2321 }
2322
2323 int capacity() {
2324 return array_->length();
2325 }
2326
2327 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002328 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 result_array->set_length(Smi::FromInt(length_));
2330 return result_array;
2331 }
2332
2333 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002334 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002335 target_array->set_length(Smi::FromInt(length_));
2336 return target_array;
2337 }
2338
2339 private:
2340 Handle<FixedArray> array_;
2341 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002342 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002343};
2344
2345
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002346// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002347const int kStringBuilderConcatHelperLengthBits = 11;
2348const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002349
2350template <typename schar>
2351static inline void StringBuilderConcatHelper(String*,
2352 schar*,
2353 FixedArray*,
2354 int);
2355
lrn@chromium.org25156de2010-04-06 13:10:27 +00002356typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2357 StringBuilderSubstringLength;
2358typedef BitField<int,
2359 kStringBuilderConcatHelperLengthBits,
2360 kStringBuilderConcatHelperPositionBits>
2361 StringBuilderSubstringPosition;
2362
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002363
2364class ReplacementStringBuilder {
2365 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002366 ReplacementStringBuilder(Heap* heap,
2367 Handle<String> subject,
2368 int estimated_part_count)
2369 : heap_(heap),
2370 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002371 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002372 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002373 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374 // Require a non-zero initial size. Ensures that doubling the size to
2375 // extend the array will work.
2376 ASSERT(estimated_part_count > 0);
2377 }
2378
lrn@chromium.org25156de2010-04-06 13:10:27 +00002379 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2380 int from,
2381 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002382 ASSERT(from >= 0);
2383 int length = to - from;
2384 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002385 if (StringBuilderSubstringLength::is_valid(length) &&
2386 StringBuilderSubstringPosition::is_valid(from)) {
2387 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2388 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002389 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002390 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002391 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002392 builder->Add(Smi::FromInt(-length));
2393 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002394 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002395 }
2396
2397
2398 void EnsureCapacity(int elements) {
2399 array_builder_.EnsureCapacity(elements);
2400 }
2401
2402
2403 void AddSubjectSlice(int from, int to) {
2404 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002405 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 }
2407
2408
2409 void AddString(Handle<String> string) {
2410 int length = string->length();
2411 ASSERT(length > 0);
2412 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002413 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002414 is_ascii_ = false;
2415 }
2416 IncrementCharacterCount(length);
2417 }
2418
2419
2420 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002421 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002422 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002423 }
2424
2425 Handle<String> joined_string;
2426 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002427 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002429 char* char_buffer = seq->GetChars();
2430 StringBuilderConcatHelper(*subject_,
2431 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002432 *array_builder_.array(),
2433 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002434 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002435 } else {
2436 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002437 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002438 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 uc16* char_buffer = seq->GetChars();
2440 StringBuilderConcatHelper(*subject_,
2441 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002442 *array_builder_.array(),
2443 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002444 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002445 }
2446 return joined_string;
2447 }
2448
2449
2450 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002451 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002452 V8::FatalProcessOutOfMemory("String.replace result too large.");
2453 }
2454 character_count_ += by;
2455 }
2456
lrn@chromium.org25156de2010-04-06 13:10:27 +00002457 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002458 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002459 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002460
lrn@chromium.org25156de2010-04-06 13:10:27 +00002461 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002462 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2463 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002464 }
2465
2466
ager@chromium.org04921a82011-06-27 13:21:41 +00002467 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2468 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 }
2470
2471
2472 void AddElement(Object* element) {
2473 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002474 ASSERT(array_builder_.capacity() > array_builder_.length());
2475 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002476 }
2477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002478 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002479 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002481 int character_count_;
2482 bool is_ascii_;
2483};
2484
2485
2486class CompiledReplacement {
2487 public:
2488 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002489 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002490
2491 void Compile(Handle<String> replacement,
2492 int capture_count,
2493 int subject_length);
2494
2495 void Apply(ReplacementStringBuilder* builder,
2496 int match_from,
2497 int match_to,
2498 Handle<JSArray> last_match_info);
2499
2500 // Number of distinct parts of the replacement pattern.
2501 int parts() {
2502 return parts_.length();
2503 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002504
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002505 bool simple_hint() {
2506 return simple_hint_;
2507 }
2508
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002509 private:
2510 enum PartType {
2511 SUBJECT_PREFIX = 1,
2512 SUBJECT_SUFFIX,
2513 SUBJECT_CAPTURE,
2514 REPLACEMENT_SUBSTRING,
2515 REPLACEMENT_STRING,
2516
2517 NUMBER_OF_PART_TYPES
2518 };
2519
2520 struct ReplacementPart {
2521 static inline ReplacementPart SubjectMatch() {
2522 return ReplacementPart(SUBJECT_CAPTURE, 0);
2523 }
2524 static inline ReplacementPart SubjectCapture(int capture_index) {
2525 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2526 }
2527 static inline ReplacementPart SubjectPrefix() {
2528 return ReplacementPart(SUBJECT_PREFIX, 0);
2529 }
2530 static inline ReplacementPart SubjectSuffix(int subject_length) {
2531 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2532 }
2533 static inline ReplacementPart ReplacementString() {
2534 return ReplacementPart(REPLACEMENT_STRING, 0);
2535 }
2536 static inline ReplacementPart ReplacementSubString(int from, int to) {
2537 ASSERT(from >= 0);
2538 ASSERT(to > from);
2539 return ReplacementPart(-from, to);
2540 }
2541
2542 // If tag <= 0 then it is the negation of a start index of a substring of
2543 // the replacement pattern, otherwise it's a value from PartType.
2544 ReplacementPart(int tag, int data)
2545 : tag(tag), data(data) {
2546 // Must be non-positive or a PartType value.
2547 ASSERT(tag < NUMBER_OF_PART_TYPES);
2548 }
2549 // Either a value of PartType or a non-positive number that is
2550 // the negation of an index into the replacement string.
2551 int tag;
2552 // The data value's interpretation depends on the value of tag:
2553 // tag == SUBJECT_PREFIX ||
2554 // tag == SUBJECT_SUFFIX: data is unused.
2555 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2556 // tag == REPLACEMENT_SUBSTRING ||
2557 // tag == REPLACEMENT_STRING: data is index into array of substrings
2558 // of the replacement string.
2559 // tag <= 0: Temporary representation of the substring of the replacement
2560 // string ranging over -tag .. data.
2561 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2562 // substring objects.
2563 int data;
2564 };
2565
2566 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002567 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002568 Vector<Char> characters,
2569 int capture_count,
2570 int subject_length) {
2571 int length = characters.length();
2572 int last = 0;
2573 for (int i = 0; i < length; i++) {
2574 Char c = characters[i];
2575 if (c == '$') {
2576 int next_index = i + 1;
2577 if (next_index == length) { // No next character!
2578 break;
2579 }
2580 Char c2 = characters[next_index];
2581 switch (c2) {
2582 case '$':
2583 if (i > last) {
2584 // There is a substring before. Include the first "$".
2585 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2586 last = next_index + 1; // Continue after the second "$".
2587 } else {
2588 // Let the next substring start with the second "$".
2589 last = next_index;
2590 }
2591 i = next_index;
2592 break;
2593 case '`':
2594 if (i > last) {
2595 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2596 }
2597 parts->Add(ReplacementPart::SubjectPrefix());
2598 i = next_index;
2599 last = i + 1;
2600 break;
2601 case '\'':
2602 if (i > last) {
2603 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2604 }
2605 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2606 i = next_index;
2607 last = i + 1;
2608 break;
2609 case '&':
2610 if (i > last) {
2611 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2612 }
2613 parts->Add(ReplacementPart::SubjectMatch());
2614 i = next_index;
2615 last = i + 1;
2616 break;
2617 case '0':
2618 case '1':
2619 case '2':
2620 case '3':
2621 case '4':
2622 case '5':
2623 case '6':
2624 case '7':
2625 case '8':
2626 case '9': {
2627 int capture_ref = c2 - '0';
2628 if (capture_ref > capture_count) {
2629 i = next_index;
2630 continue;
2631 }
2632 int second_digit_index = next_index + 1;
2633 if (second_digit_index < length) {
2634 // Peek ahead to see if we have two digits.
2635 Char c3 = characters[second_digit_index];
2636 if ('0' <= c3 && c3 <= '9') { // Double digits.
2637 int double_digit_ref = capture_ref * 10 + c3 - '0';
2638 if (double_digit_ref <= capture_count) {
2639 next_index = second_digit_index;
2640 capture_ref = double_digit_ref;
2641 }
2642 }
2643 }
2644 if (capture_ref > 0) {
2645 if (i > last) {
2646 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2647 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002648 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002649 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2650 last = next_index + 1;
2651 }
2652 i = next_index;
2653 break;
2654 }
2655 default:
2656 i = next_index;
2657 break;
2658 }
2659 }
2660 }
2661 if (length > last) {
2662 if (last == 0) {
2663 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002664 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002665 } else {
2666 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2667 }
2668 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002669 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002670 }
2671
2672 ZoneList<ReplacementPart> parts_;
2673 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002674 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002675};
2676
2677
2678void CompiledReplacement::Compile(Handle<String> replacement,
2679 int capture_count,
2680 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002681 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002682 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002683 String::FlatContent content = replacement->GetFlatContent();
2684 ASSERT(content.IsFlat());
2685 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002686 simple_hint_ = ParseReplacementPattern(&parts_,
2687 content.ToAsciiVector(),
2688 capture_count,
2689 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002690 } else {
2691 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002692 simple_hint_ = ParseReplacementPattern(&parts_,
2693 content.ToUC16Vector(),
2694 capture_count,
2695 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002696 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002697 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002698 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002699 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002700 int substring_index = 0;
2701 for (int i = 0, n = parts_.length(); i < n; i++) {
2702 int tag = parts_[i].tag;
2703 if (tag <= 0) { // A replacement string slice.
2704 int from = -tag;
2705 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002706 replacement_substrings_.Add(
2707 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002708 parts_[i].tag = REPLACEMENT_SUBSTRING;
2709 parts_[i].data = substring_index;
2710 substring_index++;
2711 } else if (tag == REPLACEMENT_STRING) {
2712 replacement_substrings_.Add(replacement);
2713 parts_[i].data = substring_index;
2714 substring_index++;
2715 }
2716 }
2717}
2718
2719
2720void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2721 int match_from,
2722 int match_to,
2723 Handle<JSArray> last_match_info) {
2724 for (int i = 0, n = parts_.length(); i < n; i++) {
2725 ReplacementPart part = parts_[i];
2726 switch (part.tag) {
2727 case SUBJECT_PREFIX:
2728 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2729 break;
2730 case SUBJECT_SUFFIX: {
2731 int subject_length = part.data;
2732 if (match_to < subject_length) {
2733 builder->AddSubjectSlice(match_to, subject_length);
2734 }
2735 break;
2736 }
2737 case SUBJECT_CAPTURE: {
2738 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002739 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002740 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2741 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2742 if (from >= 0 && to > from) {
2743 builder->AddSubjectSlice(from, to);
2744 }
2745 break;
2746 }
2747 case REPLACEMENT_SUBSTRING:
2748 case REPLACEMENT_STRING:
2749 builder->AddString(replacement_substrings_[part.data]);
2750 break;
2751 default:
2752 UNREACHABLE();
2753 }
2754 }
2755}
2756
2757
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002758void FindAsciiStringIndices(Vector<const char> subject,
2759 char pattern,
2760 ZoneList<int>* indices,
2761 unsigned int limit) {
2762 ASSERT(limit > 0);
2763 // Collect indices of pattern in subject using memchr.
2764 // Stop after finding at most limit values.
2765 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2766 const char* subject_end = subject_start + subject.length();
2767 const char* pos = subject_start;
2768 while (limit > 0) {
2769 pos = reinterpret_cast<const char*>(
2770 memchr(pos, pattern, subject_end - pos));
2771 if (pos == NULL) return;
2772 indices->Add(static_cast<int>(pos - subject_start));
2773 pos++;
2774 limit--;
2775 }
2776}
2777
2778
2779template <typename SubjectChar, typename PatternChar>
2780void FindStringIndices(Isolate* isolate,
2781 Vector<const SubjectChar> subject,
2782 Vector<const PatternChar> pattern,
2783 ZoneList<int>* indices,
2784 unsigned int limit) {
2785 ASSERT(limit > 0);
2786 // Collect indices of pattern in subject.
2787 // Stop after finding at most limit values.
2788 int pattern_length = pattern.length();
2789 int index = 0;
2790 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2791 while (limit > 0) {
2792 index = search.Search(subject, index);
2793 if (index < 0) return;
2794 indices->Add(index);
2795 index += pattern_length;
2796 limit--;
2797 }
2798}
2799
2800
2801void FindStringIndicesDispatch(Isolate* isolate,
2802 String* subject,
2803 String* pattern,
2804 ZoneList<int>* indices,
2805 unsigned int limit) {
2806 {
2807 AssertNoAllocation no_gc;
2808 String::FlatContent subject_content = subject->GetFlatContent();
2809 String::FlatContent pattern_content = pattern->GetFlatContent();
2810 ASSERT(subject_content.IsFlat());
2811 ASSERT(pattern_content.IsFlat());
2812 if (subject_content.IsAscii()) {
2813 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2814 if (pattern_content.IsAscii()) {
2815 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2816 if (pattern_vector.length() == 1) {
2817 FindAsciiStringIndices(subject_vector,
2818 pattern_vector[0],
2819 indices,
2820 limit);
2821 } else {
2822 FindStringIndices(isolate,
2823 subject_vector,
2824 pattern_vector,
2825 indices,
2826 limit);
2827 }
2828 } else {
2829 FindStringIndices(isolate,
2830 subject_vector,
2831 pattern_content.ToUC16Vector(),
2832 indices,
2833 limit);
2834 }
2835 } else {
2836 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002837 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002838 FindStringIndices(isolate,
2839 subject_vector,
2840 pattern_content.ToAsciiVector(),
2841 indices,
2842 limit);
2843 } else {
2844 FindStringIndices(isolate,
2845 subject_vector,
2846 pattern_content.ToUC16Vector(),
2847 indices,
2848 limit);
2849 }
2850 }
2851 }
2852}
2853
2854
2855template<typename ResultSeqString>
2856MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2857 Isolate* isolate,
2858 Handle<String> subject,
2859 Handle<JSRegExp> pattern_regexp,
2860 Handle<String> replacement) {
2861 ASSERT(subject->IsFlat());
2862 ASSERT(replacement->IsFlat());
2863
2864 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2865 ZoneList<int> indices(8);
2866 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2867 String* pattern =
2868 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2869 int subject_len = subject->length();
2870 int pattern_len = pattern->length();
2871 int replacement_len = replacement->length();
2872
2873 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2874
2875 int matches = indices.length();
2876 if (matches == 0) return *subject;
2877
2878 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2879 int subject_pos = 0;
2880 int result_pos = 0;
2881
2882 Handle<ResultSeqString> result;
2883 if (ResultSeqString::kHasAsciiEncoding) {
2884 result = Handle<ResultSeqString>::cast(
2885 isolate->factory()->NewRawAsciiString(result_len));
2886 } else {
2887 result = Handle<ResultSeqString>::cast(
2888 isolate->factory()->NewRawTwoByteString(result_len));
2889 }
2890
2891 for (int i = 0; i < matches; i++) {
2892 // Copy non-matched subject content.
2893 if (subject_pos < indices.at(i)) {
2894 String::WriteToFlat(*subject,
2895 result->GetChars() + result_pos,
2896 subject_pos,
2897 indices.at(i));
2898 result_pos += indices.at(i) - subject_pos;
2899 }
2900
2901 // Replace match.
2902 if (replacement_len > 0) {
2903 String::WriteToFlat(*replacement,
2904 result->GetChars() + result_pos,
2905 0,
2906 replacement_len);
2907 result_pos += replacement_len;
2908 }
2909
2910 subject_pos = indices.at(i) + pattern_len;
2911 }
2912 // Add remaining subject content at the end.
2913 if (subject_pos < subject_len) {
2914 String::WriteToFlat(*subject,
2915 result->GetChars() + result_pos,
2916 subject_pos,
2917 subject_len);
2918 }
2919 return *result;
2920}
2921
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002922
lrn@chromium.org303ada72010-10-27 09:33:13 +00002923MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002924 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002925 String* subject,
2926 JSRegExp* regexp,
2927 String* replacement,
2928 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002929 ASSERT(subject->IsFlat());
2930 ASSERT(replacement->IsFlat());
2931
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002932 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002933
2934 int length = subject->length();
2935 Handle<String> subject_handle(subject);
2936 Handle<JSRegExp> regexp_handle(regexp);
2937 Handle<String> replacement_handle(replacement);
2938 Handle<JSArray> last_match_info_handle(last_match_info);
2939 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2940 subject_handle,
2941 0,
2942 last_match_info_handle);
2943 if (match.is_null()) {
2944 return Failure::Exception();
2945 }
2946 if (match->IsNull()) {
2947 return *subject_handle;
2948 }
2949
2950 int capture_count = regexp_handle->CaptureCount();
2951
2952 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002953 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002954 CompiledReplacement compiled_replacement;
2955 compiled_replacement.Compile(replacement_handle,
2956 capture_count,
2957 length);
2958
2959 bool is_global = regexp_handle->GetFlags().is_global();
2960
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002961 // Shortcut for simple non-regexp global replacements
2962 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002963 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002964 compiled_replacement.simple_hint()) {
2965 if (subject_handle->HasOnlyAsciiChars() &&
2966 replacement_handle->HasOnlyAsciiChars()) {
2967 return StringReplaceStringWithString<SeqAsciiString>(
2968 isolate, subject_handle, regexp_handle, replacement_handle);
2969 } else {
2970 return StringReplaceStringWithString<SeqTwoByteString>(
2971 isolate, subject_handle, regexp_handle, replacement_handle);
2972 }
2973 }
2974
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002975 // Guessing the number of parts that the final result string is built
2976 // from. Global regexps can match any number of times, so we guess
2977 // conservatively.
2978 int expected_parts =
2979 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002980 ReplacementStringBuilder builder(isolate->heap(),
2981 subject_handle,
2982 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002983
2984 // Index of end of last match.
2985 int prev = 0;
2986
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002987 // Number of parts added by compiled replacement plus preceeding
2988 // string and possibly suffix after last match. It is possible for
2989 // all components to use two elements when encoded as two smis.
2990 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002991 bool matched = true;
2992 do {
2993 ASSERT(last_match_info_handle->HasFastElements());
2994 // Increase the capacity of the builder before entering local handle-scope,
2995 // so its internal buffer can safely allocate a new handle if it grows.
2996 builder.EnsureCapacity(parts_added_per_loop);
2997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002998 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002999 int start, end;
3000 {
3001 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003002 FixedArray* match_info_array =
3003 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003004
3005 ASSERT_EQ(capture_count * 2 + 2,
3006 RegExpImpl::GetLastCaptureCount(match_info_array));
3007 start = RegExpImpl::GetCapture(match_info_array, 0);
3008 end = RegExpImpl::GetCapture(match_info_array, 1);
3009 }
3010
3011 if (prev < start) {
3012 builder.AddSubjectSlice(prev, start);
3013 }
3014 compiled_replacement.Apply(&builder,
3015 start,
3016 end,
3017 last_match_info_handle);
3018 prev = end;
3019
3020 // Only continue checking for global regexps.
3021 if (!is_global) break;
3022
3023 // Continue from where the match ended, unless it was an empty match.
3024 int next = end;
3025 if (start == end) {
3026 next = end + 1;
3027 if (next > length) break;
3028 }
3029
3030 match = RegExpImpl::Exec(regexp_handle,
3031 subject_handle,
3032 next,
3033 last_match_info_handle);
3034 if (match.is_null()) {
3035 return Failure::Exception();
3036 }
3037 matched = !match->IsNull();
3038 } while (matched);
3039
3040 if (prev < length) {
3041 builder.AddSubjectSlice(prev, length);
3042 }
3043
3044 return *(builder.ToString());
3045}
3046
3047
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003048template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003049MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003050 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003051 String* subject,
3052 JSRegExp* regexp,
3053 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003054 ASSERT(subject->IsFlat());
3055
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003056 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003057
3058 Handle<String> subject_handle(subject);
3059 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003060
3061 // Shortcut for simple non-regexp global replacements
3062 if (regexp_handle->GetFlags().is_global() &&
3063 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3064 Handle<String> empty_string_handle(HEAP->empty_string());
3065 if (subject_handle->HasOnlyAsciiChars()) {
3066 return StringReplaceStringWithString<SeqAsciiString>(
3067 isolate, subject_handle, regexp_handle, empty_string_handle);
3068 } else {
3069 return StringReplaceStringWithString<SeqTwoByteString>(
3070 isolate, subject_handle, regexp_handle, empty_string_handle);
3071 }
3072 }
3073
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003074 Handle<JSArray> last_match_info_handle(last_match_info);
3075 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3076 subject_handle,
3077 0,
3078 last_match_info_handle);
3079 if (match.is_null()) return Failure::Exception();
3080 if (match->IsNull()) return *subject_handle;
3081
3082 ASSERT(last_match_info_handle->HasFastElements());
3083
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003084 int start, end;
3085 {
3086 AssertNoAllocation match_info_array_is_not_in_a_handle;
3087 FixedArray* match_info_array =
3088 FixedArray::cast(last_match_info_handle->elements());
3089
3090 start = RegExpImpl::GetCapture(match_info_array, 0);
3091 end = RegExpImpl::GetCapture(match_info_array, 1);
3092 }
3093
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003094 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003095 int new_length = length - (end - start);
3096 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003097 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003098 }
3099 Handle<ResultSeqString> answer;
3100 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003101 answer = Handle<ResultSeqString>::cast(
3102 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003103 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003104 answer = Handle<ResultSeqString>::cast(
3105 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003106 }
3107
3108 // If the regexp isn't global, only match once.
3109 if (!regexp_handle->GetFlags().is_global()) {
3110 if (start > 0) {
3111 String::WriteToFlat(*subject_handle,
3112 answer->GetChars(),
3113 0,
3114 start);
3115 }
3116 if (end < length) {
3117 String::WriteToFlat(*subject_handle,
3118 answer->GetChars() + start,
3119 end,
3120 length);
3121 }
3122 return *answer;
3123 }
3124
3125 int prev = 0; // Index of end of last match.
3126 int next = 0; // Start of next search (prev unless last match was empty).
3127 int position = 0;
3128
3129 do {
3130 if (prev < start) {
3131 // Add substring subject[prev;start] to answer string.
3132 String::WriteToFlat(*subject_handle,
3133 answer->GetChars() + position,
3134 prev,
3135 start);
3136 position += start - prev;
3137 }
3138 prev = end;
3139 next = end;
3140 // Continue from where the match ended, unless it was an empty match.
3141 if (start == end) {
3142 next++;
3143 if (next > length) break;
3144 }
3145 match = RegExpImpl::Exec(regexp_handle,
3146 subject_handle,
3147 next,
3148 last_match_info_handle);
3149 if (match.is_null()) return Failure::Exception();
3150 if (match->IsNull()) break;
3151
3152 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003153 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003154 {
3155 AssertNoAllocation match_info_array_is_not_in_a_handle;
3156 FixedArray* match_info_array =
3157 FixedArray::cast(last_match_info_handle->elements());
3158 start = RegExpImpl::GetCapture(match_info_array, 0);
3159 end = RegExpImpl::GetCapture(match_info_array, 1);
3160 }
3161 } while (true);
3162
3163 if (prev < length) {
3164 // Add substring subject[prev;length] to answer string.
3165 String::WriteToFlat(*subject_handle,
3166 answer->GetChars() + position,
3167 prev,
3168 length);
3169 position += length - prev;
3170 }
3171
3172 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003173 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003174 }
3175
3176 // Shorten string and fill
3177 int string_size = ResultSeqString::SizeFor(position);
3178 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3179 int delta = allocated_string_size - string_size;
3180
3181 answer->set_length(position);
3182 if (delta == 0) return *answer;
3183
3184 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003185 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003186 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3187 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3188 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003189
3190 return *answer;
3191}
3192
3193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003194RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003195 ASSERT(args.length() == 4);
3196
3197 CONVERT_CHECKED(String, subject, args[0]);
3198 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003199 Object* flat_subject;
3200 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3201 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3202 return maybe_flat_subject;
3203 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003204 }
3205 subject = String::cast(flat_subject);
3206 }
3207
3208 CONVERT_CHECKED(String, replacement, args[2]);
3209 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003210 Object* flat_replacement;
3211 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3212 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3213 return maybe_flat_replacement;
3214 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003215 }
3216 replacement = String::cast(flat_replacement);
3217 }
3218
3219 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3220 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3221
3222 ASSERT(last_match_info->HasFastElements());
3223
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003224 if (replacement->length() == 0) {
3225 if (subject->HasOnlyAsciiChars()) {
3226 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003227 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003228 } else {
3229 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003230 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003231 }
3232 }
3233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003234 return StringReplaceRegExpWithString(isolate,
3235 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003236 regexp,
3237 replacement,
3238 last_match_info);
3239}
3240
3241
ager@chromium.org7c537e22008-10-16 08:43:32 +00003242// Perform string match of pattern on subject, starting at start index.
3243// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003244// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003245int Runtime::StringMatch(Isolate* isolate,
3246 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003247 Handle<String> pat,
3248 int start_index) {
3249 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003250 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003251
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003252 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003253 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003254
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003255 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003256 if (start_index + pattern_length > subject_length) return -1;
3257
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003258 if (!sub->IsFlat()) FlattenString(sub);
3259 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003260
ager@chromium.org7c537e22008-10-16 08:43:32 +00003261 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003262 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003263 String::FlatContent seq_sub = sub->GetFlatContent();
3264 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003265
ager@chromium.org7c537e22008-10-16 08:43:32 +00003266 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003267 if (seq_pat.IsAscii()) {
3268 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3269 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003270 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003271 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003272 pat_vector,
3273 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003274 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003275 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003276 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003277 pat_vector,
3278 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003279 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003280 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3281 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003282 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003283 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 pat_vector,
3285 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003286 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003287 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003288 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003289 pat_vector,
3290 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003291}
3292
3293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003294RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003295 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003296 ASSERT(args.length() == 3);
3297
ager@chromium.org7c537e22008-10-16 08:43:32 +00003298 CONVERT_ARG_CHECKED(String, sub, 0);
3299 CONVERT_ARG_CHECKED(String, pat, 1);
3300
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003301 Object* index = args[2];
3302 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003303 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003304
ager@chromium.org870a0b62008-11-04 11:43:05 +00003305 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003306 int position =
3307 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003308 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003309}
3310
3311
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003312template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003313static int StringMatchBackwards(Vector<const schar> subject,
3314 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003315 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003316 int pattern_length = pattern.length();
3317 ASSERT(pattern_length >= 1);
3318 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003319
3320 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003321 for (int i = 0; i < pattern_length; i++) {
3322 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003323 if (c > String::kMaxAsciiCharCode) {
3324 return -1;
3325 }
3326 }
3327 }
3328
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003329 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003330 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003331 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003332 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003333 while (j < pattern_length) {
3334 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003335 break;
3336 }
3337 j++;
3338 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003339 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003340 return i;
3341 }
3342 }
3343 return -1;
3344}
3345
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003346RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003347 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 ASSERT(args.length() == 3);
3349
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003350 CONVERT_ARG_CHECKED(String, sub, 0);
3351 CONVERT_ARG_CHECKED(String, pat, 1);
3352
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003354 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003355 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003356
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003357 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003358 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003359
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003360 if (start_index + pat_length > sub_length) {
3361 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003362 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003364 if (pat_length == 0) {
3365 return Smi::FromInt(start_index);
3366 }
3367
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003368 if (!sub->IsFlat()) FlattenString(sub);
3369 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003370
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003371 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003372 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3373
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 String::FlatContent sub_content = sub->GetFlatContent();
3375 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003376
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003377 if (pat_content.IsAscii()) {
3378 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3379 if (sub_content.IsAscii()) {
3380 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003381 pat_vector,
3382 start_index);
3383 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003384 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003385 pat_vector,
3386 start_index);
3387 }
3388 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003389 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3390 if (sub_content.IsAscii()) {
3391 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003392 pat_vector,
3393 start_index);
3394 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003395 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003396 pat_vector,
3397 start_index);
3398 }
3399 }
3400
3401 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402}
3403
3404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003405RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003406 NoHandleAllocation ha;
3407 ASSERT(args.length() == 2);
3408
3409 CONVERT_CHECKED(String, str1, args[0]);
3410 CONVERT_CHECKED(String, str2, args[1]);
3411
3412 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003413 int str1_length = str1->length();
3414 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415
3416 // Decide trivial cases without flattening.
3417 if (str1_length == 0) {
3418 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3419 return Smi::FromInt(-str2_length);
3420 } else {
3421 if (str2_length == 0) return Smi::FromInt(str1_length);
3422 }
3423
3424 int end = str1_length < str2_length ? str1_length : str2_length;
3425
3426 // No need to flatten if we are going to find the answer on the first
3427 // character. At this point we know there is at least one character
3428 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003429 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003430 if (d != 0) return Smi::FromInt(d);
3431
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003432 str1->TryFlatten();
3433 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003435 StringInputBuffer& buf1 =
3436 *isolate->runtime_state()->string_locale_compare_buf1();
3437 StringInputBuffer& buf2 =
3438 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003439
3440 buf1.Reset(str1);
3441 buf2.Reset(str2);
3442
3443 for (int i = 0; i < end; i++) {
3444 uint16_t char1 = buf1.GetNext();
3445 uint16_t char2 = buf2.GetNext();
3446 if (char1 != char2) return Smi::FromInt(char1 - char2);
3447 }
3448
3449 return Smi::FromInt(str1_length - str2_length);
3450}
3451
3452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003453RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454 NoHandleAllocation ha;
3455 ASSERT(args.length() == 3);
3456
3457 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003458 int start, end;
3459 // We have a fast integer-only case here to avoid a conversion to double in
3460 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003461 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3462 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3463 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3464 start = from_number;
3465 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003466 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003467 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3468 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003469 start = FastD2I(from_number);
3470 end = FastD2I(to_number);
3471 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472 RUNTIME_ASSERT(end >= start);
3473 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003474 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003475 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003476 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003477}
3478
3479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003480RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003481 ASSERT_EQ(3, args.length());
3482
3483 CONVERT_ARG_CHECKED(String, subject, 0);
3484 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3485 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3486 HandleScope handles;
3487
3488 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3489
3490 if (match.is_null()) {
3491 return Failure::Exception();
3492 }
3493 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003494 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003495 }
3496 int length = subject->length();
3497
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003498 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003499 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003500 int start;
3501 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003502 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003503 {
3504 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003505 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003506 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3507 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3508 }
3509 offsets.Add(start);
3510 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003511 if (start == end) if (++end > length) break;
3512 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003513 if (match.is_null()) {
3514 return Failure::Exception();
3515 }
3516 } while (!match->IsNull());
3517 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003518 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003519 Handle<String> substring = isolate->factory()->
3520 NewSubString(subject, offsets.at(0), offsets.at(1));
3521 elements->set(0, *substring);
3522 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003523 int from = offsets.at(i * 2);
3524 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003525 Handle<String> substring = isolate->factory()->
3526 NewProperSubString(subject, from, to);
3527 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003528 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003529 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003530 result->set_length(Smi::FromInt(matches));
3531 return *result;
3532}
3533
3534
lrn@chromium.org25156de2010-04-06 13:10:27 +00003535// Two smis before and after the match, for very long strings.
3536const int kMaxBuilderEntriesPerRegExpMatch = 5;
3537
3538
3539static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3540 Handle<JSArray> last_match_info,
3541 int match_start,
3542 int match_end) {
3543 // Fill last_match_info with a single capture.
3544 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3545 AssertNoAllocation no_gc;
3546 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3547 RegExpImpl::SetLastCaptureCount(elements, 2);
3548 RegExpImpl::SetLastInput(elements, *subject);
3549 RegExpImpl::SetLastSubject(elements, *subject);
3550 RegExpImpl::SetCapture(elements, 0, match_start);
3551 RegExpImpl::SetCapture(elements, 1, match_end);
3552}
3553
3554
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003555template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003556static bool SearchStringMultiple(Isolate* isolate,
3557 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003558 Vector<const PatternChar> pattern,
3559 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003560 FixedArrayBuilder* builder,
3561 int* match_pos) {
3562 int pos = *match_pos;
3563 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003564 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003565 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003567 while (pos <= max_search_start) {
3568 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3569 *match_pos = pos;
3570 return false;
3571 }
3572 // Position of end of previous match.
3573 int match_end = pos + pattern_length;
3574 int new_pos = search.Search(subject, match_end);
3575 if (new_pos >= 0) {
3576 // A match.
3577 if (new_pos > match_end) {
3578 ReplacementStringBuilder::AddSubjectSlice(builder,
3579 match_end,
3580 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003581 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003582 pos = new_pos;
3583 builder->Add(pattern_string);
3584 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003585 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003586 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003587 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003588
lrn@chromium.org25156de2010-04-06 13:10:27 +00003589 if (pos < max_search_start) {
3590 ReplacementStringBuilder::AddSubjectSlice(builder,
3591 pos + pattern_length,
3592 subject_length);
3593 }
3594 *match_pos = pos;
3595 return true;
3596}
3597
3598
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003599static bool SearchStringMultiple(Isolate* isolate,
3600 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003601 Handle<String> pattern,
3602 Handle<JSArray> last_match_info,
3603 FixedArrayBuilder* builder) {
3604 ASSERT(subject->IsFlat());
3605 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003606
3607 // Treating as if a previous match was before first character.
3608 int match_pos = -pattern->length();
3609
3610 for (;;) { // Break when search complete.
3611 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3612 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003613 String::FlatContent subject_content = subject->GetFlatContent();
3614 String::FlatContent pattern_content = pattern->GetFlatContent();
3615 if (subject_content.IsAscii()) {
3616 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3617 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003618 if (SearchStringMultiple(isolate,
3619 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003620 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003621 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003622 builder,
3623 &match_pos)) break;
3624 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 if (SearchStringMultiple(isolate,
3626 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003627 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003628 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003629 builder,
3630 &match_pos)) break;
3631 }
3632 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003633 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3634 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003635 if (SearchStringMultiple(isolate,
3636 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003637 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003638 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003639 builder,
3640 &match_pos)) break;
3641 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003642 if (SearchStringMultiple(isolate,
3643 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003644 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003645 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003646 builder,
3647 &match_pos)) break;
3648 }
3649 }
3650 }
3651
3652 if (match_pos >= 0) {
3653 SetLastMatchInfoNoCaptures(subject,
3654 last_match_info,
3655 match_pos,
3656 match_pos + pattern->length());
3657 return true;
3658 }
3659 return false; // No matches at all.
3660}
3661
3662
3663static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003664 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003665 Handle<String> subject,
3666 Handle<JSRegExp> regexp,
3667 Handle<JSArray> last_match_array,
3668 FixedArrayBuilder* builder) {
3669 ASSERT(subject->IsFlat());
3670 int match_start = -1;
3671 int match_end = 0;
3672 int pos = 0;
3673 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3674 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3675
3676 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003677 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003678 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003679 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003680
3681 for (;;) { // Break on failure, return on exception.
3682 RegExpImpl::IrregexpResult result =
3683 RegExpImpl::IrregexpExecOnce(regexp,
3684 subject,
3685 pos,
3686 register_vector);
3687 if (result == RegExpImpl::RE_SUCCESS) {
3688 match_start = register_vector[0];
3689 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3690 if (match_end < match_start) {
3691 ReplacementStringBuilder::AddSubjectSlice(builder,
3692 match_end,
3693 match_start);
3694 }
3695 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003697 if (!first) {
3698 builder->Add(*isolate->factory()->NewProperSubString(subject,
3699 match_start,
3700 match_end));
3701 } else {
3702 builder->Add(*isolate->factory()->NewSubString(subject,
3703 match_start,
3704 match_end));
3705 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003706 if (match_start != match_end) {
3707 pos = match_end;
3708 } else {
3709 pos = match_end + 1;
3710 if (pos > subject_length) break;
3711 }
3712 } else if (result == RegExpImpl::RE_FAILURE) {
3713 break;
3714 } else {
3715 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3716 return result;
3717 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003718 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003719 }
3720
3721 if (match_start >= 0) {
3722 if (match_end < subject_length) {
3723 ReplacementStringBuilder::AddSubjectSlice(builder,
3724 match_end,
3725 subject_length);
3726 }
3727 SetLastMatchInfoNoCaptures(subject,
3728 last_match_array,
3729 match_start,
3730 match_end);
3731 return RegExpImpl::RE_SUCCESS;
3732 } else {
3733 return RegExpImpl::RE_FAILURE; // No matches at all.
3734 }
3735}
3736
3737
3738static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003739 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003740 Handle<String> subject,
3741 Handle<JSRegExp> regexp,
3742 Handle<JSArray> last_match_array,
3743 FixedArrayBuilder* builder) {
3744
3745 ASSERT(subject->IsFlat());
3746 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3747 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3748
3749 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003750 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003751
3752 RegExpImpl::IrregexpResult result =
3753 RegExpImpl::IrregexpExecOnce(regexp,
3754 subject,
3755 0,
3756 register_vector);
3757
3758 int capture_count = regexp->CaptureCount();
3759 int subject_length = subject->length();
3760
3761 // Position to search from.
3762 int pos = 0;
3763 // End of previous match. Differs from pos if match was empty.
3764 int match_end = 0;
3765 if (result == RegExpImpl::RE_SUCCESS) {
3766 // Need to keep a copy of the previous match for creating last_match_info
3767 // at the end, so we have two vectors that we swap between.
3768 OffsetsVector registers2(required_registers);
3769 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003770 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003771 do {
3772 int match_start = register_vector[0];
3773 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3774 if (match_end < match_start) {
3775 ReplacementStringBuilder::AddSubjectSlice(builder,
3776 match_end,
3777 match_start);
3778 }
3779 match_end = register_vector[1];
3780
3781 {
3782 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003783 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003784 // Arguments array to replace function is match, captures, index and
3785 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003786 Handle<FixedArray> elements =
3787 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003788 Handle<String> match;
3789 if (!first) {
3790 match = isolate->factory()->NewProperSubString(subject,
3791 match_start,
3792 match_end);
3793 } else {
3794 match = isolate->factory()->NewSubString(subject,
3795 match_start,
3796 match_end);
3797 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003798 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003799 for (int i = 1; i <= capture_count; i++) {
3800 int start = register_vector[i * 2];
3801 if (start >= 0) {
3802 int end = register_vector[i * 2 + 1];
3803 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003804 Handle<String> substring;
3805 if (!first) {
3806 substring = isolate->factory()->NewProperSubString(subject,
3807 start,
3808 end);
3809 } else {
3810 substring = isolate->factory()->NewSubString(subject, start, end);
3811 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003812 elements->set(i, *substring);
3813 } else {
3814 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003815 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003816 }
3817 }
3818 elements->set(capture_count + 1, Smi::FromInt(match_start));
3819 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003820 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003821 }
3822 // Swap register vectors, so the last successful match is in
3823 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003824 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003825 prev_register_vector = register_vector;
3826 register_vector = tmp;
3827
3828 if (match_end > match_start) {
3829 pos = match_end;
3830 } else {
3831 pos = match_end + 1;
3832 if (pos > subject_length) {
3833 break;
3834 }
3835 }
3836
3837 result = RegExpImpl::IrregexpExecOnce(regexp,
3838 subject,
3839 pos,
3840 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003841 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003842 } while (result == RegExpImpl::RE_SUCCESS);
3843
3844 if (result != RegExpImpl::RE_EXCEPTION) {
3845 // Finished matching, with at least one match.
3846 if (match_end < subject_length) {
3847 ReplacementStringBuilder::AddSubjectSlice(builder,
3848 match_end,
3849 subject_length);
3850 }
3851
3852 int last_match_capture_count = (capture_count + 1) * 2;
3853 int last_match_array_size =
3854 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3855 last_match_array->EnsureSize(last_match_array_size);
3856 AssertNoAllocation no_gc;
3857 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3858 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3859 RegExpImpl::SetLastSubject(elements, *subject);
3860 RegExpImpl::SetLastInput(elements, *subject);
3861 for (int i = 0; i < last_match_capture_count; i++) {
3862 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3863 }
3864 return RegExpImpl::RE_SUCCESS;
3865 }
3866 }
3867 // No matches at all, return failure or exception result directly.
3868 return result;
3869}
3870
3871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003872RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003873 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003874 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003875
3876 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003877 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003878 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3879 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3880 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3881
3882 ASSERT(last_match_info->HasFastElements());
3883 ASSERT(regexp->GetFlags().is_global());
3884 Handle<FixedArray> result_elements;
3885 if (result_array->HasFastElements()) {
3886 result_elements =
3887 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003888 }
3889 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003890 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003891 }
3892 FixedArrayBuilder builder(result_elements);
3893
3894 if (regexp->TypeTag() == JSRegExp::ATOM) {
3895 Handle<String> pattern(
3896 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003897 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003898 if (SearchStringMultiple(isolate, subject, pattern,
3899 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003900 return *builder.ToJSArray(result_array);
3901 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003902 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003903 }
3904
3905 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3906
3907 RegExpImpl::IrregexpResult result;
3908 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003909 result = SearchRegExpNoCaptureMultiple(isolate,
3910 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003911 regexp,
3912 last_match_info,
3913 &builder);
3914 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003915 result = SearchRegExpMultiple(isolate,
3916 subject,
3917 regexp,
3918 last_match_info,
3919 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003920 }
3921 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003922 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3924 return Failure::Exception();
3925}
3926
3927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003928RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003929 NoHandleAllocation ha;
3930 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003931 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003932 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003934 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003935 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003936 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003937 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003938 // Character array used for conversion.
3939 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003940 return isolate->heap()->
3941 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003942 }
3943 }
3944
3945 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003946 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003947 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003948 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 }
3950 if (isinf(value)) {
3951 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003952 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003953 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003954 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003955 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003957 MaybeObject* result =
3958 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959 DeleteArray(str);
3960 return result;
3961}
3962
3963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003964RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 NoHandleAllocation ha;
3966 ASSERT(args.length() == 2);
3967
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003968 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003970 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 }
3972 if (isinf(value)) {
3973 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003974 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003976 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003978 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 int f = FastD2I(f_number);
3980 RUNTIME_ASSERT(f >= 0);
3981 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003982 MaybeObject* res =
3983 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003985 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986}
3987
3988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003989RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990 NoHandleAllocation ha;
3991 ASSERT(args.length() == 2);
3992
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003993 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003994 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003995 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003996 }
3997 if (isinf(value)) {
3998 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003999 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004001 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004002 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004003 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004 int f = FastD2I(f_number);
4005 RUNTIME_ASSERT(f >= -1 && f <= 20);
4006 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 MaybeObject* res =
4008 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004010 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011}
4012
4013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004014RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 NoHandleAllocation ha;
4016 ASSERT(args.length() == 2);
4017
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004018 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004020 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 }
4022 if (isinf(value)) {
4023 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004024 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004025 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004026 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004028 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 int f = FastD2I(f_number);
4030 RUNTIME_ASSERT(f >= 1 && f <= 21);
4031 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004032 MaybeObject* res =
4033 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004034 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004035 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036}
4037
4038
4039// Returns a single character string where first character equals
4040// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004041static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004042 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004043 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004044 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004045 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004047 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048}
4049
4050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004051MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4052 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004053 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 // Handle [] indexing on Strings
4055 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004056 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4057 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004058 }
4059
4060 // Handle [] indexing on String objects
4061 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004062 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4063 Handle<Object> result =
4064 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4065 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 }
4067
4068 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004069 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004070 return prototype->GetElement(index);
4071 }
4072
4073 return object->GetElement(index);
4074}
4075
4076
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004077MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4078 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004079 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004081
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004083 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004085 isolate->factory()->NewTypeError("non_object_property_load",
4086 HandleVector(args, 2));
4087 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 }
4089
4090 // Check if the given key is an array index.
4091 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004092 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004093 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 }
4095
4096 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004097 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004099 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 bool has_pending_exception = false;
4102 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004103 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004104 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004105 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106 }
4107
ager@chromium.org32912102009-01-16 10:38:43 +00004108 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 // the element if so.
4110 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004111 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004113 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 }
4115}
4116
4117
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004118RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 NoHandleAllocation ha;
4120 ASSERT(args.length() == 2);
4121
4122 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004123 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004125 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126}
4127
4128
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004129MaybeObject* TransitionElements(Handle<Object> object,
4130 ElementsKind to_kind,
4131 Isolate* isolate) {
4132 HandleScope scope(isolate);
4133 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4134 ElementsKind from_kind =
4135 Handle<JSObject>::cast(object)->map()->elements_kind();
4136 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
4137 Handle<Object> result =
4138 TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
4139 if (result.is_null()) return isolate->ThrowIllegalOperation();
4140 return *result;
4141 }
4142 return isolate->ThrowIllegalOperation();
4143}
4144
4145
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004146// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004147RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004148 NoHandleAllocation ha;
4149 ASSERT(args.length() == 2);
4150
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004151 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004152 // itself.
4153 //
4154 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004155 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004156 // global proxy object never has properties. This is the case
4157 // because the global proxy object forwards everything to its hidden
4158 // prototype including local lookups.
4159 //
4160 // Additionally, we need to make sure that we do not cache results
4161 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004162 if (args[0]->IsJSObject()) {
4163 if (!args[0]->IsJSGlobalProxy() &&
4164 !args[0]->IsAccessCheckNeeded() &&
4165 args[1]->IsString()) {
4166 JSObject* receiver = JSObject::cast(args[0]);
4167 String* key = String::cast(args[1]);
4168 if (receiver->HasFastProperties()) {
4169 // Attempt to use lookup cache.
4170 Map* receiver_map = receiver->map();
4171 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4172 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4173 if (offset != -1) {
4174 Object* value = receiver->FastPropertyAt(offset);
4175 return value->IsTheHole()
4176 ? isolate->heap()->undefined_value()
4177 : value;
4178 }
4179 // Lookup cache miss. Perform lookup and update the cache if
4180 // appropriate.
4181 LookupResult result(isolate);
4182 receiver->LocalLookup(key, &result);
4183 if (result.IsProperty() && result.type() == FIELD) {
4184 int offset = result.GetFieldIndex();
4185 keyed_lookup_cache->Update(receiver_map, key, offset);
4186 return receiver->FastPropertyAt(offset);
4187 }
4188 } else {
4189 // Attempt dictionary lookup.
4190 StringDictionary* dictionary = receiver->property_dictionary();
4191 int entry = dictionary->FindEntry(key);
4192 if ((entry != StringDictionary::kNotFound) &&
4193 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4194 Object* value = dictionary->ValueAt(entry);
4195 if (!receiver->IsGlobalObject()) return value;
4196 value = JSGlobalPropertyCell::cast(value)->value();
4197 if (!value->IsTheHole()) return value;
4198 // If value is the hole do the general lookup.
4199 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004200 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004201 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4202 // JSObject without a string key. If the key is a Smi, check for a
4203 // definite out-of-bounds access to elements, which is a strong indicator
4204 // that subsequent accesses will also call the runtime. Proactively
4205 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4206 // doubles for those future calls in the case that the elements would
4207 // become FAST_DOUBLE_ELEMENTS.
4208 Handle<JSObject> js_object(args.at<JSObject>(0));
4209 ElementsKind elements_kind = js_object->GetElementsKind();
4210 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4211 elements_kind == FAST_DOUBLE_ELEMENTS) {
4212 FixedArrayBase* elements = js_object->elements();
4213 if (args.at<Smi>(1)->value() >= elements->length()) {
4214 MaybeObject* maybe_object = TransitionElements(js_object,
4215 FAST_ELEMENTS,
4216 isolate);
4217 if (maybe_object->IsFailure()) return maybe_object;
4218 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004219 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004220 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004221 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4222 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004223 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004224 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004225 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004226 if (index >= 0 && index < str->length()) {
4227 Handle<Object> result = GetCharAt(str, index);
4228 return *result;
4229 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004230 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004231
4232 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004233 return Runtime::GetObjectProperty(isolate,
4234 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004235 args.at<Object>(1));
4236}
4237
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004238// Implements part of 8.12.9 DefineOwnProperty.
4239// There are 3 cases that lead here:
4240// Step 4b - define a new accessor property.
4241// Steps 9c & 12 - replace an existing data property with an accessor property.
4242// Step 12 - update an existing accessor property with an accessor or generic
4243// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004244RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004245 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004246 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004247 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4248 CONVERT_CHECKED(String, name, args[1]);
4249 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004250 Object* fun = args[3];
ager@chromium.org5c838252010-02-19 08:53:10 +00004251 CONVERT_CHECKED(Smi, flag_attr, args[4]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004252
ager@chromium.org5c838252010-02-19 08:53:10 +00004253 int unchecked = flag_attr->value();
4254 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004255 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004256
4257 RUNTIME_ASSERT(!obj->IsNull());
4258 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004259 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4260}
4261
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004262// Implements part of 8.12.9 DefineOwnProperty.
4263// There are 3 cases that lead here:
4264// Step 4a - define a new data property.
4265// Steps 9b & 12 - replace an existing accessor property with a data property.
4266// Step 12 - update an existing data property with a data or generic
4267// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004268RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004269 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004270 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004271 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4272 CONVERT_ARG_CHECKED(String, name, 1);
4273 Handle<Object> obj_value = args.at<Object>(2);
ager@chromium.org5c838252010-02-19 08:53:10 +00004274 CONVERT_CHECKED(Smi, flag, args[3]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004275
ager@chromium.org5c838252010-02-19 08:53:10 +00004276 int unchecked = flag->value();
4277 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004278 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4279
4280 // Check if this is an element.
4281 uint32_t index;
4282 bool is_element = name->AsArrayIndex(&index);
4283
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004284 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004285 // If elements are in fast case we always implicitly assume that:
4286 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004287 if (is_element && (attr != NONE ||
4288 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004289 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004290 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004291 // We do not need to do access checks here since these has already
4292 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004293 Handle<Object> proto(js_object->GetPrototype());
4294 // If proxy is detached, ignore the assignment. Alternatively,
4295 // we could throw an exception.
4296 if (proto->IsNull()) return *obj_value;
4297 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004298 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004299
4300 // Don't allow element properties to be redefined on objects with external
4301 // array elements.
4302 if (js_object->HasExternalArrayElements()) {
4303 Handle<Object> args[2] = { js_object, name };
4304 Handle<Object> error =
4305 isolate->factory()->NewTypeError("redef_external_array_element",
4306 HandleVector(args, 2));
4307 return isolate->Throw(*error);
4308 }
4309
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004310 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004311 // Make sure that we never go back to fast case.
4312 dictionary->set_requires_slow_elements();
4313 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004314 Handle<NumberDictionary> extended_dictionary =
4315 NumberDictionarySet(dictionary, index, obj_value, details);
4316 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004317 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004318 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4319 } else {
4320 js_object->set_elements(*extended_dictionary);
4321 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004322 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004323 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004324 }
4325
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004326 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004327 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004328
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004329 // Special case for callback properties.
4330 if (result.IsProperty() && result.type() == CALLBACKS) {
4331 Object* callback = result.GetCallbackObject();
4332 // To be compatible with Safari we do not change the value on API objects
4333 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4334 // the value.
4335 if (callback->IsAccessorInfo()) {
4336 return isolate->heap()->undefined_value();
4337 }
4338 // Avoid redefining foreign callback as data property, just use the stored
4339 // setter to update the value instead.
4340 // TODO(mstarzinger): So far this only works if property attributes don't
4341 // change, this should be fixed once we cleanup the underlying code.
4342 if (callback->IsForeign() && result.GetAttributes() == attr) {
4343 return js_object->SetPropertyWithCallback(callback,
4344 *name,
4345 *obj_value,
4346 result.holder(),
4347 kStrictMode);
4348 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004349 }
4350
ager@chromium.org5c838252010-02-19 08:53:10 +00004351 // Take special care when attributes are different and there is already
4352 // a property. For simplicity we normalize the property which enables us
4353 // to not worry about changing the instance_descriptor and creating a new
4354 // map. The current version of SetObjectProperty does not handle attributes
4355 // correctly in the case where a property is a field and is reset with
4356 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004357 if (result.IsProperty() &&
4358 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004359 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004360 if (js_object->IsJSGlobalProxy()) {
4361 // Since the result is a property, the prototype will exist so
4362 // we don't have to check for null.
4363 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004364 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004365 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004366 // Use IgnoreAttributes version since a readonly property may be
4367 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004368 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4369 *obj_value,
4370 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004371 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004372
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004373 return Runtime::ForceSetObjectProperty(isolate,
4374 js_object,
4375 name,
4376 obj_value,
4377 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004378}
4379
4380
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004381// Special case for elements if any of the flags are true.
4382// If elements are in fast case we always implicitly assume that:
4383// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4384static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4385 Handle<JSObject> js_object,
4386 uint32_t index,
4387 Handle<Object> value,
4388 PropertyAttributes attr) {
4389 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004390 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004391 // Make sure that we never go back to fast case.
4392 dictionary->set_requires_slow_elements();
4393 PropertyDetails details = PropertyDetails(attr, NORMAL);
4394 Handle<NumberDictionary> extended_dictionary =
4395 NumberDictionarySet(dictionary, index, value, details);
4396 if (*extended_dictionary != *dictionary) {
4397 js_object->set_elements(*extended_dictionary);
4398 }
4399 return *value;
4400}
4401
4402
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004403MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4404 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004405 Handle<Object> key,
4406 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004407 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004408 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004409 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004410
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004411 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004412 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004413 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004414 isolate->factory()->NewTypeError("non_object_property_store",
4415 HandleVector(args, 2));
4416 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004417 }
4418
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004419 if (object->IsJSProxy()) {
4420 bool has_pending_exception = false;
4421 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4422 if (has_pending_exception) return Failure::Exception();
4423 return JSProxy::cast(*object)->SetProperty(
4424 String::cast(*name), *value, attr, strict_mode);
4425 }
4426
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004427 // If the object isn't a JavaScript object, we ignore the store.
4428 if (!object->IsJSObject()) return *value;
4429
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004430 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4431
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004432 // Check if the given key is an array index.
4433 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004434 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004435 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4436 // of a string using [] notation. We need to support this too in
4437 // JavaScript.
4438 // In the case of a String object we just need to redirect the assignment to
4439 // the underlying string if the index is in range. Since the underlying
4440 // string does nothing with the assignment then we can ignore such
4441 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004442 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004443 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004444 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004445
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004446 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4447 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4448 }
4449
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004450 Handle<Object> result = SetElement(js_object, index, value, strict_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)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004458 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4459 return NormalizeObjectSetElement(isolate,
4460 js_object,
4461 index,
4462 value,
4463 attr);
4464 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004465 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004466 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004467 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004468 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004469 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004470 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004471 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472 return *value;
4473 }
4474
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004475 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004476 bool has_pending_exception = false;
4477 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4478 if (has_pending_exception) return Failure::Exception();
4479 Handle<String> name = Handle<String>::cast(converted);
4480
4481 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004482 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004484 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 }
4486}
4487
4488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004489MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4490 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004491 Handle<Object> key,
4492 Handle<Object> value,
4493 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004494 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004495
4496 // Check if the given key is an array index.
4497 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004498 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004499 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4500 // of a string using [] notation. We need to support this too in
4501 // JavaScript.
4502 // In the case of a String object we just need to redirect the assignment to
4503 // the underlying string if the index is in range. Since the underlying
4504 // string does nothing with the assignment then we can ignore such
4505 // assignments.
4506 if (js_object->IsStringObjectWithCharacterAt(index)) {
4507 return *value;
4508 }
4509
whesse@chromium.org7b260152011-06-20 15:33:18 +00004510 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004511 }
4512
4513 if (key->IsString()) {
4514 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004515 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004516 } else {
4517 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004518 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004519 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4520 *value,
4521 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004522 }
4523 }
4524
4525 // Call-back into JavaScript to convert the key to a string.
4526 bool has_pending_exception = false;
4527 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4528 if (has_pending_exception) return Failure::Exception();
4529 Handle<String> name = Handle<String>::cast(converted);
4530
4531 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004532 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004533 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004534 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004535 }
4536}
4537
4538
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004539MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004540 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004541 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004542 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004543
4544 // Check if the given key is an array index.
4545 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004546 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004547 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4548 // characters of a string using [] notation. In the case of a
4549 // String object we just need to redirect the deletion to the
4550 // underlying string if the index is in range. Since the
4551 // underlying string does nothing with the deletion, we can ignore
4552 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004553 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004554 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004555 }
4556
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004557 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004558 }
4559
4560 Handle<String> key_string;
4561 if (key->IsString()) {
4562 key_string = Handle<String>::cast(key);
4563 } else {
4564 // Call-back into JavaScript to convert the key to a string.
4565 bool has_pending_exception = false;
4566 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4567 if (has_pending_exception) return Failure::Exception();
4568 key_string = Handle<String>::cast(converted);
4569 }
4570
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004571 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004572 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004573}
4574
4575
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004576RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004577 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004578 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579
4580 Handle<Object> object = args.at<Object>(0);
4581 Handle<Object> key = args.at<Object>(1);
4582 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004583 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004584 RUNTIME_ASSERT(
4585 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004587 PropertyAttributes attributes =
4588 static_cast<PropertyAttributes>(unchecked_attributes);
4589
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004590 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004591 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004592 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4593 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004595
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004596 return Runtime::SetObjectProperty(isolate,
4597 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004598 key,
4599 value,
4600 attributes,
4601 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004602}
4603
4604
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004605RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4606 NoHandleAllocation ha;
4607 RUNTIME_ASSERT(args.length() == 1);
4608 Handle<Object> object = args.at<Object>(0);
4609 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4610}
4611
4612
4613RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4614 NoHandleAllocation ha;
4615 RUNTIME_ASSERT(args.length() == 1);
4616 Handle<Object> object = args.at<Object>(0);
4617 return TransitionElements(object, FAST_ELEMENTS, isolate);
4618}
4619
4620
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004621// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004622// This is used to decide if we should transform null and undefined
4623// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004624RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004625 NoHandleAllocation ha;
4626 RUNTIME_ASSERT(args.length() == 1);
4627
4628 Handle<Object> object = args.at<Object>(0);
4629
4630 if (object->IsJSFunction()) {
4631 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004632 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004633 }
4634 return isolate->heap()->undefined_value();
4635}
4636
4637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004638RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4639 RUNTIME_ASSERT(args.length() == 5);
4640 CONVERT_ARG_CHECKED(JSObject, object, 0);
4641 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4642 Handle<Object> value = args.at<Object>(2);
4643 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4644 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4645 HandleScope scope;
4646
4647 Object* raw_boilerplate_object = literals->get(literal_index);
4648 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4649#if DEBUG
4650 ElementsKind elements_kind = object->GetElementsKind();
4651#endif
4652 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4653 // Smis should never trigger transitions.
4654 ASSERT(!value->IsSmi());
4655
4656 if (value->IsNumber()) {
4657 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
4658 TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004659 TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004660 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4661 FixedDoubleArray* double_array =
4662 FixedDoubleArray::cast(object->elements());
4663 HeapNumber* number = HeapNumber::cast(*value);
4664 double_array->set(store_index, number->Number());
4665 } else {
4666 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4667 elements_kind == FAST_DOUBLE_ELEMENTS);
4668 TransitionElementsKind(object, FAST_ELEMENTS);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004669 TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004670 FixedArray* object_array =
4671 FixedArray::cast(object->elements());
4672 object_array->set(store_index, *value);
4673 }
4674 return *object;
4675}
4676
4677
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004678// Set a local property, even if it is READ_ONLY. If the property does not
4679// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004680RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004682 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683 CONVERT_CHECKED(JSObject, object, args[0]);
4684 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004685 // Compute attributes.
4686 PropertyAttributes attributes = NONE;
4687 if (args.length() == 4) {
4688 CONVERT_CHECKED(Smi, value_obj, args[3]);
4689 int unchecked_value = value_obj->value();
4690 // Only attribute bits should be set.
4691 RUNTIME_ASSERT(
4692 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4693 attributes = static_cast<PropertyAttributes>(unchecked_value);
4694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004696 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004697 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004698}
4699
4700
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004701RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004703 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004704
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004705 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004706 CONVERT_CHECKED(String, key, args[1]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004707 CONVERT_STRICT_MODE_ARG(strict_mode, 2);
4708 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004709 ? JSReceiver::STRICT_DELETION
4710 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711}
4712
4713
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004714static Object* HasLocalPropertyImplementation(Isolate* isolate,
4715 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004716 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004717 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004718 // Handle hidden prototypes. If there's a hidden prototype above this thing
4719 // then we have to check it for properties, because they are supposed to
4720 // look like they are on this object.
4721 Handle<Object> proto(object->GetPrototype());
4722 if (proto->IsJSObject() &&
4723 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004724 return HasLocalPropertyImplementation(isolate,
4725 Handle<JSObject>::cast(proto),
4726 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004727 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004728 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004729}
4730
4731
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004732RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004733 NoHandleAllocation ha;
4734 ASSERT(args.length() == 2);
4735 CONVERT_CHECKED(String, key, args[1]);
4736
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004737 uint32_t index;
4738 const bool key_is_array_index = key->AsArrayIndex(&index);
4739
ager@chromium.org9085a012009-05-11 19:22:57 +00004740 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004741 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004742 if (obj->IsJSObject()) {
4743 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004744 // Fast case: either the key is a real named property or it is not
4745 // an array index and there are no interceptors or hidden
4746 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004747 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004748 Map* map = object->map();
4749 if (!key_is_array_index &&
4750 !map->has_named_interceptor() &&
4751 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4752 return isolate->heap()->false_value();
4753 }
4754 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 HandleScope scope(isolate);
4756 return HasLocalPropertyImplementation(isolate,
4757 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004758 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004759 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004761 String* string = String::cast(obj);
4762 if (index < static_cast<uint32_t>(string->length())) {
4763 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 }
4765 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004766 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004767}
4768
4769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004770RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004771 NoHandleAllocation na;
4772 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004773 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4774 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004776 bool result = receiver->HasProperty(key);
4777 if (isolate->has_pending_exception()) return Failure::Exception();
4778 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779}
4780
4781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004782RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004783 NoHandleAllocation na;
4784 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004785 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4786 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004788 bool result = receiver->HasElement(index->value());
4789 if (isolate->has_pending_exception()) return Failure::Exception();
4790 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791}
4792
4793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004794RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795 NoHandleAllocation ha;
4796 ASSERT(args.length() == 2);
4797
4798 CONVERT_CHECKED(JSObject, object, args[0]);
4799 CONVERT_CHECKED(String, key, args[1]);
4800
4801 uint32_t index;
4802 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004803 JSObject::LocalElementType type = object->HasLocalElement(index);
4804 switch (type) {
4805 case JSObject::UNDEFINED_ELEMENT:
4806 case JSObject::STRING_CHARACTER_ELEMENT:
4807 return isolate->heap()->false_value();
4808 case JSObject::INTERCEPTED_ELEMENT:
4809 case JSObject::FAST_ELEMENT:
4810 return isolate->heap()->true_value();
4811 case JSObject::DICTIONARY_ELEMENT: {
4812 if (object->IsJSGlobalProxy()) {
4813 Object* proto = object->GetPrototype();
4814 if (proto->IsNull()) {
4815 return isolate->heap()->false_value();
4816 }
4817 ASSERT(proto->IsJSGlobalObject());
4818 object = JSObject::cast(proto);
4819 }
4820 FixedArray* elements = FixedArray::cast(object->elements());
4821 NumberDictionary* dictionary = NULL;
4822 if (elements->map() ==
4823 isolate->heap()->non_strict_arguments_elements_map()) {
4824 dictionary = NumberDictionary::cast(elements->get(1));
4825 } else {
4826 dictionary = NumberDictionary::cast(elements);
4827 }
4828 int entry = dictionary->FindEntry(index);
4829 ASSERT(entry != NumberDictionary::kNotFound);
4830 PropertyDetails details = dictionary->DetailsAt(entry);
4831 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4832 }
4833 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004834 }
4835
ager@chromium.org870a0b62008-11-04 11:43:05 +00004836 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004837 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838}
4839
4840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004841RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004842 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004844 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4845 bool threw = false;
4846 Handle<JSArray> result = GetKeysFor(object, &threw);
4847 if (threw) return Failure::Exception();
4848 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004849}
4850
4851
4852// Returns either a FixedArray as Runtime_GetPropertyNames,
4853// or, if the given object has an enum cache that contains
4854// all enumerable properties of the object and its prototypes
4855// have none, the map of the object. This is used to speed up
4856// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004857RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858 ASSERT(args.length() == 1);
4859
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004860 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861
4862 if (raw_object->IsSimpleEnum()) return raw_object->map();
4863
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004864 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004865 Handle<JSReceiver> object(raw_object);
4866 bool threw = false;
4867 Handle<FixedArray> content =
4868 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4869 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870
4871 // Test again, since cache may have been built by preceding call.
4872 if (object->IsSimpleEnum()) return object->map();
4873
4874 return *content;
4875}
4876
4877
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004878// Find the length of the prototype chain that is to to handled as one. If a
4879// prototype object is hidden it is to be viewed as part of the the object it
4880// is prototype for.
4881static int LocalPrototypeChainLength(JSObject* obj) {
4882 int count = 1;
4883 Object* proto = obj->GetPrototype();
4884 while (proto->IsJSObject() &&
4885 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4886 count++;
4887 proto = JSObject::cast(proto)->GetPrototype();
4888 }
4889 return count;
4890}
4891
4892
4893// Return the names of the local named properties.
4894// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004895RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004896 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004897 ASSERT(args.length() == 1);
4898 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004899 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004900 }
4901 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4902
4903 // Skip the global proxy as it has no properties and always delegates to the
4904 // real global object.
4905 if (obj->IsJSGlobalProxy()) {
4906 // Only collect names if access is permitted.
4907 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004908 !isolate->MayNamedAccess(*obj,
4909 isolate->heap()->undefined_value(),
4910 v8::ACCESS_KEYS)) {
4911 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4912 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004913 }
4914 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4915 }
4916
4917 // Find the number of objects making up this.
4918 int length = LocalPrototypeChainLength(*obj);
4919
4920 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004921 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004922 int total_property_count = 0;
4923 Handle<JSObject> jsproto = obj;
4924 for (int i = 0; i < length; i++) {
4925 // Only collect names if access is permitted.
4926 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004927 !isolate->MayNamedAccess(*jsproto,
4928 isolate->heap()->undefined_value(),
4929 v8::ACCESS_KEYS)) {
4930 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4931 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004932 }
4933 int n;
4934 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4935 local_property_count[i] = n;
4936 total_property_count += n;
4937 if (i < length - 1) {
4938 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4939 }
4940 }
4941
4942 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004943 Handle<FixedArray> names =
4944 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004945
4946 // Get the property names.
4947 jsproto = obj;
4948 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004949 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004950 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004951 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4952 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004953 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004954 proto_with_hidden_properties++;
4955 }
4956 if (i < length - 1) {
4957 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4958 }
4959 }
4960
4961 // Filter out name of hidden propeties object.
4962 if (proto_with_hidden_properties > 0) {
4963 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004964 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004965 names->length() - proto_with_hidden_properties);
4966 int dest_pos = 0;
4967 for (int i = 0; i < total_property_count; i++) {
4968 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004969 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004970 continue;
4971 }
4972 names->set(dest_pos++, name);
4973 }
4974 }
4975
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004976 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004977}
4978
4979
4980// Return the names of the local indexed properties.
4981// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004982RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004983 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004984 ASSERT(args.length() == 1);
4985 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004986 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004987 }
4988 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4989
4990 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004991 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004992 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004993 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004994}
4995
4996
4997// Return information on whether an object has a named or indexed interceptor.
4998// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004999RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005000 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005001 ASSERT(args.length() == 1);
5002 if (!args[0]->IsJSObject()) {
5003 return Smi::FromInt(0);
5004 }
5005 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5006
5007 int result = 0;
5008 if (obj->HasNamedInterceptor()) result |= 2;
5009 if (obj->HasIndexedInterceptor()) result |= 1;
5010
5011 return Smi::FromInt(result);
5012}
5013
5014
5015// Return property names from named interceptor.
5016// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005017RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005018 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005019 ASSERT(args.length() == 1);
5020 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5021
5022 if (obj->HasNamedInterceptor()) {
5023 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5024 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5025 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005026 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005027}
5028
5029
5030// Return element names from indexed interceptor.
5031// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005032RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005033 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005034 ASSERT(args.length() == 1);
5035 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5036
5037 if (obj->HasIndexedInterceptor()) {
5038 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5039 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5040 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005041 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005042}
5043
5044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005045RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005046 ASSERT_EQ(args.length(), 1);
5047 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005048 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005049 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005050
5051 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005052 // Do access checks before going to the global object.
5053 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005054 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005055 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005056 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5057 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005058 }
5059
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005060 Handle<Object> proto(object->GetPrototype());
5061 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005062 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005063 object = Handle<JSObject>::cast(proto);
5064 }
5065
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005066 bool threw = false;
5067 Handle<FixedArray> contents =
5068 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5069 if (threw) return Failure::Exception();
5070
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005071 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5072 // property array and since the result is mutable we have to create
5073 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005074 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005075 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005076 for (int i = 0; i < length; i++) {
5077 Object* entry = contents->get(i);
5078 if (entry->IsString()) {
5079 copy->set(i, entry);
5080 } else {
5081 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005082 HandleScope scope(isolate);
5083 Handle<Object> entry_handle(entry, isolate);
5084 Handle<Object> entry_str =
5085 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005086 copy->set(i, *entry_str);
5087 }
5088 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005089 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005090}
5091
5092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005093RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005094 NoHandleAllocation ha;
5095 ASSERT(args.length() == 1);
5096
5097 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005098 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005099 it.AdvanceToArgumentsFrame();
5100 JavaScriptFrame* frame = it.frame();
5101
5102 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005103 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005104
5105 // Try to convert the key to an index. If successful and within
5106 // index return the the argument from the frame.
5107 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005108 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005109 return frame->GetParameter(index);
5110 }
5111
5112 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005113 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005114 bool exception = false;
5115 Handle<Object> converted =
5116 Execution::ToString(args.at<Object>(0), &exception);
5117 if (exception) return Failure::Exception();
5118 Handle<String> key = Handle<String>::cast(converted);
5119
5120 // Try to convert the string key into an array index.
5121 if (key->AsArrayIndex(&index)) {
5122 if (index < n) {
5123 return frame->GetParameter(index);
5124 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005125 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005126 }
5127 }
5128
5129 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005130 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5131 if (key->Equals(isolate->heap()->callee_symbol())) {
5132 Object* function = frame->function();
5133 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005134 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005135 return isolate->Throw(*isolate->factory()->NewTypeError(
5136 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5137 }
5138 return function;
5139 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005140
5141 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005142 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005143}
5144
5145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005146RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005147 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005148
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005149 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005150 Handle<Object> object = args.at<Object>(0);
5151 if (object->IsJSObject()) {
5152 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005153 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005154 MaybeObject* ok = js_object->TransformToFastProperties(0);
5155 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005156 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005157 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005158 return *object;
5159}
5160
5161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005162RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005163 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005164
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005165 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005166 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005167 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005168 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005169 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005170 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005171 return *object;
5172}
5173
5174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005175RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005176 NoHandleAllocation ha;
5177 ASSERT(args.length() == 1);
5178
5179 return args[0]->ToBoolean();
5180}
5181
5182
5183// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5184// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005185RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005186 NoHandleAllocation ha;
5187
5188 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005189 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005190 HeapObject* heap_obj = HeapObject::cast(obj);
5191
5192 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005193 if (heap_obj->map()->is_undetectable()) {
5194 return isolate->heap()->undefined_symbol();
5195 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196
5197 InstanceType instance_type = heap_obj->map()->instance_type();
5198 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005199 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005200 }
5201
5202 switch (instance_type) {
5203 case ODDBALL_TYPE:
5204 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005205 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 }
5207 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005208 return FLAG_harmony_typeof
5209 ? isolate->heap()->null_symbol()
5210 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005211 }
5212 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005213 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005214 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005215 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005216 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005217 default:
5218 // For any kind of object not handled above, the spec rule for
5219 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005220 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005221 }
5222}
5223
5224
lrn@chromium.org25156de2010-04-06 13:10:27 +00005225static bool AreDigits(const char*s, int from, int to) {
5226 for (int i = from; i < to; i++) {
5227 if (s[i] < '0' || s[i] > '9') return false;
5228 }
5229
5230 return true;
5231}
5232
5233
5234static int ParseDecimalInteger(const char*s, int from, int to) {
5235 ASSERT(to - from < 10); // Overflow is not possible.
5236 ASSERT(from < to);
5237 int d = s[from] - '0';
5238
5239 for (int i = from + 1; i < to; i++) {
5240 d = 10 * d + (s[i] - '0');
5241 }
5242
5243 return d;
5244}
5245
5246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005247RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248 NoHandleAllocation ha;
5249 ASSERT(args.length() == 1);
5250 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005251 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005252
5253 // Fast case: short integer or some sorts of junk values.
5254 int len = subject->length();
5255 if (subject->IsSeqAsciiString()) {
5256 if (len == 0) return Smi::FromInt(0);
5257
5258 char const* data = SeqAsciiString::cast(subject)->GetChars();
5259 bool minus = (data[0] == '-');
5260 int start_pos = (minus ? 1 : 0);
5261
5262 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005263 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005264 } else if (data[start_pos] > '9') {
5265 // Fast check for a junk value. A valid string may start from a
5266 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5267 // the 'I' character ('Infinity'). All of that have codes not greater than
5268 // '9' except 'I'.
5269 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005270 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005271 }
5272 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5273 // The maximal/minimal smi has 10 digits. If the string has less digits we
5274 // know it will fit into the smi-data type.
5275 int d = ParseDecimalInteger(data, start_pos, len);
5276 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005277 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005278 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005279 } else if (!subject->HasHashCode() &&
5280 len <= String::kMaxArrayIndexSize &&
5281 (len == 1 || data[0] != '0')) {
5282 // String hash is not calculated yet but all the data are present.
5283 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005284 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005285#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005286 subject->Hash(); // Force hash calculation.
5287 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5288 static_cast<int>(hash));
5289#endif
5290 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005291 }
5292 return Smi::FromInt(d);
5293 }
5294 }
5295
5296 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005297 return isolate->heap()->NumberFromDouble(
5298 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005299}
5300
5301
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005302RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005303 NoHandleAllocation ha;
5304 ASSERT(args.length() == 1);
5305
5306 CONVERT_CHECKED(JSArray, codes, args[0]);
5307 int length = Smi::cast(codes->length())->value();
5308
5309 // Check if the string can be ASCII.
5310 int i;
5311 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005312 Object* element;
5313 { MaybeObject* maybe_element = codes->GetElement(i);
5314 // We probably can't get an exception here, but just in order to enforce
5315 // the checking of inputs in the runtime calls we check here.
5316 if (!maybe_element->ToObject(&element)) return maybe_element;
5317 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005318 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5319 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5320 break;
5321 }
5322
lrn@chromium.org303ada72010-10-27 09:33:13 +00005323 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005324 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005325 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005326 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005327 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005328 }
5329
lrn@chromium.org303ada72010-10-27 09:33:13 +00005330 Object* object = NULL;
5331 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005332 String* result = String::cast(object);
5333 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005334 Object* element;
5335 { MaybeObject* maybe_element = codes->GetElement(i);
5336 if (!maybe_element->ToObject(&element)) return maybe_element;
5337 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005338 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005339 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340 }
5341 return result;
5342}
5343
5344
5345// kNotEscaped is generated by the following:
5346//
5347// #!/bin/perl
5348// for (my $i = 0; $i < 256; $i++) {
5349// print "\n" if $i % 16 == 0;
5350// my $c = chr($i);
5351// my $escaped = 1;
5352// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5353// print $escaped ? "0, " : "1, ";
5354// }
5355
5356
5357static bool IsNotEscaped(uint16_t character) {
5358 // Only for 8 bit characters, the rest are always escaped (in a different way)
5359 ASSERT(character < 256);
5360 static const char kNotEscaped[256] = {
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, 1, 1, 0, 1, 1, 1,
5364 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5365 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5366 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5367 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5368 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5377 };
5378 return kNotEscaped[character] != 0;
5379}
5380
5381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005382RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005383 const char hex_chars[] = "0123456789ABCDEF";
5384 NoHandleAllocation ha;
5385 ASSERT(args.length() == 1);
5386 CONVERT_CHECKED(String, source, args[0]);
5387
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005388 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005389
5390 int escaped_length = 0;
5391 int length = source->length();
5392 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005393 Access<StringInputBuffer> buffer(
5394 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 buffer->Reset(source);
5396 while (buffer->has_more()) {
5397 uint16_t character = buffer->GetNext();
5398 if (character >= 256) {
5399 escaped_length += 6;
5400 } else if (IsNotEscaped(character)) {
5401 escaped_length++;
5402 } else {
5403 escaped_length += 3;
5404 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005405 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005406 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005407 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005408 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409 return Failure::OutOfMemoryException();
5410 }
5411 }
5412 }
5413 // No length change implies no change. Return original string if no change.
5414 if (escaped_length == length) {
5415 return source;
5416 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005417 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005418 { MaybeObject* maybe_o =
5419 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005420 if (!maybe_o->ToObject(&o)) return maybe_o;
5421 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005422 String* destination = String::cast(o);
5423 int dest_position = 0;
5424
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005425 Access<StringInputBuffer> buffer(
5426 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005427 buffer->Rewind();
5428 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005429 uint16_t chr = buffer->GetNext();
5430 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005431 destination->Set(dest_position, '%');
5432 destination->Set(dest_position+1, 'u');
5433 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5434 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5435 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5436 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005437 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005438 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005440 dest_position++;
5441 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005442 destination->Set(dest_position, '%');
5443 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5444 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005445 dest_position += 3;
5446 }
5447 }
5448 return destination;
5449}
5450
5451
5452static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5453 static const signed char kHexValue['g'] = {
5454 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5455 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5456 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5457 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5458 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5459 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5460 -1, 10, 11, 12, 13, 14, 15 };
5461
5462 if (character1 > 'f') return -1;
5463 int hi = kHexValue[character1];
5464 if (hi == -1) return -1;
5465 if (character2 > 'f') return -1;
5466 int lo = kHexValue[character2];
5467 if (lo == -1) return -1;
5468 return (hi << 4) + lo;
5469}
5470
5471
ager@chromium.org870a0b62008-11-04 11:43:05 +00005472static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005473 int i,
5474 int length,
5475 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005476 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005477 int32_t hi = 0;
5478 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 if (character == '%' &&
5480 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005481 source->Get(i + 1) == 'u' &&
5482 (hi = TwoDigitHex(source->Get(i + 2),
5483 source->Get(i + 3))) != -1 &&
5484 (lo = TwoDigitHex(source->Get(i + 4),
5485 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005486 *step = 6;
5487 return (hi << 8) + lo;
5488 } else if (character == '%' &&
5489 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005490 (lo = TwoDigitHex(source->Get(i + 1),
5491 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492 *step = 3;
5493 return lo;
5494 } else {
5495 *step = 1;
5496 return character;
5497 }
5498}
5499
5500
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005501RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005502 NoHandleAllocation ha;
5503 ASSERT(args.length() == 1);
5504 CONVERT_CHECKED(String, source, args[0]);
5505
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005506 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507
5508 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005509 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005510
5511 int unescaped_length = 0;
5512 for (int i = 0; i < length; unescaped_length++) {
5513 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005514 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005516 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005517 i += step;
5518 }
5519
5520 // No length change implies no change. Return original string if no change.
5521 if (unescaped_length == length)
5522 return source;
5523
lrn@chromium.org303ada72010-10-27 09:33:13 +00005524 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005525 { MaybeObject* maybe_o =
5526 ascii ?
5527 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5528 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005529 if (!maybe_o->ToObject(&o)) return maybe_o;
5530 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005531 String* destination = String::cast(o);
5532
5533 int dest_position = 0;
5534 for (int i = 0; i < length; dest_position++) {
5535 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005536 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005537 i += step;
5538 }
5539 return destination;
5540}
5541
5542
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005543static const unsigned int kQuoteTableLength = 128u;
5544
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005545static const int kJsonQuotesCharactersPerEntry = 8;
5546static const char* const JsonQuotes =
5547 "\\u0000 \\u0001 \\u0002 \\u0003 "
5548 "\\u0004 \\u0005 \\u0006 \\u0007 "
5549 "\\b \\t \\n \\u000b "
5550 "\\f \\r \\u000e \\u000f "
5551 "\\u0010 \\u0011 \\u0012 \\u0013 "
5552 "\\u0014 \\u0015 \\u0016 \\u0017 "
5553 "\\u0018 \\u0019 \\u001a \\u001b "
5554 "\\u001c \\u001d \\u001e \\u001f "
5555 " ! \\\" # "
5556 "$ % & ' "
5557 "( ) * + "
5558 ", - . / "
5559 "0 1 2 3 "
5560 "4 5 6 7 "
5561 "8 9 : ; "
5562 "< = > ? "
5563 "@ A B C "
5564 "D E F G "
5565 "H I J K "
5566 "L M N O "
5567 "P Q R S "
5568 "T U V W "
5569 "X Y Z [ "
5570 "\\\\ ] ^ _ "
5571 "` a b c "
5572 "d e f g "
5573 "h i j k "
5574 "l m n o "
5575 "p q r s "
5576 "t u v w "
5577 "x y z { "
5578 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005579
5580
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005581// For a string that is less than 32k characters it should always be
5582// possible to allocate it in new space.
5583static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5584
5585
5586// Doing JSON quoting cannot make the string more than this many times larger.
5587static const int kJsonQuoteWorstCaseBlowup = 6;
5588
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005589static const int kSpaceForQuotesAndComma = 3;
5590static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005591
5592// Covers the entire ASCII range (all other characters are unchanged by JSON
5593// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005594static const byte JsonQuoteLengths[kQuoteTableLength] = {
5595 6, 6, 6, 6, 6, 6, 6, 6,
5596 2, 2, 2, 6, 2, 2, 6, 6,
5597 6, 6, 6, 6, 6, 6, 6, 6,
5598 6, 6, 6, 6, 6, 6, 6, 6,
5599 1, 1, 2, 1, 1, 1, 1, 1,
5600 1, 1, 1, 1, 1, 1, 1, 1,
5601 1, 1, 1, 1, 1, 1, 1, 1,
5602 1, 1, 1, 1, 1, 1, 1, 1,
5603 1, 1, 1, 1, 1, 1, 1, 1,
5604 1, 1, 1, 1, 1, 1, 1, 1,
5605 1, 1, 1, 1, 1, 1, 1, 1,
5606 1, 1, 1, 1, 2, 1, 1, 1,
5607 1, 1, 1, 1, 1, 1, 1, 1,
5608 1, 1, 1, 1, 1, 1, 1, 1,
5609 1, 1, 1, 1, 1, 1, 1, 1,
5610 1, 1, 1, 1, 1, 1, 1, 1,
5611};
5612
5613
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005614template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005615MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005616
5617
5618template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005619MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5620 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005621}
5622
5623
5624template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005625MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5626 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005627}
5628
5629
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005630template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005631static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5632 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005633 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005634 const Char* read_cursor = characters.start();
5635 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005636 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005637 int quoted_length = kSpaceForQuotes;
5638 while (read_cursor < end) {
5639 Char c = *(read_cursor++);
5640 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5641 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005642 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005643 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005644 }
5645 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005646 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5647 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005648 Object* new_object;
5649 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005650 return new_alloc;
5651 }
5652 StringType* new_string = StringType::cast(new_object);
5653
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005654 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005655 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005656 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005657 *(write_cursor++) = '"';
5658
5659 read_cursor = characters.start();
5660 while (read_cursor < end) {
5661 Char c = *(read_cursor++);
5662 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5663 *(write_cursor++) = c;
5664 } else {
5665 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5666 const char* replacement = JsonQuotes +
5667 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5668 for (int i = 0; i < len; i++) {
5669 *write_cursor++ = *replacement++;
5670 }
5671 }
5672 }
5673 *(write_cursor++) = '"';
5674 return new_string;
5675}
5676
5677
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005678template <typename SinkChar, typename SourceChar>
5679static inline SinkChar* WriteQuoteJsonString(
5680 Isolate* isolate,
5681 SinkChar* write_cursor,
5682 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005683 // SinkChar is only char if SourceChar is guaranteed to be char.
5684 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005685 const SourceChar* read_cursor = characters.start();
5686 const SourceChar* end = read_cursor + characters.length();
5687 *(write_cursor++) = '"';
5688 while (read_cursor < end) {
5689 SourceChar c = *(read_cursor++);
5690 if (sizeof(SourceChar) > 1u &&
5691 static_cast<unsigned>(c) >= kQuoteTableLength) {
5692 *(write_cursor++) = static_cast<SinkChar>(c);
5693 } else {
5694 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5695 const char* replacement = JsonQuotes +
5696 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5697 write_cursor[0] = replacement[0];
5698 if (len > 1) {
5699 write_cursor[1] = replacement[1];
5700 if (len > 2) {
5701 ASSERT(len == 6);
5702 write_cursor[2] = replacement[2];
5703 write_cursor[3] = replacement[3];
5704 write_cursor[4] = replacement[4];
5705 write_cursor[5] = replacement[5];
5706 }
5707 }
5708 write_cursor += len;
5709 }
5710 }
5711 *(write_cursor++) = '"';
5712 return write_cursor;
5713}
5714
5715
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005716template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005717static MaybeObject* QuoteJsonString(Isolate* isolate,
5718 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005719 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005720 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005721 int worst_case_length =
5722 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005723 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005724 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005725 }
5726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005727 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5728 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005729 Object* new_object;
5730 if (!new_alloc->ToObject(&new_object)) {
5731 return new_alloc;
5732 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005733 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005734 // Even if our string is small enough to fit in new space we still have to
5735 // handle it being allocated in old space as may happen in the third
5736 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5737 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005738 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005739 }
5740 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005741 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005742
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005743 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005744 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005745 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005746 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5747 write_cursor,
5748 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005749 int final_length = static_cast<int>(
5750 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005751 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005752 isolate->heap()->new_space()->
5753 template ShrinkStringAtAllocationBoundary<StringType>(
5754 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005755 return new_string;
5756}
5757
5758
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005759RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005760 NoHandleAllocation ha;
5761 CONVERT_CHECKED(String, str, args[0]);
5762 if (!str->IsFlat()) {
5763 MaybeObject* try_flatten = str->TryFlatten();
5764 Object* flat;
5765 if (!try_flatten->ToObject(&flat)) {
5766 return try_flatten;
5767 }
5768 str = String::cast(flat);
5769 ASSERT(str->IsFlat());
5770 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005771 String::FlatContent flat = str->GetFlatContent();
5772 ASSERT(flat.IsFlat());
5773 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005774 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005775 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005776 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005777 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005778 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005779 }
5780}
5781
5782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005783RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005784 NoHandleAllocation ha;
5785 CONVERT_CHECKED(String, str, args[0]);
5786 if (!str->IsFlat()) {
5787 MaybeObject* try_flatten = str->TryFlatten();
5788 Object* flat;
5789 if (!try_flatten->ToObject(&flat)) {
5790 return try_flatten;
5791 }
5792 str = String::cast(flat);
5793 ASSERT(str->IsFlat());
5794 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005795 String::FlatContent flat = str->GetFlatContent();
5796 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005797 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005798 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005799 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005800 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005801 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005802 }
5803}
5804
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005805
5806template <typename Char, typename StringType>
5807static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5808 FixedArray* array,
5809 int worst_case_length) {
5810 int length = array->length();
5811
5812 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5813 worst_case_length);
5814 Object* new_object;
5815 if (!new_alloc->ToObject(&new_object)) {
5816 return new_alloc;
5817 }
5818 if (!isolate->heap()->new_space()->Contains(new_object)) {
5819 // Even if our string is small enough to fit in new space we still have to
5820 // handle it being allocated in old space as may happen in the third
5821 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5822 // CEntryStub::GenerateCore.
5823 return isolate->heap()->undefined_value();
5824 }
5825 AssertNoAllocation no_gc;
5826 StringType* new_string = StringType::cast(new_object);
5827 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5828
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005829 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005830 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005831 *(write_cursor++) = '[';
5832 for (int i = 0; i < length; i++) {
5833 if (i != 0) *(write_cursor++) = ',';
5834 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005835 String::FlatContent content = str->GetFlatContent();
5836 ASSERT(content.IsFlat());
5837 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005838 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5839 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005840 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005841 } else {
5842 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5843 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005844 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005845 }
5846 }
5847 *(write_cursor++) = ']';
5848
5849 int final_length = static_cast<int>(
5850 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005851 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005852 isolate->heap()->new_space()->
5853 template ShrinkStringAtAllocationBoundary<StringType>(
5854 new_string, final_length);
5855 return new_string;
5856}
5857
5858
5859RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5860 NoHandleAllocation ha;
5861 ASSERT(args.length() == 1);
5862 CONVERT_CHECKED(JSArray, array, args[0]);
5863
5864 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5865 FixedArray* elements = FixedArray::cast(array->elements());
5866 int n = elements->length();
5867 bool ascii = true;
5868 int total_length = 0;
5869
5870 for (int i = 0; i < n; i++) {
5871 Object* elt = elements->get(i);
5872 if (!elt->IsString()) return isolate->heap()->undefined_value();
5873 String* element = String::cast(elt);
5874 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5875 total_length += element->length();
5876 if (ascii && element->IsTwoByteRepresentation()) {
5877 ascii = false;
5878 }
5879 }
5880
5881 int worst_case_length =
5882 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5883 + total_length * kJsonQuoteWorstCaseBlowup;
5884
5885 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5886 return isolate->heap()->undefined_value();
5887 }
5888
5889 if (ascii) {
5890 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5891 elements,
5892 worst_case_length);
5893 } else {
5894 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5895 elements,
5896 worst_case_length);
5897 }
5898}
5899
5900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005901RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005902 NoHandleAllocation ha;
5903
5904 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005905 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005906
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005907 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005908
lrn@chromium.org25156de2010-04-06 13:10:27 +00005909 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005910 double value = StringToInt(isolate->unicode_cache(), s, radix);
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
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916 NoHandleAllocation ha;
5917 CONVERT_CHECKED(String, str, args[0]);
5918
5919 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005920 double value = StringToDouble(isolate->unicode_cache(),
5921 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922
5923 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005924 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005925}
5926
5927
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005929MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005930 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005931 String* s,
5932 int length,
5933 int input_string_length,
5934 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005935 // We try this twice, once with the assumption that the result is no longer
5936 // than the input and, if that assumption breaks, again with the exact
5937 // length. This may not be pretty, but it is nicer than what was here before
5938 // and I hereby claim my vaffel-is.
5939 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940 // Allocate the resulting string.
5941 //
5942 // NOTE: This assumes that the upper/lower case of an ascii
5943 // character is also ascii. This is currently the case, but it
5944 // might break in the future if we implement more context and locale
5945 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005946 Object* o;
5947 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005948 ? isolate->heap()->AllocateRawAsciiString(length)
5949 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005950 if (!maybe_o->ToObject(&o)) return maybe_o;
5951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005952 String* result = String::cast(o);
5953 bool has_changed_character = false;
5954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005955 // Convert all characters to upper case, assuming that they will fit
5956 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005957 Access<StringInputBuffer> buffer(
5958 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005960 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005961 // We can assume that the string is not empty
5962 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005963 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005964 bool has_next = buffer->has_more();
5965 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005966 int char_length = mapping->get(current, next, chars);
5967 if (char_length == 0) {
5968 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005969 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005970 i++;
5971 } else if (char_length == 1) {
5972 // Common case: converting the letter resulted in one character.
5973 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005974 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975 has_changed_character = true;
5976 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005977 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005978 // We've assumed that the result would be as long as the
5979 // input but here is a character that converts to several
5980 // characters. No matter, we calculate the exact length
5981 // of the result and try the whole thing again.
5982 //
5983 // Note that this leaves room for optimization. We could just
5984 // memcpy what we already have to the result string. Also,
5985 // the result string is the last object allocated we could
5986 // "realloc" it and probably, in the vast majority of cases,
5987 // extend the existing string to be able to hold the full
5988 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005989 int next_length = 0;
5990 if (has_next) {
5991 next_length = mapping->get(next, 0, chars);
5992 if (next_length == 0) next_length = 1;
5993 }
5994 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 while (buffer->has_more()) {
5996 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005997 // NOTE: we use 0 as the next character here because, while
5998 // the next character may affect what a character converts to,
5999 // it does not in any case affect the length of what it convert
6000 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001 int char_length = mapping->get(current, 0, chars);
6002 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006003 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006004 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006005 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006006 return Failure::OutOfMemoryException();
6007 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006009 // Try again with the real length.
6010 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006011 } else {
6012 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006013 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006014 i++;
6015 }
6016 has_changed_character = true;
6017 }
6018 current = next;
6019 }
6020 if (has_changed_character) {
6021 return result;
6022 } else {
6023 // If we didn't actually change anything in doing the conversion
6024 // we simple return the result and let the converted string
6025 // become garbage; there is no reason to keep two identical strings
6026 // alive.
6027 return s;
6028 }
6029}
6030
6031
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006032namespace {
6033
lrn@chromium.org303ada72010-10-27 09:33:13 +00006034static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6035
6036
6037// Given a word and two range boundaries returns a word with high bit
6038// set in every byte iff the corresponding input byte was strictly in
6039// the range (m, n). All the other bits in the result are cleared.
6040// This function is only useful when it can be inlined and the
6041// boundaries are statically known.
6042// Requires: all bytes in the input word and the boundaries must be
6043// ascii (less than 0x7F).
6044static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6045 // Every byte in an ascii string is less than or equal to 0x7F.
6046 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6047 // Use strict inequalities since in edge cases the function could be
6048 // further simplified.
6049 ASSERT(0 < m && m < n && n < 0x7F);
6050 // Has high bit set in every w byte less than n.
6051 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6052 // Has high bit set in every w byte greater than m.
6053 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6054 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6055}
6056
6057
6058enum AsciiCaseConversion {
6059 ASCII_TO_LOWER,
6060 ASCII_TO_UPPER
6061};
6062
6063
6064template <AsciiCaseConversion dir>
6065struct FastAsciiConverter {
6066 static bool Convert(char* dst, char* src, int length) {
6067#ifdef DEBUG
6068 char* saved_dst = dst;
6069 char* saved_src = src;
6070#endif
6071 // We rely on the distance between upper and lower case letters
6072 // being a known power of 2.
6073 ASSERT('a' - 'A' == (1 << 5));
6074 // Boundaries for the range of input characters than require conversion.
6075 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6076 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6077 bool changed = false;
6078 char* const limit = src + length;
6079#ifdef V8_HOST_CAN_READ_UNALIGNED
6080 // Process the prefix of the input that requires no conversion one
6081 // (machine) word at a time.
6082 while (src <= limit - sizeof(uintptr_t)) {
6083 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6084 if (AsciiRangeMask(w, lo, hi) != 0) {
6085 changed = true;
6086 break;
6087 }
6088 *reinterpret_cast<uintptr_t*>(dst) = w;
6089 src += sizeof(uintptr_t);
6090 dst += sizeof(uintptr_t);
6091 }
6092 // Process the remainder of the input performing conversion when
6093 // required one word at a time.
6094 while (src <= limit - sizeof(uintptr_t)) {
6095 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6096 uintptr_t m = AsciiRangeMask(w, lo, hi);
6097 // The mask has high (7th) bit set in every byte that needs
6098 // conversion and we know that the distance between cases is
6099 // 1 << 5.
6100 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6101 src += sizeof(uintptr_t);
6102 dst += sizeof(uintptr_t);
6103 }
6104#endif
6105 // Process the last few bytes of the input (or the whole input if
6106 // unaligned access is not supported).
6107 while (src < limit) {
6108 char c = *src;
6109 if (lo < c && c < hi) {
6110 c ^= (1 << 5);
6111 changed = true;
6112 }
6113 *dst = c;
6114 ++src;
6115 ++dst;
6116 }
6117#ifdef DEBUG
6118 CheckConvert(saved_dst, saved_src, length, changed);
6119#endif
6120 return changed;
6121 }
6122
6123#ifdef DEBUG
6124 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6125 bool expected_changed = false;
6126 for (int i = 0; i < length; i++) {
6127 if (dst[i] == src[i]) continue;
6128 expected_changed = true;
6129 if (dir == ASCII_TO_LOWER) {
6130 ASSERT('A' <= src[i] && src[i] <= 'Z');
6131 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6132 } else {
6133 ASSERT(dir == ASCII_TO_UPPER);
6134 ASSERT('a' <= src[i] && src[i] <= 'z');
6135 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6136 }
6137 }
6138 ASSERT(expected_changed == changed);
6139 }
6140#endif
6141};
6142
6143
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006144struct ToLowerTraits {
6145 typedef unibrow::ToLowercase UnibrowConverter;
6146
lrn@chromium.org303ada72010-10-27 09:33:13 +00006147 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006148};
6149
6150
6151struct ToUpperTraits {
6152 typedef unibrow::ToUppercase UnibrowConverter;
6153
lrn@chromium.org303ada72010-10-27 09:33:13 +00006154 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006155};
6156
6157} // namespace
6158
6159
6160template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006161MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006162 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006163 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006165 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006166 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006167 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006168
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006169 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006170 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006171 if (length == 0) return s;
6172
6173 // Simpler handling of ascii strings.
6174 //
6175 // NOTE: This assumes that the upper/lower case of an ascii
6176 // character is also ascii. This is currently the case, but it
6177 // might break in the future if we implement more context and locale
6178 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006179 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006180 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006181 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006182 if (!maybe_o->ToObject(&o)) return maybe_o;
6183 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006184 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006185 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006186 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006187 return has_changed_character ? result : s;
6188 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006189
lrn@chromium.org303ada72010-10-27 09:33:13 +00006190 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006191 { MaybeObject* maybe_answer =
6192 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006193 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6194 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006195 if (answer->IsSmi()) {
6196 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006197 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006198 ConvertCaseHelper(isolate,
6199 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006200 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6201 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006202 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006203 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006204}
6205
6206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006207RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006208 return ConvertCase<ToLowerTraits>(
6209 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006210}
6211
6212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006213RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006214 return ConvertCase<ToUpperTraits>(
6215 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006216}
6217
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006218
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006219static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006220 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006221}
6222
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006224RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006225 NoHandleAllocation ha;
6226 ASSERT(args.length() == 3);
6227
6228 CONVERT_CHECKED(String, s, args[0]);
6229 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6230 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6231
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006232 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006233 int length = s->length();
6234
6235 int left = 0;
6236 if (trimLeft) {
6237 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6238 left++;
6239 }
6240 }
6241
6242 int right = length;
6243 if (trimRight) {
6244 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6245 right--;
6246 }
6247 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006248 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006249}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006250
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006251
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006252RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006253 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006254 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006255 CONVERT_ARG_CHECKED(String, subject, 0);
6256 CONVERT_ARG_CHECKED(String, pattern, 1);
6257 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6258
6259 int subject_length = subject->length();
6260 int pattern_length = pattern->length();
6261 RUNTIME_ASSERT(pattern_length > 0);
6262
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006263 if (limit == 0xffffffffu) {
6264 Handle<Object> cached_answer(StringSplitCache::Lookup(
6265 isolate->heap()->string_split_cache(),
6266 *subject,
6267 *pattern));
6268 if (*cached_answer != Smi::FromInt(0)) {
6269 Handle<JSArray> result =
6270 isolate->factory()->NewJSArrayWithElements(
6271 Handle<FixedArray>::cast(cached_answer));
6272 return *result;
6273 }
6274 }
6275
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006276 // The limit can be very large (0xffffffffu), but since the pattern
6277 // isn't empty, we can never create more parts than ~half the length
6278 // of the subject.
6279
6280 if (!subject->IsFlat()) FlattenString(subject);
6281
6282 static const int kMaxInitialListCapacity = 16;
6283
danno@chromium.org40cb8782011-05-25 07:58:50 +00006284 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006285
6286 // Find (up to limit) indices of separator and end-of-string in subject
6287 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6288 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006289 if (!pattern->IsFlat()) FlattenString(pattern);
6290
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006291 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006292
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006293 if (static_cast<uint32_t>(indices.length()) < limit) {
6294 indices.Add(subject_length);
6295 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006296
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006297 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006298
6299 // Create JSArray of substrings separated by separator.
6300 int part_count = indices.length();
6301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006302 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006303 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006304 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305 result->set_length(Smi::FromInt(part_count));
6306
6307 ASSERT(result->HasFastElements());
6308
6309 if (part_count == 1 && indices.at(0) == subject_length) {
6310 FixedArray::cast(result->elements())->set(0, *subject);
6311 return *result;
6312 }
6313
6314 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6315 int part_start = 0;
6316 for (int i = 0; i < part_count; i++) {
6317 HandleScope local_loop_handle;
6318 int part_end = indices.at(i);
6319 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006320 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006321 elements->set(i, *substring);
6322 part_start = part_end + pattern_length;
6323 }
6324
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006325 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006326 if (result->HasFastElements()) {
6327 StringSplitCache::Enter(isolate->heap(),
6328 isolate->heap()->string_split_cache(),
6329 *subject,
6330 *pattern,
6331 *elements);
6332 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006333 }
6334
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006335 return *result;
6336}
6337
6338
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006339// Copies ascii characters to the given fixed array looking up
6340// one-char strings in the cache. Gives up on the first char that is
6341// not in the cache and fills the remainder with smi zeros. Returns
6342// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006343static int CopyCachedAsciiCharsToArray(Heap* heap,
6344 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006345 FixedArray* elements,
6346 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006347 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006348 FixedArray* ascii_cache = heap->single_character_string_cache();
6349 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006350 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006351 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006352 for (i = 0; i < length; ++i) {
6353 Object* value = ascii_cache->get(chars[i]);
6354 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006355 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006356 }
6357 if (i < length) {
6358 ASSERT(Smi::FromInt(0) == 0);
6359 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6360 }
6361#ifdef DEBUG
6362 for (int j = 0; j < length; ++j) {
6363 Object* element = elements->get(j);
6364 ASSERT(element == Smi::FromInt(0) ||
6365 (element->IsString() && String::cast(element)->LooksValid()));
6366 }
6367#endif
6368 return i;
6369}
6370
6371
6372// Converts a String to JSArray.
6373// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006374RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006375 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006376 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006377 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006378 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006379
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006380 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006381 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006382
6383 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006384 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006385 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006386 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006387 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006388 { MaybeObject* maybe_obj =
6389 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006390 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6391 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006392 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006393 String::FlatContent content = s->GetFlatContent();
6394 if (content.IsAscii()) {
6395 Vector<const char> chars = content.ToAsciiVector();
6396 // Note, this will initialize all elements (not only the prefix)
6397 // to prevent GC from seeing partially initialized array.
6398 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6399 chars.start(),
6400 *elements,
6401 length);
6402 } else {
6403 MemsetPointer(elements->data_start(),
6404 isolate->heap()->undefined_value(),
6405 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006406 }
6407 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006408 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006409 }
6410 for (int i = position; i < length; ++i) {
6411 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6412 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006413 }
6414
6415#ifdef DEBUG
6416 for (int i = 0; i < length; ++i) {
6417 ASSERT(String::cast(elements->get(i))->length() == 1);
6418 }
6419#endif
6420
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006421 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006422}
6423
6424
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006425RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006426 NoHandleAllocation ha;
6427 ASSERT(args.length() == 1);
6428 CONVERT_CHECKED(String, value, args[0]);
6429 return value->ToObject();
6430}
6431
6432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006433bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006434 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006435 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006436 return char_length == 0;
6437}
6438
6439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006440RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441 NoHandleAllocation ha;
6442 ASSERT(args.length() == 1);
6443
6444 Object* number = args[0];
6445 RUNTIME_ASSERT(number->IsNumber());
6446
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006447 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006448}
6449
6450
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006451RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006452 NoHandleAllocation ha;
6453 ASSERT(args.length() == 1);
6454
6455 Object* number = args[0];
6456 RUNTIME_ASSERT(number->IsNumber());
6457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006459}
6460
6461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006462RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006463 NoHandleAllocation ha;
6464 ASSERT(args.length() == 1);
6465
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006466 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006467
6468 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6469 if (number > 0 && number <= Smi::kMaxValue) {
6470 return Smi::FromInt(static_cast<int>(number));
6471 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006472 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006473}
6474
6475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006476RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006477 NoHandleAllocation ha;
6478 ASSERT(args.length() == 1);
6479
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006480 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006481
6482 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6483 if (number > 0 && number <= Smi::kMaxValue) {
6484 return Smi::FromInt(static_cast<int>(number));
6485 }
6486
6487 double double_value = DoubleToInteger(number);
6488 // Map both -0 and +0 to +0.
6489 if (double_value == 0) double_value = 0;
6490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006491 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006492}
6493
6494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006495RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006496 NoHandleAllocation ha;
6497 ASSERT(args.length() == 1);
6498
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006499 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006500 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006501}
6502
6503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006504RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505 NoHandleAllocation ha;
6506 ASSERT(args.length() == 1);
6507
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006508 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006509
6510 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6511 if (number > 0 && number <= Smi::kMaxValue) {
6512 return Smi::FromInt(static_cast<int>(number));
6513 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515}
6516
6517
ager@chromium.org870a0b62008-11-04 11:43:05 +00006518// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6519// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006521 NoHandleAllocation ha;
6522 ASSERT(args.length() == 1);
6523
6524 Object* obj = args[0];
6525 if (obj->IsSmi()) {
6526 return obj;
6527 }
6528 if (obj->IsHeapNumber()) {
6529 double value = HeapNumber::cast(obj)->value();
6530 int int_value = FastD2I(value);
6531 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6532 return Smi::FromInt(int_value);
6533 }
6534 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006535 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006536}
6537
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006538
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006539RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006540 NoHandleAllocation ha;
6541 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006542 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006543}
6544
6545
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006546RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006547 NoHandleAllocation ha;
6548 ASSERT(args.length() == 2);
6549
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006550 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6551 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006552 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006553}
6554
6555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006556RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006557 NoHandleAllocation ha;
6558 ASSERT(args.length() == 2);
6559
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006560 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6561 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006562 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563}
6564
6565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006566RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567 NoHandleAllocation ha;
6568 ASSERT(args.length() == 2);
6569
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006570 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6571 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006572 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573}
6574
6575
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006576RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006577 NoHandleAllocation ha;
6578 ASSERT(args.length() == 1);
6579
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006580 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006581 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582}
6583
6584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006585RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006586 NoHandleAllocation ha;
6587 ASSERT(args.length() == 0);
6588
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006589 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006590}
6591
6592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006593RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594 NoHandleAllocation ha;
6595 ASSERT(args.length() == 2);
6596
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006597 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6598 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006599 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006600}
6601
6602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006603RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006604 NoHandleAllocation ha;
6605 ASSERT(args.length() == 2);
6606
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006607 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6608 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609
ager@chromium.org3811b432009-10-28 14:53:37 +00006610 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006611 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006612 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613}
6614
6615
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006616RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617 NoHandleAllocation ha;
6618 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 CONVERT_CHECKED(String, str1, args[0]);
6620 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006621 isolate->counters()->string_add_runtime()->Increment();
6622 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623}
6624
6625
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006626template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006627static inline void StringBuilderConcatHelper(String* special,
6628 sinkchar* sink,
6629 FixedArray* fixed_array,
6630 int array_length) {
6631 int position = 0;
6632 for (int i = 0; i < array_length; i++) {
6633 Object* element = fixed_array->get(i);
6634 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006635 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006636 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006637 int pos;
6638 int len;
6639 if (encoded_slice > 0) {
6640 // Position and length encoded in one smi.
6641 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6642 len = StringBuilderSubstringLength::decode(encoded_slice);
6643 } else {
6644 // Position and length encoded in two smis.
6645 Object* obj = fixed_array->get(++i);
6646 ASSERT(obj->IsSmi());
6647 pos = Smi::cast(obj)->value();
6648 len = -encoded_slice;
6649 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006650 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006651 sink + position,
6652 pos,
6653 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006654 position += len;
6655 } else {
6656 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006657 int element_length = string->length();
6658 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006659 position += element_length;
6660 }
6661 }
6662}
6663
6664
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006665RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006666 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006667 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006668 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006669 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006670 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006671 return Failure::OutOfMemoryException();
6672 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006673 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006674 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006675
6676 // This assumption is used by the slice encoding in one or two smis.
6677 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6678
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006679 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006680 if (maybe_result->IsFailure()) return maybe_result;
6681
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006682 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006683 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006684 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006685 }
6686 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006687 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006688 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006690
6691 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006692 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693 } else if (array_length == 1) {
6694 Object* first = fixed_array->get(0);
6695 if (first->IsString()) return first;
6696 }
6697
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006698 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006699 int position = 0;
6700 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006701 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702 Object* elt = fixed_array->get(i);
6703 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006704 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006705 int smi_value = Smi::cast(elt)->value();
6706 int pos;
6707 int len;
6708 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006709 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006710 pos = StringBuilderSubstringPosition::decode(smi_value);
6711 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006712 } else {
6713 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006714 len = -smi_value;
6715 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006716 i++;
6717 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006718 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006719 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006720 Object* next_smi = fixed_array->get(i);
6721 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006722 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006723 }
6724 pos = Smi::cast(next_smi)->value();
6725 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006726 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006727 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006729 ASSERT(pos >= 0);
6730 ASSERT(len >= 0);
6731 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006732 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006733 }
6734 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 } else if (elt->IsString()) {
6736 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006737 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006738 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006739 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006741 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006742 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006743 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006744 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006745 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006746 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006747 return Failure::OutOfMemoryException();
6748 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006749 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750 }
6751
6752 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006754
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006755 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006756 { MaybeObject* maybe_object =
6757 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006758 if (!maybe_object->ToObject(&object)) return maybe_object;
6759 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006760 SeqAsciiString* answer = SeqAsciiString::cast(object);
6761 StringBuilderConcatHelper(special,
6762 answer->GetChars(),
6763 fixed_array,
6764 array_length);
6765 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006766 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006767 { MaybeObject* maybe_object =
6768 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006769 if (!maybe_object->ToObject(&object)) return maybe_object;
6770 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006771 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6772 StringBuilderConcatHelper(special,
6773 answer->GetChars(),
6774 fixed_array,
6775 array_length);
6776 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006777 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006778}
6779
6780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006781RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006782 NoHandleAllocation ha;
6783 ASSERT(args.length() == 3);
6784 CONVERT_CHECKED(JSArray, array, args[0]);
6785 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006786 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006787 return Failure::OutOfMemoryException();
6788 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006789 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006790 CONVERT_CHECKED(String, separator, args[2]);
6791
6792 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006793 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006794 }
6795 FixedArray* fixed_array = FixedArray::cast(array->elements());
6796 if (fixed_array->length() < array_length) {
6797 array_length = fixed_array->length();
6798 }
6799
6800 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006801 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006802 } else if (array_length == 1) {
6803 Object* first = fixed_array->get(0);
6804 if (first->IsString()) return first;
6805 }
6806
6807 int separator_length = separator->length();
6808 int max_nof_separators =
6809 (String::kMaxLength + separator_length - 1) / separator_length;
6810 if (max_nof_separators < (array_length - 1)) {
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 int length = (array_length - 1) * separator_length;
6815 for (int i = 0; i < array_length; i++) {
6816 Object* element_obj = fixed_array->get(i);
6817 if (!element_obj->IsString()) {
6818 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006819 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006820 }
6821 String* element = String::cast(element_obj);
6822 int increment = element->length();
6823 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006824 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006825 return Failure::OutOfMemoryException();
6826 }
6827 length += increment;
6828 }
6829
6830 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006831 { MaybeObject* maybe_object =
6832 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006833 if (!maybe_object->ToObject(&object)) return maybe_object;
6834 }
6835 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6836
6837 uc16* sink = answer->GetChars();
6838#ifdef DEBUG
6839 uc16* end = sink + length;
6840#endif
6841
6842 String* first = String::cast(fixed_array->get(0));
6843 int first_length = first->length();
6844 String::WriteToFlat(first, sink, 0, first_length);
6845 sink += first_length;
6846
6847 for (int i = 1; i < array_length; i++) {
6848 ASSERT(sink + separator_length <= end);
6849 String::WriteToFlat(separator, sink, 0, separator_length);
6850 sink += separator_length;
6851
6852 String* element = String::cast(fixed_array->get(i));
6853 int element_length = element->length();
6854 ASSERT(sink + element_length <= end);
6855 String::WriteToFlat(element, sink, 0, element_length);
6856 sink += element_length;
6857 }
6858 ASSERT(sink == end);
6859
6860 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6861 return answer;
6862}
6863
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006864template <typename Char>
6865static void JoinSparseArrayWithSeparator(FixedArray* elements,
6866 int elements_length,
6867 uint32_t array_length,
6868 String* separator,
6869 Vector<Char> buffer) {
6870 int previous_separator_position = 0;
6871 int separator_length = separator->length();
6872 int cursor = 0;
6873 for (int i = 0; i < elements_length; i += 2) {
6874 int position = NumberToInt32(elements->get(i));
6875 String* string = String::cast(elements->get(i + 1));
6876 int string_length = string->length();
6877 if (string->length() > 0) {
6878 while (previous_separator_position < position) {
6879 String::WriteToFlat<Char>(separator, &buffer[cursor],
6880 0, separator_length);
6881 cursor += separator_length;
6882 previous_separator_position++;
6883 }
6884 String::WriteToFlat<Char>(string, &buffer[cursor],
6885 0, string_length);
6886 cursor += string->length();
6887 }
6888 }
6889 if (separator_length > 0) {
6890 // Array length must be representable as a signed 32-bit number,
6891 // otherwise the total string length would have been too large.
6892 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6893 int last_array_index = static_cast<int>(array_length - 1);
6894 while (previous_separator_position < last_array_index) {
6895 String::WriteToFlat<Char>(separator, &buffer[cursor],
6896 0, separator_length);
6897 cursor += separator_length;
6898 previous_separator_position++;
6899 }
6900 }
6901 ASSERT(cursor <= buffer.length());
6902}
6903
6904
6905RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6906 NoHandleAllocation ha;
6907 ASSERT(args.length() == 3);
6908 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006909 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6910 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006911 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6912 CONVERT_CHECKED(String, separator, args[2]);
6913 // elements_array is fast-mode JSarray of alternating positions
6914 // (increasing order) and strings.
6915 // array_length is length of original array (used to add separators);
6916 // separator is string to put between elements. Assumed to be non-empty.
6917
6918 // Find total length of join result.
6919 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006920 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006921 int max_string_length;
6922 if (is_ascii) {
6923 max_string_length = SeqAsciiString::kMaxLength;
6924 } else {
6925 max_string_length = SeqTwoByteString::kMaxLength;
6926 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006927 bool overflow = false;
6928 CONVERT_NUMBER_CHECKED(int, elements_length,
6929 Int32, elements_array->length());
6930 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6931 FixedArray* elements = FixedArray::cast(elements_array->elements());
6932 for (int i = 0; i < elements_length; i += 2) {
6933 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6934 CONVERT_CHECKED(String, string, elements->get(i + 1));
6935 int length = string->length();
6936 if (is_ascii && !string->IsAsciiRepresentation()) {
6937 is_ascii = false;
6938 max_string_length = SeqTwoByteString::kMaxLength;
6939 }
6940 if (length > max_string_length ||
6941 max_string_length - length < string_length) {
6942 overflow = true;
6943 break;
6944 }
6945 string_length += length;
6946 }
6947 int separator_length = separator->length();
6948 if (!overflow && separator_length > 0) {
6949 if (array_length <= 0x7fffffffu) {
6950 int separator_count = static_cast<int>(array_length) - 1;
6951 int remaining_length = max_string_length - string_length;
6952 if ((remaining_length / separator_length) >= separator_count) {
6953 string_length += separator_length * (array_length - 1);
6954 } else {
6955 // Not room for the separators within the maximal string length.
6956 overflow = true;
6957 }
6958 } else {
6959 // Nonempty separator and at least 2^31-1 separators necessary
6960 // means that the string is too large to create.
6961 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6962 overflow = true;
6963 }
6964 }
6965 if (overflow) {
6966 // Throw OutOfMemory exception for creating too large a string.
6967 V8::FatalProcessOutOfMemory("Array join result too large.");
6968 }
6969
6970 if (is_ascii) {
6971 MaybeObject* result_allocation =
6972 isolate->heap()->AllocateRawAsciiString(string_length);
6973 if (result_allocation->IsFailure()) return result_allocation;
6974 SeqAsciiString* result_string =
6975 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6976 JoinSparseArrayWithSeparator<char>(elements,
6977 elements_length,
6978 array_length,
6979 separator,
6980 Vector<char>(result_string->GetChars(),
6981 string_length));
6982 return result_string;
6983 } else {
6984 MaybeObject* result_allocation =
6985 isolate->heap()->AllocateRawTwoByteString(string_length);
6986 if (result_allocation->IsFailure()) return result_allocation;
6987 SeqTwoByteString* result_string =
6988 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6989 JoinSparseArrayWithSeparator<uc16>(elements,
6990 elements_length,
6991 array_length,
6992 separator,
6993 Vector<uc16>(result_string->GetChars(),
6994 string_length));
6995 return result_string;
6996 }
6997}
6998
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007000RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001 NoHandleAllocation ha;
7002 ASSERT(args.length() == 2);
7003
7004 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7005 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007006 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007007}
7008
7009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007010RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007011 NoHandleAllocation ha;
7012 ASSERT(args.length() == 2);
7013
7014 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7015 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007016 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007017}
7018
7019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007020RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007021 NoHandleAllocation ha;
7022 ASSERT(args.length() == 2);
7023
7024 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7025 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007026 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027}
7028
7029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007030RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007031 NoHandleAllocation ha;
7032 ASSERT(args.length() == 1);
7033
7034 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007035 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007036}
7037
7038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007039RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007040 NoHandleAllocation ha;
7041 ASSERT(args.length() == 2);
7042
7043 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7044 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007045 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007046}
7047
7048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007049RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050 NoHandleAllocation ha;
7051 ASSERT(args.length() == 2);
7052
7053 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7054 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007055 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007056}
7057
7058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007059RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007060 NoHandleAllocation ha;
7061 ASSERT(args.length() == 2);
7062
7063 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7064 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007065 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007066}
7067
7068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007069RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070 NoHandleAllocation ha;
7071 ASSERT(args.length() == 2);
7072
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007073 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7074 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007075 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7076 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7077 if (x == y) return Smi::FromInt(EQUAL);
7078 Object* result;
7079 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7080 result = Smi::FromInt(EQUAL);
7081 } else {
7082 result = Smi::FromInt(NOT_EQUAL);
7083 }
7084 return result;
7085}
7086
7087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007088RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007089 NoHandleAllocation ha;
7090 ASSERT(args.length() == 2);
7091
7092 CONVERT_CHECKED(String, x, args[0]);
7093 CONVERT_CHECKED(String, y, args[1]);
7094
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007095 bool not_equal = !x->Equals(y);
7096 // This is slightly convoluted because the value that signifies
7097 // equality is 0 and inequality is 1 so we have to negate the result
7098 // from String::Equals.
7099 ASSERT(not_equal == 0 || not_equal == 1);
7100 STATIC_CHECK(EQUAL == 0);
7101 STATIC_CHECK(NOT_EQUAL == 1);
7102 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103}
7104
7105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007106RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107 NoHandleAllocation ha;
7108 ASSERT(args.length() == 3);
7109
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007110 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7111 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007112 if (isnan(x) || isnan(y)) return args[2];
7113 if (x == y) return Smi::FromInt(EQUAL);
7114 if (isless(x, y)) return Smi::FromInt(LESS);
7115 return Smi::FromInt(GREATER);
7116}
7117
7118
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007119// Compare two Smis as if they were converted to strings and then
7120// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007121RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007122 NoHandleAllocation ha;
7123 ASSERT(args.length() == 2);
7124
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007125 // Extract the integer values from the Smis.
7126 CONVERT_CHECKED(Smi, x, args[0]);
7127 CONVERT_CHECKED(Smi, y, args[1]);
7128 int x_value = x->value();
7129 int y_value = y->value();
7130
7131 // If the integers are equal so are the string representations.
7132 if (x_value == y_value) return Smi::FromInt(EQUAL);
7133
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007134 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007135 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007136 if (x_value == 0 || y_value == 0)
7137 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007138
ager@chromium.org32912102009-01-16 10:38:43 +00007139 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007140 // smallest because the char code of '-' is less than the char code
7141 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007142
7143 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7144 // architectures using 32-bit Smis.
7145 uint32_t x_scaled = x_value;
7146 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007147 if (x_value < 0 || y_value < 0) {
7148 if (y_value >= 0) return Smi::FromInt(LESS);
7149 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007150 x_scaled = -x_value;
7151 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007152 }
7153
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007154 static const uint32_t kPowersOf10[] = {
7155 1, 10, 100, 1000, 10*1000, 100*1000,
7156 1000*1000, 10*1000*1000, 100*1000*1000,
7157 1000*1000*1000
7158 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007159
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007160 // If the integers have the same number of decimal digits they can be
7161 // compared directly as the numeric order is the same as the
7162 // lexicographic order. If one integer has fewer digits, it is scaled
7163 // by some power of 10 to have the same number of digits as the longer
7164 // integer. If the scaled integers are equal it means the shorter
7165 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007166
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007167 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7168 int x_log2 = IntegerLog2(x_scaled);
7169 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7170 x_log10 -= x_scaled < kPowersOf10[x_log10];
7171
7172 int y_log2 = IntegerLog2(y_scaled);
7173 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7174 y_log10 -= y_scaled < kPowersOf10[y_log10];
7175
7176 int tie = EQUAL;
7177
7178 if (x_log10 < y_log10) {
7179 // X has fewer digits. We would like to simply scale up X but that
7180 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7181 // be scaled up to 9_000_000_000. So we scale up by the next
7182 // smallest power and scale down Y to drop one digit. It is OK to
7183 // drop one digit from the longer integer since the final digit is
7184 // past the length of the shorter integer.
7185 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7186 y_scaled /= 10;
7187 tie = LESS;
7188 } else if (y_log10 < x_log10) {
7189 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7190 x_scaled /= 10;
7191 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007192 }
7193
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007194 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7195 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7196 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007197}
7198
7199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007200static Object* StringInputBufferCompare(RuntimeState* state,
7201 String* x,
7202 String* y) {
7203 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7204 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007205 bufx.Reset(x);
7206 bufy.Reset(y);
7207 while (bufx.has_more() && bufy.has_more()) {
7208 int d = bufx.GetNext() - bufy.GetNext();
7209 if (d < 0) return Smi::FromInt(LESS);
7210 else if (d > 0) return Smi::FromInt(GREATER);
7211 }
7212
7213 // x is (non-trivial) prefix of y:
7214 if (bufy.has_more()) return Smi::FromInt(LESS);
7215 // y is prefix of x:
7216 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7217}
7218
7219
7220static Object* FlatStringCompare(String* x, String* y) {
7221 ASSERT(x->IsFlat());
7222 ASSERT(y->IsFlat());
7223 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7224 int prefix_length = x->length();
7225 if (y->length() < prefix_length) {
7226 prefix_length = y->length();
7227 equal_prefix_result = Smi::FromInt(GREATER);
7228 } else if (y->length() > prefix_length) {
7229 equal_prefix_result = Smi::FromInt(LESS);
7230 }
7231 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007232 String::FlatContent x_content = x->GetFlatContent();
7233 String::FlatContent y_content = y->GetFlatContent();
7234 if (x_content.IsAscii()) {
7235 Vector<const char> x_chars = x_content.ToAsciiVector();
7236 if (y_content.IsAscii()) {
7237 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007238 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007239 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007240 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007241 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7242 }
7243 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007244 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7245 if (y_content.IsAscii()) {
7246 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007247 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7248 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007249 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007250 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7251 }
7252 }
7253 Object* result;
7254 if (r == 0) {
7255 result = equal_prefix_result;
7256 } else {
7257 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7258 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007259 ASSERT(result ==
7260 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007261 return result;
7262}
7263
7264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007265RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007266 NoHandleAllocation ha;
7267 ASSERT(args.length() == 2);
7268
7269 CONVERT_CHECKED(String, x, args[0]);
7270 CONVERT_CHECKED(String, y, args[1]);
7271
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007272 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007274 // A few fast case tests before we flatten.
7275 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007276 if (y->length() == 0) {
7277 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007278 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007279 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007280 return Smi::FromInt(LESS);
7281 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007282
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007283 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007284 if (d < 0) return Smi::FromInt(LESS);
7285 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007286
lrn@chromium.org303ada72010-10-27 09:33:13 +00007287 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007288 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007289 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7290 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007291 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007292 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7293 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007295 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007296 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007297}
7298
7299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007300RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301 NoHandleAllocation ha;
7302 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007303 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007304
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007305 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307}
7308
7309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007310RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311 NoHandleAllocation ha;
7312 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007315 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007316 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007317}
7318
7319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007320RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321 NoHandleAllocation ha;
7322 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007325 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007326 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007327}
7328
7329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007330static const double kPiDividedBy4 = 0.78539816339744830962;
7331
7332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007333RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334 NoHandleAllocation ha;
7335 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007336 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007337
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007338 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7339 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007340 double result;
7341 if (isinf(x) && isinf(y)) {
7342 // Make sure that the result in case of two infinite arguments
7343 // is a multiple of Pi / 4. The sign of the result is determined
7344 // by the first argument (x) and the sign of the second argument
7345 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346 int multiplier = (x < 0) ? -1 : 1;
7347 if (y < 0) multiplier *= 3;
7348 result = multiplier * kPiDividedBy4;
7349 } else {
7350 result = atan2(x, y);
7351 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007352 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007353}
7354
7355
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007356RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007357 NoHandleAllocation ha;
7358 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007359 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007361 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007362 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363}
7364
7365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007366RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367 NoHandleAllocation ha;
7368 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007369 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007371 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007372 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373}
7374
7375
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007376RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377 NoHandleAllocation ha;
7378 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007381 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007382 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007383}
7384
7385
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007386RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387 NoHandleAllocation ha;
7388 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007391 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007392 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393}
7394
7395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007396RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397 NoHandleAllocation ha;
7398 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007401 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007402 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403}
7404
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007405// Slow version of Math.pow. We check for fast paths for special cases.
7406// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007407RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408 NoHandleAllocation ha;
7409 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007410 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007411
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007412 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007413
7414 // If the second argument is a smi, it is much faster to call the
7415 // custom powi() function than the generic pow().
7416 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007417 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007418 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007419 }
7420
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007421 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007422 int y_int = static_cast<int>(y);
7423 double result;
7424 if (y == y_int) {
7425 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7426 } else if (y == 0.5) {
7427 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7428 } else if (y == -0.5) {
7429 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7430 } else {
7431 result = power_double_double(x, y);
7432 }
7433 if (isnan(result)) return isolate->heap()->nan_value();
7434 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007435}
7436
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007437// Fast version of Math.pow if we know that y is not an integer and y is not
7438// -0.5 or 0.5. Used as slow case from fullcodegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007439RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007440 NoHandleAllocation ha;
7441 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007442 isolate->counters()->math_pow()->Increment();
7443
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007444 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7445 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007446 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007447 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007448 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007449 double result = power_double_double(x, y);
7450 if (isnan(result)) return isolate->heap()->nan_value();
7451 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007452 }
7453}
7454
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007456RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007457 NoHandleAllocation ha;
7458 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007459 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007460
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007461 if (!args[0]->IsHeapNumber()) {
7462 // Must be smi. Return the argument unchanged for all the other types
7463 // to make fuzz-natives test happy.
7464 return args[0];
7465 }
7466
7467 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7468
7469 double value = number->value();
7470 int exponent = number->get_exponent();
7471 int sign = number->get_sign();
7472
danno@chromium.org160a7b02011-04-18 15:51:38 +00007473 if (exponent < -1) {
7474 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7475 if (sign) return isolate->heap()->minus_zero_value();
7476 return Smi::FromInt(0);
7477 }
7478
7479 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7480 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7481 // agument holds for 32-bit smis).
7482 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007483 return Smi::FromInt(static_cast<int>(value + 0.5));
7484 }
7485
7486 // If the magnitude is big enough, there's no place for fraction part. If we
7487 // try to add 0.5 to this number, 1.0 will be added instead.
7488 if (exponent >= 52) {
7489 return number;
7490 }
7491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007492 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007493
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007494 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007495 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007496}
7497
7498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007499RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007500 NoHandleAllocation ha;
7501 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007502 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007503
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007504 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007505 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007506}
7507
7508
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007509RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007510 NoHandleAllocation ha;
7511 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007512 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007513
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007514 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007515 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007516}
7517
7518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007519RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007520 NoHandleAllocation ha;
7521 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007522 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007523
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007524 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007525 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007526}
7527
7528
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007529static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007530 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7531 181, 212, 243, 273, 304, 334};
7532 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7533 182, 213, 244, 274, 305, 335};
7534
7535 year += month / 12;
7536 month %= 12;
7537 if (month < 0) {
7538 year--;
7539 month += 12;
7540 }
7541
7542 ASSERT(month >= 0);
7543 ASSERT(month < 12);
7544
7545 // year_delta is an arbitrary number such that:
7546 // a) year_delta = -1 (mod 400)
7547 // b) year + year_delta > 0 for years in the range defined by
7548 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7549 // Jan 1 1970. This is required so that we don't run into integer
7550 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007551 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007552 // operations.
7553 static const int year_delta = 399999;
7554 static const int base_day = 365 * (1970 + year_delta) +
7555 (1970 + year_delta) / 4 -
7556 (1970 + year_delta) / 100 +
7557 (1970 + year_delta) / 400;
7558
7559 int year1 = year + year_delta;
7560 int day_from_year = 365 * year1 +
7561 year1 / 4 -
7562 year1 / 100 +
7563 year1 / 400 -
7564 base_day;
7565
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007566 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7567 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007568 }
7569
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007570 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007571}
7572
7573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007574RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007575 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007576 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007577
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007578 CONVERT_SMI_ARG_CHECKED(year, 0);
7579 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007580
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007581 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007582}
7583
7584
7585static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7586static const int kDaysIn4Years = 4 * 365 + 1;
7587static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7588static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7589static const int kDays1970to2000 = 30 * 365 + 7;
7590static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7591 kDays1970to2000;
7592static const int kYearsOffset = 400000;
7593
7594static const char kDayInYear[] = {
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, 31,
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,
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, 31,
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,
7603 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7604 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7605 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7606 22, 23, 24, 25, 26, 27, 28, 29, 30,
7607 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7608 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7609 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7610 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7611 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7612 22, 23, 24, 25, 26, 27, 28, 29, 30,
7613 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7614 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7615 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7616 22, 23, 24, 25, 26, 27, 28, 29, 30,
7617 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7618 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7619
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, 31,
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,
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, 31,
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,
7628 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7629 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7630 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7631 22, 23, 24, 25, 26, 27, 28, 29, 30,
7632 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7633 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7634 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7635 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7636 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7637 22, 23, 24, 25, 26, 27, 28, 29, 30,
7638 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7639 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7640 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7641 22, 23, 24, 25, 26, 27, 28, 29, 30,
7642 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7643 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7644
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, 31,
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,
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, 31,
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,
7653 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7654 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7655 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7656 22, 23, 24, 25, 26, 27, 28, 29, 30,
7657 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7658 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7659 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7660 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7661 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7662 22, 23, 24, 25, 26, 27, 28, 29, 30,
7663 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7664 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7665 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7666 22, 23, 24, 25, 26, 27, 28, 29, 30,
7667 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7668 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7669
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, 31,
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,
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, 31,
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,
7678 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7679 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7680 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7681 22, 23, 24, 25, 26, 27, 28, 29, 30,
7682 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7683 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7684 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7685 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7686 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7687 22, 23, 24, 25, 26, 27, 28, 29, 30,
7688 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7689 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7690 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7691 22, 23, 24, 25, 26, 27, 28, 29, 30,
7692 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7693 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7694
7695static const char kMonthInYear[] = {
7696 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,
7697 0, 0, 0, 0, 0, 0,
7698 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,
7699 1, 1, 1,
7700 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,
7701 2, 2, 2, 2, 2, 2,
7702 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,
7703 3, 3, 3, 3, 3,
7704 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,
7705 4, 4, 4, 4, 4, 4,
7706 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,
7707 5, 5, 5, 5, 5,
7708 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,
7709 6, 6, 6, 6, 6, 6,
7710 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,
7711 7, 7, 7, 7, 7, 7,
7712 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,
7713 8, 8, 8, 8, 8,
7714 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,
7715 9, 9, 9, 9, 9, 9,
7716 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7717 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7718 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7719 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7720
7721 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,
7722 0, 0, 0, 0, 0, 0,
7723 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,
7724 1, 1, 1,
7725 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,
7726 2, 2, 2, 2, 2, 2,
7727 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,
7728 3, 3, 3, 3, 3,
7729 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,
7730 4, 4, 4, 4, 4, 4,
7731 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,
7732 5, 5, 5, 5, 5,
7733 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,
7734 6, 6, 6, 6, 6, 6,
7735 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,
7736 7, 7, 7, 7, 7, 7,
7737 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,
7738 8, 8, 8, 8, 8,
7739 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,
7740 9, 9, 9, 9, 9, 9,
7741 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7742 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7743 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7744 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7745
7746 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,
7747 0, 0, 0, 0, 0, 0,
7748 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,
7749 1, 1, 1, 1,
7750 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,
7751 2, 2, 2, 2, 2, 2,
7752 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,
7753 3, 3, 3, 3, 3,
7754 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,
7755 4, 4, 4, 4, 4, 4,
7756 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,
7757 5, 5, 5, 5, 5,
7758 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,
7759 6, 6, 6, 6, 6, 6,
7760 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,
7761 7, 7, 7, 7, 7, 7,
7762 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,
7763 8, 8, 8, 8, 8,
7764 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,
7765 9, 9, 9, 9, 9, 9,
7766 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7767 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7768 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7769 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7770
7771 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,
7772 0, 0, 0, 0, 0, 0,
7773 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,
7774 1, 1, 1,
7775 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,
7776 2, 2, 2, 2, 2, 2,
7777 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,
7778 3, 3, 3, 3, 3,
7779 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,
7780 4, 4, 4, 4, 4, 4,
7781 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,
7782 5, 5, 5, 5, 5,
7783 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,
7784 6, 6, 6, 6, 6, 6,
7785 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,
7786 7, 7, 7, 7, 7, 7,
7787 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,
7788 8, 8, 8, 8, 8,
7789 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,
7790 9, 9, 9, 9, 9, 9,
7791 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7792 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7793 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7794 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7795
7796
7797// This function works for dates from 1970 to 2099.
7798static inline void DateYMDFromTimeAfter1970(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 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7805 date %= kDaysIn4Years;
7806
7807 month = kMonthInYear[date];
7808 day = kDayInYear[date];
7809
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007810 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007811}
7812
7813
7814static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007815 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007816#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007817 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007818#endif
7819
7820 date += kDaysOffset;
7821 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7822 date %= kDaysIn400Years;
7823
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007824 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007825
7826 date--;
7827 int yd1 = date / kDaysIn100Years;
7828 date %= kDaysIn100Years;
7829 year += 100 * yd1;
7830
7831 date++;
7832 int yd2 = date / kDaysIn4Years;
7833 date %= kDaysIn4Years;
7834 year += 4 * yd2;
7835
7836 date--;
7837 int yd3 = date / 365;
7838 date %= 365;
7839 year += yd3;
7840
7841 bool is_leap = (!yd1 || yd2) && !yd3;
7842
7843 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007844 ASSERT(is_leap || (date >= 0));
7845 ASSERT((date < 365) || (is_leap && (date < 366)));
7846 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007847 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7848 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007849
7850 if (is_leap) {
7851 day = kDayInYear[2*365 + 1 + date];
7852 month = kMonthInYear[2*365 + 1 + date];
7853 } else {
7854 day = kDayInYear[date];
7855 month = kMonthInYear[date];
7856 }
7857
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007858 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007859}
7860
7861
7862static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007863 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007864 if (date >= 0 && date < 32 * kDaysIn4Years) {
7865 DateYMDFromTimeAfter1970(date, year, month, day);
7866 } else {
7867 DateYMDFromTimeSlow(date, year, month, day);
7868 }
7869}
7870
7871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007872RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007873 NoHandleAllocation ha;
7874 ASSERT(args.length() == 2);
7875
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007876 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007877 CONVERT_CHECKED(JSArray, res_array, args[1]);
7878
7879 int year, month, day;
7880 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7881
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007882 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7883 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007884 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007885
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007886 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7887 if (maybe->IsFailure()) return maybe;
7888 FixedArray* elms = FixedArray::cast(res_array->elements());
7889 elms->set(0, Smi::FromInt(year));
7890 elms->set(1, Smi::FromInt(month));
7891 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007892
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007893 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007894}
7895
7896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007897RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007898 HandleScope scope(isolate);
7899 ASSERT(args.length() == 3);
7900
7901 Handle<JSFunction> callee = args.at<JSFunction>(0);
7902 Object** parameters = reinterpret_cast<Object**>(args[1]);
7903 const int argument_count = Smi::cast(args[2])->value();
7904
7905 Handle<JSObject> result =
7906 isolate->factory()->NewArgumentsObject(callee, argument_count);
7907 // Allocate the elements if needed.
7908 int parameter_count = callee->shared()->formal_parameter_count();
7909 if (argument_count > 0) {
7910 if (parameter_count > 0) {
7911 int mapped_count = Min(argument_count, parameter_count);
7912 Handle<FixedArray> parameter_map =
7913 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7914 parameter_map->set_map(
7915 isolate->heap()->non_strict_arguments_elements_map());
7916
7917 Handle<Map> old_map(result->map());
7918 Handle<Map> new_map =
7919 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007920 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007921
7922 result->set_map(*new_map);
7923 result->set_elements(*parameter_map);
7924
7925 // Store the context and the arguments array at the beginning of the
7926 // parameter map.
7927 Handle<Context> context(isolate->context());
7928 Handle<FixedArray> arguments =
7929 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7930 parameter_map->set(0, *context);
7931 parameter_map->set(1, *arguments);
7932
7933 // Loop over the actual parameters backwards.
7934 int index = argument_count - 1;
7935 while (index >= mapped_count) {
7936 // These go directly in the arguments array and have no
7937 // corresponding slot in the parameter map.
7938 arguments->set(index, *(parameters - index - 1));
7939 --index;
7940 }
7941
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007942 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007943 while (index >= 0) {
7944 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007945 Handle<String> name(scope_info->ParameterName(index));
7946 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007947 bool duplicate = false;
7948 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007949 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007950 duplicate = true;
7951 break;
7952 }
7953 }
7954
7955 if (duplicate) {
7956 // This goes directly in the arguments array with a hole in the
7957 // parameter map.
7958 arguments->set(index, *(parameters - index - 1));
7959 parameter_map->set_the_hole(index + 2);
7960 } else {
7961 // The context index goes in the parameter map with a hole in the
7962 // arguments array.
7963 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007964 for (int j = 0; j < context_local_count; ++j) {
7965 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007966 context_index = j;
7967 break;
7968 }
7969 }
7970 ASSERT(context_index >= 0);
7971 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007972 parameter_map->set(index + 2, Smi::FromInt(
7973 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007974 }
7975
7976 --index;
7977 }
7978 } else {
7979 // If there is no aliasing, the arguments object elements are not
7980 // special in any way.
7981 Handle<FixedArray> elements =
7982 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7983 result->set_elements(*elements);
7984 for (int i = 0; i < argument_count; ++i) {
7985 elements->set(i, *(parameters - i - 1));
7986 }
7987 }
7988 }
7989 return *result;
7990}
7991
7992
7993RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007994 NoHandleAllocation ha;
7995 ASSERT(args.length() == 3);
7996
7997 JSFunction* callee = JSFunction::cast(args[0]);
7998 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007999 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008000
lrn@chromium.org303ada72010-10-27 09:33:13 +00008001 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008002 { MaybeObject* maybe_result =
8003 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008004 if (!maybe_result->ToObject(&result)) return maybe_result;
8005 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008006 // Allocate the elements if needed.
8007 if (length > 0) {
8008 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008009 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008010 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008011 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8012 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008013
8014 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008015 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008016 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008017 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008018
8019 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008020 for (int i = 0; i < length; i++) {
8021 array->set(i, *--parameters, mode);
8022 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008023 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008024 }
8025 return result;
8026}
8027
8028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008029RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008030 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008031 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008032 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008033 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008034 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008035
whesse@chromium.org7b260152011-06-20 15:33:18 +00008036 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008037 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008038 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008039 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008040 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8041 context,
8042 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008043 return *result;
8044}
8045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008046
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008047// Find the arguments of the JavaScript function invocation that called
8048// into C++ code. Collect these in a newly allocated array of handles (possibly
8049// prefixed by a number of empty handles).
8050static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8051 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008052 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008053 // Find frame containing arguments passed to the caller.
8054 JavaScriptFrameIterator it;
8055 JavaScriptFrame* frame = it.frame();
8056 List<JSFunction*> functions(2);
8057 frame->GetFunctions(&functions);
8058 if (functions.length() > 1) {
8059 int inlined_frame_index = functions.length() - 1;
8060 JSFunction* inlined_function = functions[inlined_frame_index];
8061 int args_count = inlined_function->shared()->formal_parameter_count();
8062 ScopedVector<SlotRef> args_slots(args_count);
8063 SlotRef::ComputeSlotMappingForArguments(frame,
8064 inlined_frame_index,
8065 &args_slots);
8066
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008067 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008068 SmartArrayPointer<Handle<Object> > param_data(
8069 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008070 for (int i = 0; i < args_count; i++) {
8071 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008072 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008073 }
8074 return param_data;
8075 } else {
8076 it.AdvanceToArgumentsFrame();
8077 frame = it.frame();
8078 int args_count = frame->ComputeParametersCount();
8079
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008080 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008081 SmartArrayPointer<Handle<Object> > param_data(
8082 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008083 for (int i = 0; i < args_count; i++) {
8084 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008085 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008086 }
8087 return param_data;
8088 }
8089}
8090
8091
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008092RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8093 HandleScope scope(isolate);
8094 ASSERT(args.length() == 4);
8095 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8096 RUNTIME_ASSERT(args[3]->IsNumber());
8097 Handle<Object> bindee = args.at<Object>(1);
8098
8099 // TODO(lrn): Create bound function in C++ code from premade shared info.
8100 bound_function->shared()->set_bound(true);
8101 // Get all arguments of calling function (Function.prototype.bind).
8102 int argc = 0;
8103 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8104 // Don't count the this-arg.
8105 if (argc > 0) {
8106 ASSERT(*arguments[0] == args[2]);
8107 argc--;
8108 } else {
8109 ASSERT(args[2]->IsUndefined());
8110 }
8111 // Initialize array of bindings (function, this, and any existing arguments
8112 // if the function was already bound).
8113 Handle<FixedArray> new_bindings;
8114 int i;
8115 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8116 Handle<FixedArray> old_bindings(
8117 JSFunction::cast(*bindee)->function_bindings());
8118 new_bindings =
8119 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8120 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8121 i = 0;
8122 for (int n = old_bindings->length(); i < n; i++) {
8123 new_bindings->set(i, old_bindings->get(i));
8124 }
8125 } else {
8126 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8127 new_bindings = isolate->factory()->NewFixedArray(array_size);
8128 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8129 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8130 i = 2;
8131 }
8132 // Copy arguments, skipping the first which is "this_arg".
8133 for (int j = 0; j < argc; j++, i++) {
8134 new_bindings->set(i, *arguments[j + 1]);
8135 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008136 new_bindings->set_map_no_write_barrier(
8137 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008138 bound_function->set_function_bindings(*new_bindings);
8139
8140 // Update length.
8141 Handle<String> length_symbol = isolate->factory()->length_symbol();
8142 Handle<Object> new_length(args.at<Object>(3));
8143 PropertyAttributes attr =
8144 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8145 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8146 return *bound_function;
8147}
8148
8149
8150RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8151 HandleScope handles(isolate);
8152 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008153 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008154 if (callable->IsJSFunction()) {
8155 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8156 if (function->shared()->bound()) {
8157 Handle<FixedArray> bindings(function->function_bindings());
8158 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8159 return *isolate->factory()->NewJSArrayWithElements(bindings);
8160 }
8161 }
8162 return isolate->heap()->undefined_value();
8163}
8164
8165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008166RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008167 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008168 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008169 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008170 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008171 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008172
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008173 // The argument is a bound function. Extract its bound arguments
8174 // and callable.
8175 Handle<FixedArray> bound_args =
8176 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8177 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8178 Handle<Object> bound_function(
8179 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8180 ASSERT(!bound_function->IsJSFunction() ||
8181 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008183 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008184 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008185 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008186 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008187 param_data[i] = Handle<Object>(bound_args->get(
8188 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008189 }
8190
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008191 if (!bound_function->IsJSFunction()) {
8192 bool exception_thrown;
8193 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8194 &exception_thrown);
8195 if (exception_thrown) return Failure::Exception();
8196 }
8197 ASSERT(bound_function->IsJSFunction());
8198
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008199 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008200 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008201 Execution::New(Handle<JSFunction>::cast(bound_function),
8202 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008203 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008204 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008205 }
8206 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008207 return *result;
8208}
8209
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008210
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008211static void TrySettingInlineConstructStub(Isolate* isolate,
8212 Handle<JSFunction> function) {
8213 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008214 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008215 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008216 }
8217 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008218 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008219 Handle<Code> code = compiler.CompileConstructStub(function);
8220 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008221 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008222}
8223
8224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008225RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008226 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008227 ASSERT(args.length() == 1);
8228
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008229 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008230
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008231 // If the constructor isn't a proper function we throw a type error.
8232 if (!constructor->IsJSFunction()) {
8233 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);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008237 }
8238
8239 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008240
8241 // If function should not have prototype, construction is not allowed. In this
8242 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008243 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008244 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8245 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008246 isolate->factory()->NewTypeError("not_constructor", arguments);
8247 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008248 }
8249
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008250#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008252 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008253 if (debug->StepInActive()) {
8254 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008255 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008256#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008257
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008258 if (function->has_initial_map()) {
8259 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008260 // The 'Function' function ignores the receiver object when
8261 // called using 'new' and creates a new JSFunction object that
8262 // is returned. The receiver object is only used for error
8263 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008264 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008265 // allocate JSFunctions since it does not properly initialize
8266 // the shared part of the function. Since the receiver is
8267 // ignored anyway, we use the global object as the receiver
8268 // instead of a new JSFunction object. This way, errors are
8269 // reported the same way whether or not 'Function' is called
8270 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008271 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008272 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273 }
8274
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008275 // The function should be compiled for the optimization hints to be
8276 // available. We cannot use EnsureCompiled because that forces a
8277 // compilation through the shared function info which makes it
8278 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008279 if (!function->is_compiled()) {
8280 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8281 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008282
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008283 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008284 if (!function->has_initial_map() &&
8285 shared->IsInobjectSlackTrackingInProgress()) {
8286 // The tracking is already in progress for another function. We can only
8287 // track one initial_map at a time, so we force the completion before the
8288 // function is called as a constructor for the first time.
8289 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008290 }
8291
8292 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008293 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8294 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008295 // Delay setting the stub if inobject slack tracking is in progress.
8296 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008297 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008298 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008299
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008300 isolate->counters()->constructed_objects()->Increment();
8301 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008302
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008303 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008304}
8305
8306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008307RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008308 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008309 ASSERT(args.length() == 1);
8310
8311 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8312 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008313 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008315 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008316}
8317
8318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008319RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008320 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321 ASSERT(args.length() == 1);
8322
8323 Handle<JSFunction> function = args.at<JSFunction>(0);
8324#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008325 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008326 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008327 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328 PrintF("]\n");
8329 }
8330#endif
8331
lrn@chromium.org34e60782011-09-15 07:25:40 +00008332 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008333 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008334 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008335 return Failure::Exception();
8336 }
8337
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008338 // All done. Return the compiled code.
8339 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008340 return function->code();
8341}
8342
8343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008344RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008345 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008346 ASSERT(args.length() == 1);
8347 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008348
8349 // If the function is not compiled ignore the lazy
8350 // recompilation. This can happen if the debugger is activated and
8351 // the function is returned to the not compiled state.
8352 if (!function->shared()->is_compiled()) {
8353 function->ReplaceCode(function->shared()->code());
8354 return function->code();
8355 }
8356
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008357 // If the function is not optimizable or debugger is active continue using the
8358 // code from the full compiler.
8359 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008360 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008361 if (FLAG_trace_opt) {
8362 PrintF("[failed to optimize ");
8363 function->PrintName();
8364 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8365 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008366 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008367 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008368 function->ReplaceCode(function->shared()->code());
8369 return function->code();
8370 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008371 if (JSFunction::CompileOptimized(function,
8372 AstNode::kNoNumber,
8373 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008374 return function->code();
8375 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008376 if (FLAG_trace_opt) {
8377 PrintF("[failed to optimize ");
8378 function->PrintName();
8379 PrintF(": optimized compilation failed]\n");
8380 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008381 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008382 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008383}
8384
8385
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008386class ActivationsFinder : public ThreadVisitor {
8387 public:
8388 explicit ActivationsFinder(JSFunction* function)
8389 : function_(function), has_activations_(false) {}
8390
8391 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8392 if (has_activations_) return;
8393
8394 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8395 JavaScriptFrame* frame = it.frame();
8396 if (frame->is_optimized() && frame->function() == function_) {
8397 has_activations_ = true;
8398 return;
8399 }
8400 }
8401 }
8402
8403 bool has_activations() { return has_activations_; }
8404
8405 private:
8406 JSFunction* function_;
8407 bool has_activations_;
8408};
8409
8410
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008411RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008412 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008413 ASSERT(args.length() == 1);
8414 RUNTIME_ASSERT(args[0]->IsSmi());
8415 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008416 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008417 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8418 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008419 int frames = deoptimizer->output_count();
8420
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008421 deoptimizer->MaterializeHeapNumbers();
8422 delete deoptimizer;
8423
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008424 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008425 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008426 for (int i = 0; i < frames - 1; i++) it.Advance();
8427 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008428
8429 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008430 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008431 Handle<Object> arguments;
8432 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008433 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008434 if (arguments.is_null()) {
8435 // FunctionGetArguments can't throw an exception, so cast away the
8436 // doubt with an assert.
8437 arguments = Handle<Object>(
8438 Accessors::FunctionGetArguments(*function,
8439 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008440 ASSERT(*arguments != isolate->heap()->null_value());
8441 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008442 }
8443 frame->SetExpression(i, *arguments);
8444 }
8445 }
8446
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008447 if (type == Deoptimizer::EAGER) {
8448 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008449 }
8450
8451 // Avoid doing too much work when running with --always-opt and keep
8452 // the optimized code around.
8453 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008454 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008455 }
8456
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008457 // Find other optimized activations of the function.
8458 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008459 while (!it.done()) {
8460 JavaScriptFrame* frame = it.frame();
8461 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008462 has_other_activations = true;
8463 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008464 }
8465 it.Advance();
8466 }
8467
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008468 if (!has_other_activations) {
8469 ActivationsFinder activations_finder(*function);
8470 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8471 has_other_activations = activations_finder.has_activations();
8472 }
8473
8474 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008475 if (FLAG_trace_deopt) {
8476 PrintF("[removing optimized code for: ");
8477 function->PrintName();
8478 PrintF("]\n");
8479 }
8480 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008481 } else {
8482 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008483 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008484 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008485}
8486
8487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008488RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008489 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008490 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008491 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008492}
8493
8494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008495RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008496 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008497 ASSERT(args.length() == 1);
8498 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008499 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008500
8501 Deoptimizer::DeoptimizeFunction(*function);
8502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008503 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008504}
8505
8506
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008507RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8508#if defined(USE_SIMULATOR)
8509 return isolate->heap()->true_value();
8510#else
8511 return isolate->heap()->false_value();
8512#endif
8513}
8514
8515
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008516RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8517 HandleScope scope(isolate);
8518 ASSERT(args.length() == 1);
8519 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8520 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8521 function->MarkForLazyRecompilation();
8522 return isolate->heap()->undefined_value();
8523}
8524
8525
lrn@chromium.org1c092762011-05-09 09:42:16 +00008526RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8527 HandleScope scope(isolate);
8528 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008529 // The least significant bit (after untagging) indicates whether the
8530 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008531 if (!V8::UseCrankshaft()) {
8532 return Smi::FromInt(4); // 4 == "never".
8533 }
8534 if (FLAG_always_opt) {
8535 return Smi::FromInt(3); // 3 == "always".
8536 }
8537 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8538 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8539 : Smi::FromInt(2); // 2 == "no".
8540}
8541
8542
8543RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8544 HandleScope scope(isolate);
8545 ASSERT(args.length() == 1);
8546 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8547 return Smi::FromInt(function->shared()->opt_count());
8548}
8549
8550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008551RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008552 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008553 ASSERT(args.length() == 1);
8554 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8555
8556 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008557 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008558
8559 // We have hit a back edge in an unoptimized frame for a function that was
8560 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008561 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008562 // Keep track of whether we've succeeded in optimizing.
8563 bool succeeded = unoptimized->optimizable();
8564 if (succeeded) {
8565 // If we are trying to do OSR when there are already optimized
8566 // activations of the function, it means (a) the function is directly or
8567 // indirectly recursive and (b) an optimized invocation has been
8568 // deoptimized so that we are currently in an unoptimized activation.
8569 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008570 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008571 while (succeeded && !it.done()) {
8572 JavaScriptFrame* frame = it.frame();
8573 succeeded = !frame->is_optimized() || frame->function() != *function;
8574 it.Advance();
8575 }
8576 }
8577
8578 int ast_id = AstNode::kNoNumber;
8579 if (succeeded) {
8580 // The top JS function is this one, the PC is somewhere in the
8581 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008582 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008583 JavaScriptFrame* frame = it.frame();
8584 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008585 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008586 ASSERT(unoptimized->contains(frame->pc()));
8587
8588 // Use linear search of the unoptimized code's stack check table to find
8589 // the AST id matching the PC.
8590 Address start = unoptimized->instruction_start();
8591 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008592 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008593 uint32_t table_length = Memory::uint32_at(table_cursor);
8594 table_cursor += kIntSize;
8595 for (unsigned i = 0; i < table_length; ++i) {
8596 // Table entries are (AST id, pc offset) pairs.
8597 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8598 if (pc_offset == target_pc_offset) {
8599 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8600 break;
8601 }
8602 table_cursor += 2 * kIntSize;
8603 }
8604 ASSERT(ast_id != AstNode::kNoNumber);
8605 if (FLAG_trace_osr) {
8606 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8607 function->PrintName();
8608 PrintF("]\n");
8609 }
8610
8611 // Try to compile the optimized code. A true return value from
8612 // CompileOptimized means that compilation succeeded, not necessarily
8613 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008614 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008615 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008616 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8617 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008618 if (data->OsrPcOffset()->value() >= 0) {
8619 if (FLAG_trace_osr) {
8620 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008621 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008622 }
8623 ASSERT(data->OsrAstId()->value() == ast_id);
8624 } else {
8625 // We may never generate the desired OSR entry if we emit an
8626 // early deoptimize.
8627 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008628 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008629 } else {
8630 succeeded = false;
8631 }
8632 }
8633
8634 // Revert to the original stack checks in the original unoptimized code.
8635 if (FLAG_trace_osr) {
8636 PrintF("[restoring original stack checks in ");
8637 function->PrintName();
8638 PrintF("]\n");
8639 }
8640 StackCheckStub check_stub;
8641 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008642 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008643 Deoptimizer::RevertStackCheckCode(*unoptimized,
8644 *check_code,
8645 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008646
8647 // Allow OSR only at nesting level zero again.
8648 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8649
8650 // If the optimization attempt succeeded, return the AST id tagged as a
8651 // smi. This tells the builtin that we need to translate the unoptimized
8652 // frame to an optimized one.
8653 if (succeeded) {
8654 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8655 return Smi::FromInt(ast_id);
8656 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008657 if (function->IsMarkedForLazyRecompilation()) {
8658 function->ReplaceCode(function->shared()->code());
8659 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008660 return Smi::FromInt(-1);
8661 }
8662}
8663
8664
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008665RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8666 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8667 return isolate->heap()->undefined_value();
8668}
8669
8670
danno@chromium.orgc612e022011-11-10 11:38:15 +00008671RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8672 HandleScope scope(isolate);
8673 ASSERT(args.length() >= 2);
8674 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8675 Object* receiver = args[0];
8676 int argc = args.length() - 2;
8677
8678 // If there are too many arguments, allocate argv via malloc.
8679 const int argv_small_size = 10;
8680 Handle<Object> argv_small_buffer[argv_small_size];
8681 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8682 Handle<Object>* argv = argv_small_buffer;
8683 if (argc > argv_small_size) {
8684 argv = new Handle<Object>[argc];
8685 if (argv == NULL) return isolate->StackOverflow();
8686 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8687 }
8688
8689 for (int i = 0; i < argc; ++i) {
8690 MaybeObject* maybe = args[1 + i];
8691 Object* object;
8692 if (!maybe->To<Object>(&object)) return maybe;
8693 argv[i] = Handle<Object>(object);
8694 }
8695
8696 bool threw;
8697 Handle<JSReceiver> hfun(fun);
8698 Handle<Object> hreceiver(receiver);
8699 Handle<Object> result =
8700 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8701
8702 if (threw) return Failure::Exception();
8703 return *result;
8704}
8705
8706
lrn@chromium.org34e60782011-09-15 07:25:40 +00008707RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8708 HandleScope scope(isolate);
8709 ASSERT(args.length() == 5);
8710 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8711 Object* receiver = args[1];
8712 CONVERT_CHECKED(JSObject, arguments, args[2]);
8713 CONVERT_CHECKED(Smi, shift, args[3]);
8714 CONVERT_CHECKED(Smi, arity, args[4]);
8715
8716 int offset = shift->value();
8717 int argc = arity->value();
8718 ASSERT(offset >= 0);
8719 ASSERT(argc >= 0);
8720
8721 // If there are too many arguments, allocate argv via malloc.
8722 const int argv_small_size = 10;
8723 Handle<Object> argv_small_buffer[argv_small_size];
8724 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8725 Handle<Object>* argv = argv_small_buffer;
8726 if (argc > argv_small_size) {
8727 argv = new Handle<Object>[argc];
8728 if (argv == NULL) return isolate->StackOverflow();
8729 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8730 }
8731
8732 for (int i = 0; i < argc; ++i) {
8733 MaybeObject* maybe = arguments->GetElement(offset + i);
8734 Object* object;
8735 if (!maybe->To<Object>(&object)) return maybe;
8736 argv[i] = Handle<Object>(object);
8737 }
8738
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008739 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008740 Handle<JSReceiver> hfun(fun);
8741 Handle<Object> hreceiver(receiver);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008742 Handle<Object> result =
8743 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008744
8745 if (threw) return Failure::Exception();
8746 return *result;
8747}
8748
8749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008750RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008751 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008752 ASSERT(args.length() == 1);
8753 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8754 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8755}
8756
8757
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008758RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008759 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008760 ASSERT(args.length() == 1);
8761 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8762 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8763}
8764
8765
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008766RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008767 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008768 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008769
kasper.lund7276f142008-07-30 08:49:36 +00008770 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008771 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008772 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008773 { MaybeObject* maybe_result =
8774 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008775 if (!maybe_result->ToObject(&result)) return maybe_result;
8776 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008777
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008778 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779
kasper.lund7276f142008-07-30 08:49:36 +00008780 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008781}
8782
lrn@chromium.org303ada72010-10-27 09:33:13 +00008783
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008784RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8785 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008786 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008787 JSObject* extension_object;
8788 if (args[0]->IsJSObject()) {
8789 extension_object = JSObject::cast(args[0]);
8790 } else {
8791 // Convert the object to a proper JavaScript object.
8792 MaybeObject* maybe_js_object = args[0]->ToObject();
8793 if (!maybe_js_object->To(&extension_object)) {
8794 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8795 HandleScope scope(isolate);
8796 Handle<Object> handle = args.at<Object>(0);
8797 Handle<Object> result =
8798 isolate->factory()->NewTypeError("with_expression",
8799 HandleVector(&handle, 1));
8800 return isolate->Throw(*result);
8801 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008802 return maybe_js_object;
8803 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008804 }
8805 }
8806
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008807 JSFunction* function;
8808 if (args[1]->IsSmi()) {
8809 // A smi sentinel indicates a context nested inside global code rather
8810 // than some function. There is a canonical empty function that can be
8811 // gotten from the global context.
8812 function = isolate->context()->global_context()->closure();
8813 } else {
8814 function = JSFunction::cast(args[1]);
8815 }
8816
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008817 Context* context;
8818 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008819 isolate->heap()->AllocateWithContext(function,
8820 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008821 extension_object);
8822 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008823 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008824 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008825}
8826
8827
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008828RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008829 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008830 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008831 String* name = String::cast(args[0]);
8832 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008833 JSFunction* function;
8834 if (args[2]->IsSmi()) {
8835 // A smi sentinel indicates a context nested inside global code rather
8836 // than some function. There is a canonical empty function that can be
8837 // gotten from the global context.
8838 function = isolate->context()->global_context()->closure();
8839 } else {
8840 function = JSFunction::cast(args[2]);
8841 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008842 Context* context;
8843 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008844 isolate->heap()->AllocateCatchContext(function,
8845 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008846 name,
8847 thrown_object);
8848 if (!maybe_context->To(&context)) return maybe_context;
8849 isolate->set_context(context);
8850 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008851}
8852
8853
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008854RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8855 NoHandleAllocation ha;
8856 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008857 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008858 JSFunction* function;
8859 if (args[1]->IsSmi()) {
8860 // A smi sentinel indicates a context nested inside global code rather
8861 // than some function. There is a canonical empty function that can be
8862 // gotten from the global context.
8863 function = isolate->context()->global_context()->closure();
8864 } else {
8865 function = JSFunction::cast(args[1]);
8866 }
8867 Context* context;
8868 MaybeObject* maybe_context =
8869 isolate->heap()->AllocateBlockContext(function,
8870 isolate->context(),
8871 scope_info);
8872 if (!maybe_context->To(&context)) return maybe_context;
8873 isolate->set_context(context);
8874 return context;
8875}
8876
8877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008878RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008879 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880 ASSERT(args.length() == 2);
8881
8882 CONVERT_ARG_CHECKED(Context, context, 0);
8883 CONVERT_ARG_CHECKED(String, name, 1);
8884
8885 int index;
8886 PropertyAttributes attributes;
8887 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008888 BindingFlags binding_flags;
8889 Handle<Object> holder = context->Lookup(name,
8890 flags,
8891 &index,
8892 &attributes,
8893 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008894
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008895 // If the slot was not found the result is true.
8896 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008897 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008898 }
8899
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008900 // If the slot was found in a context, it should be DONT_DELETE.
8901 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008902 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008903 }
8904
8905 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008906 // the global object, or the subject of a with. Try to delete it
8907 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008908 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008909 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008910}
8911
8912
ager@chromium.orga1645e22009-09-09 19:27:10 +00008913// A mechanism to return a pair of Object pointers in registers (if possible).
8914// How this is achieved is calling convention-dependent.
8915// All currently supported x86 compiles uses calling conventions that are cdecl
8916// variants where a 64-bit value is returned in two 32-bit registers
8917// (edx:eax on ia32, r1:r0 on ARM).
8918// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8919// In Win64 calling convention, a struct of two pointers is returned in memory,
8920// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008921#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008922struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008923 MaybeObject* x;
8924 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008925};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008926
lrn@chromium.org303ada72010-10-27 09:33:13 +00008927static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008928 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008929 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8930 // In Win64 they are assigned to a hidden first argument.
8931 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008932}
8933#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008934typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008935static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008936 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008937 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008938}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008939#endif
8940
8941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008942static inline MaybeObject* Unhole(Heap* heap,
8943 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008944 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008945 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8946 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008947 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008948}
8949
8950
danno@chromium.org40cb8782011-05-25 07:58:50 +00008951static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8952 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008953 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008954 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008955 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008956 JSFunction* context_extension_function =
8957 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008958 // If the holder isn't a context extension object, we just return it
8959 // as the receiver. This allows arguments objects to be used as
8960 // receivers, but only if they are put in the context scope chain
8961 // explicitly via a with-statement.
8962 Object* constructor = holder->map()->constructor();
8963 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008964 // Fall back to using the global object as the implicit receiver if
8965 // the property turns out to be a local variable allocated in a
8966 // context extension object - introduced via eval. Implicit global
8967 // receivers are indicated with the hole value.
8968 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008969}
8970
8971
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008972static ObjectPair LoadContextSlotHelper(Arguments args,
8973 Isolate* isolate,
8974 bool throw_error) {
8975 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008976 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008977
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008978 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008979 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008980 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008982 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008983
8984 int index;
8985 PropertyAttributes attributes;
8986 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008987 BindingFlags binding_flags;
8988 Handle<Object> holder = context->Lookup(name,
8989 flags,
8990 &index,
8991 &attributes,
8992 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008993
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008994 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008995 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008996 ASSERT(holder->IsContext());
8997 // If the "property" we were looking for is a local variable, the
8998 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008999 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009000 // Use the hole as the receiver to signal that the receiver is implicit
9001 // and that the global receiver should be used (as distinguished from an
9002 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009003 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009004 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009005 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009006 switch (binding_flags) {
9007 case MUTABLE_CHECK_INITIALIZED:
9008 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9009 if (value->IsTheHole()) {
9010 Handle<Object> reference_error =
9011 isolate->factory()->NewReferenceError("not_defined",
9012 HandleVector(&name, 1));
9013 return MakePair(isolate->Throw(*reference_error), NULL);
9014 }
9015 // FALLTHROUGH
9016 case MUTABLE_IS_INITIALIZED:
9017 case IMMUTABLE_IS_INITIALIZED:
9018 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9019 ASSERT(!value->IsTheHole());
9020 return MakePair(value, *receiver);
9021 case IMMUTABLE_CHECK_INITIALIZED:
9022 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9023 case MISSING_BINDING:
9024 UNREACHABLE();
9025 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009026 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009027 }
9028
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009029 // Otherwise, if the slot was found the holder is a context extension
9030 // object, subject of a with, or a global object. We read the named
9031 // property from it.
9032 if (!holder.is_null()) {
9033 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9034 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009035 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009036 Handle<Object> receiver_handle(object->IsGlobalObject()
9037 ? GlobalObject::cast(*object)->global_receiver()
9038 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009039
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009040 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009041 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009042 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009043 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009044 }
9045
9046 if (throw_error) {
9047 // The property doesn't exist - throw exception.
9048 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009049 isolate->factory()->NewReferenceError("not_defined",
9050 HandleVector(&name, 1));
9051 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009052 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009053 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009054 return MakePair(isolate->heap()->undefined_value(),
9055 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009056 }
9057}
9058
9059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009060RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009061 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009062}
9063
9064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009065RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009066 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009067}
9068
9069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009070RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009071 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009072 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009074 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009075 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009076 CONVERT_ARG_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009077 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9078 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9079 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009080
9081 int index;
9082 PropertyAttributes attributes;
9083 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009084 BindingFlags binding_flags;
9085 Handle<Object> holder = context->Lookup(name,
9086 flags,
9087 &index,
9088 &attributes,
9089 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009090
9091 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009092 // The property was found in a context slot.
9093 Handle<Context> context = Handle<Context>::cast(holder);
9094 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9095 context->get(index)->IsTheHole()) {
9096 Handle<Object> error =
9097 isolate->factory()->NewReferenceError("not_defined",
9098 HandleVector(&name, 1));
9099 return isolate->Throw(*error);
9100 }
9101 // Ignore if read_only variable.
9102 if ((attributes & READ_ONLY) == 0) {
9103 // Context is a fixed array and set cannot fail.
9104 context->set(index, *value);
9105 } else if (strict_mode == kStrictMode) {
9106 // Setting read only property in strict mode.
9107 Handle<Object> error =
9108 isolate->factory()->NewTypeError("strict_cannot_assign",
9109 HandleVector(&name, 1));
9110 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009111 }
9112 return *value;
9113 }
9114
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009115 // Slow case: The property is not in a context slot. It is either in a
9116 // context extension object, a property of the subject of a with, or a
9117 // property of the global object.
9118 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009120 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009121 // The property exists on the holder.
9122 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009123 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009124 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009125 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009126
9127 if (strict_mode == kStrictMode) {
9128 // Throw in strict mode (assignment to undefined variable).
9129 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009130 isolate->factory()->NewReferenceError(
9131 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009132 return isolate->Throw(*error);
9133 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009134 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009135 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009136 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009137 }
9138
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009139 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009140 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009141 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009142 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009143 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009144 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009145 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009146 // Setting read only property in strict mode.
9147 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009148 isolate->factory()->NewTypeError(
9149 "strict_cannot_assign", HandleVector(&name, 1));
9150 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009151 }
9152 return *value;
9153}
9154
9155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009156RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009157 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009158 ASSERT(args.length() == 1);
9159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009160 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009161}
9162
9163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009164RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009165 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166 ASSERT(args.length() == 1);
9167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009168 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009169}
9170
9171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009172RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009173 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009174 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009175}
9176
9177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009178RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009179 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180 ASSERT(args.length() == 1);
9181
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009182 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009183 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009184 isolate->factory()->NewReferenceError("not_defined",
9185 HandleVector(&name, 1));
9186 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009187}
9188
9189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009190RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009191 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009192
9193 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009194 if (isolate->stack_guard()->IsStackOverflow()) {
9195 NoHandleAllocation na;
9196 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009197 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009198
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009199 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009200}
9201
9202
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009203static int StackSize() {
9204 int n = 0;
9205 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9206 return n;
9207}
9208
9209
9210static void PrintTransition(Object* result) {
9211 // indentation
9212 { const int nmax = 80;
9213 int n = StackSize();
9214 if (n <= nmax)
9215 PrintF("%4d:%*s", n, n, "");
9216 else
9217 PrintF("%4d:%*s", n, nmax, "...");
9218 }
9219
9220 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009221 JavaScriptFrame::PrintTop(stdout, true, false);
9222 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009223 } else {
9224 // function result
9225 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009226 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009227 PrintF("\n");
9228 }
9229}
9230
9231
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009232RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
9233 ASSERT(args.length() == 5);
9234 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9235 CONVERT_SMI_ARG_CHECKED(from_kind, 1);
9236 CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
9237 CONVERT_SMI_ARG_CHECKED(to_kind, 3);
9238 CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
9239 NoHandleAllocation ha;
9240 PrintF("*");
9241 obj->PrintElementsTransition(stdout,
9242 static_cast<ElementsKind>(from_kind), *from_elements,
9243 static_cast<ElementsKind>(to_kind), *to_elements);
9244 return isolate->heap()->undefined_value();
9245}
9246
9247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009248RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009249 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009250 NoHandleAllocation ha;
9251 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009252 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009253}
9254
9255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009256RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009257 NoHandleAllocation ha;
9258 PrintTransition(args[0]);
9259 return args[0]; // return TOS
9260}
9261
9262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009263RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009264 NoHandleAllocation ha;
9265 ASSERT(args.length() == 1);
9266
9267#ifdef DEBUG
9268 if (args[0]->IsString()) {
9269 // If we have a string, assume it's a code "marker"
9270 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009271 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009272 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009273 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9274 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009275 } else {
9276 PrintF("DebugPrint: ");
9277 }
9278 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009279 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009280 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009281 HeapObject::cast(args[0])->map()->Print();
9282 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009283#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009284 // ShortPrint is available in release mode. Print is not.
9285 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009286#endif
9287 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009288 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009289
9290 return args[0]; // return TOS
9291}
9292
9293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009294RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009295 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009296 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009297 isolate->PrintStack();
9298 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009299}
9300
9301
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009302RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009303 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009304 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009305
9306 // According to ECMA-262, section 15.9.1, page 117, the precision of
9307 // the number in a Date object representing a particular instant in
9308 // time is milliseconds. Therefore, we floor the result of getting
9309 // the OS time.
9310 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009311 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312}
9313
9314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009315RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009316 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009317 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009318
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009319 CONVERT_ARG_CHECKED(String, str, 0);
9320 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009321
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009322 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009323
9324 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009325 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009326 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009327 RUNTIME_ASSERT(output->HasFastElements());
9328
9329 AssertNoAllocation no_allocation;
9330
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009331 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009332 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9333 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009334 String::FlatContent str_content = str->GetFlatContent();
9335 if (str_content.IsAscii()) {
9336 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009337 output_array,
9338 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009339 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009340 ASSERT(str_content.IsTwoByte());
9341 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009342 output_array,
9343 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009344 }
9345
9346 if (result) {
9347 return *output;
9348 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009349 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009350 }
9351}
9352
9353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009354RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009355 NoHandleAllocation ha;
9356 ASSERT(args.length() == 1);
9357
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009358 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009359 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009360 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009361}
9362
9363
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009364RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009365 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009366 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009368 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009369}
9370
9371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009372RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009373 NoHandleAllocation ha;
9374 ASSERT(args.length() == 1);
9375
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009376 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009377 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009378}
9379
9380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009381RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009382 ASSERT(args.length() == 1);
9383 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009384 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009385 return JSGlobalObject::cast(global)->global_receiver();
9386}
9387
9388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009389RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009390 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009391 ASSERT_EQ(1, args.length());
9392 CONVERT_ARG_CHECKED(String, source, 0);
9393
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009394 source = Handle<String>(source->TryFlattenGetString());
9395 // Optimized fast case where we only have ascii characters.
9396 Handle<Object> result;
9397 if (source->IsSeqAsciiString()) {
9398 result = JsonParser<true>::Parse(source);
9399 } else {
9400 result = JsonParser<false>::Parse(source);
9401 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009402 if (result.is_null()) {
9403 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009404 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009405 return Failure::Exception();
9406 }
9407 return *result;
9408}
9409
9410
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009411bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9412 Handle<Context> context) {
9413 if (context->allow_code_gen_from_strings()->IsFalse()) {
9414 // Check with callback if set.
9415 AllowCodeGenerationFromStringsCallback callback =
9416 isolate->allow_code_gen_callback();
9417 if (callback == NULL) {
9418 // No callback set and code generation disallowed.
9419 return false;
9420 } else {
9421 // Callback set. Let it decide if code generation is allowed.
9422 VMState state(isolate, EXTERNAL);
9423 return callback(v8::Utils::ToLocal(context));
9424 }
9425 }
9426 return true;
9427}
9428
9429
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009430RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009431 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009432 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009433 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009434
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009435 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009437
9438 // Check if global context allows code generation from
9439 // strings. Throw an exception if it doesn't.
9440 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9441 return isolate->Throw(*isolate->factory()->NewError(
9442 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9443 }
9444
9445 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009446 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009447 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009448 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009449 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009450 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9451 context,
9452 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009453 return *fun;
9454}
9455
9456
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009457static ObjectPair CompileGlobalEval(Isolate* isolate,
9458 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009459 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009460 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009461 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009462 Handle<Context> context = Handle<Context>(isolate->context());
9463 Handle<Context> global_context = Handle<Context>(context->global_context());
9464
9465 // Check if global context allows code generation from
9466 // strings. Throw an exception if it doesn't.
9467 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9468 isolate->Throw(*isolate->factory()->NewError(
9469 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9470 return MakePair(Failure::Exception(), NULL);
9471 }
9472
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009473 // Deal with a normal eval call with a string argument. Compile it
9474 // and return the compiled function bound in the local context.
9475 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9476 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009477 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009478 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009479 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009480 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009481 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009482 Handle<JSFunction> compiled =
9483 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009484 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009485 return MakePair(*compiled, *receiver);
9486}
9487
9488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009489RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009490 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009492 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009493 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009494
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009495 // If "eval" didn't refer to the original GlobalEval, it's not a
9496 // direct call to eval.
9497 // (And even if it is, but the first argument isn't a string, just let
9498 // execution default to an indirect call to eval, which will also return
9499 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009500 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009501 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009502 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009503 }
9504
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009505 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009506 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009507 return CompileGlobalEval(isolate,
9508 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009509 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009510 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009511 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009512}
9513
9514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009515RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009516 // This utility adjusts the property attributes for newly created Function
9517 // object ("new Function(...)") by changing the map.
9518 // All it does is changing the prototype property to enumerable
9519 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009520 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009521 ASSERT(args.length() == 1);
9522 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009523
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009524 Handle<Map> map = func->shared()->is_classic_mode()
9525 ? isolate->function_instance_map()
9526 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009527
9528 ASSERT(func->map()->instance_type() == map->instance_type());
9529 ASSERT(func->map()->instance_size() == map->instance_size());
9530 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009531 return *func;
9532}
9533
9534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009535RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009536 // Allocate a block of memory in NewSpace (filled with a filler).
9537 // Use as fallback for allocation in generated code when NewSpace
9538 // is full.
9539 ASSERT(args.length() == 1);
9540 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9541 int size = size_smi->value();
9542 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9543 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009544 Heap* heap = isolate->heap();
9545 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009546 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009547 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009548 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009549 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009550 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009551 }
9552 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009553 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009554}
9555
9556
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009557// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009558// array. Returns true if the element was pushed on the stack and
9559// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009560RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009561 ASSERT(args.length() == 2);
9562 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009563 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009564 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009565 int length = Smi::cast(array->length())->value();
9566 FixedArray* elements = FixedArray::cast(array->elements());
9567 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009568 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009569 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009570 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009571 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009572 { MaybeObject* maybe_obj =
9573 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009574 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9575 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009576 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009577}
9578
9579
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009580/**
9581 * A simple visitor visits every element of Array's.
9582 * The backend storage can be a fixed array for fast elements case,
9583 * or a dictionary for sparse array. Since Dictionary is a subtype
9584 * of FixedArray, the class can be used by both fast and slow cases.
9585 * The second parameter of the constructor, fast_elements, specifies
9586 * whether the storage is a FixedArray or Dictionary.
9587 *
9588 * An index limit is used to deal with the situation that a result array
9589 * length overflows 32-bit non-negative integer.
9590 */
9591class ArrayConcatVisitor {
9592 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009593 ArrayConcatVisitor(Isolate* isolate,
9594 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009595 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009596 isolate_(isolate),
9597 storage_(Handle<FixedArray>::cast(
9598 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009599 index_offset_(0u),
9600 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009601
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009602 ~ArrayConcatVisitor() {
9603 clear_storage();
9604 }
9605
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009606 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009607 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009608 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009609
9610 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009611 if (index < static_cast<uint32_t>(storage_->length())) {
9612 storage_->set(index, *elm);
9613 return;
9614 }
9615 // Our initial estimate of length was foiled, possibly by
9616 // getters on the arrays increasing the length of later arrays
9617 // during iteration.
9618 // This shouldn't happen in anything but pathological cases.
9619 SetDictionaryMode(index);
9620 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009621 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009622 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009623 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009624 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009625 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009626 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009627 // Dictionary needed to grow.
9628 clear_storage();
9629 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009630 }
9631}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009632
9633 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009634 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9635 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009636 } else {
9637 index_offset_ += delta;
9638 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009639 }
9640
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009641 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009642 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009643 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009644 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009645 Handle<Map> map;
9646 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009647 map = isolate_->factory()->GetElementsTransitionMap(array,
9648 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009649 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009650 map = isolate_->factory()->GetElementsTransitionMap(array,
9651 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009652 }
9653 array->set_map(*map);
9654 array->set_length(*length);
9655 array->set_elements(*storage_);
9656 return array;
9657 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009658
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009659 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009660 // Convert storage to dictionary mode.
9661 void SetDictionaryMode(uint32_t index) {
9662 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009663 Handle<FixedArray> current_storage(*storage_);
9664 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009665 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009666 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9667 for (uint32_t i = 0; i < current_length; i++) {
9668 HandleScope loop_scope;
9669 Handle<Object> element(current_storage->get(i));
9670 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009671 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009672 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009673 if (!new_storage.is_identical_to(slow_storage)) {
9674 slow_storage = loop_scope.CloseAndEscape(new_storage);
9675 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009676 }
9677 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009678 clear_storage();
9679 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009680 fast_elements_ = false;
9681 }
9682
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009683 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009684 isolate_->global_handles()->Destroy(
9685 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009686 }
9687
9688 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009689 storage_ = Handle<FixedArray>::cast(
9690 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009691 }
9692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009693 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009694 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009695 // Index after last seen index. Always less than or equal to
9696 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009697 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009698 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009699};
9700
9701
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009702static uint32_t EstimateElementCount(Handle<JSArray> array) {
9703 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9704 int element_count = 0;
9705 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009706 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009707 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009708 // Fast elements can't have lengths that are not representable by
9709 // a 32-bit signed integer.
9710 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9711 int fast_length = static_cast<int>(length);
9712 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9713 for (int i = 0; i < fast_length; i++) {
9714 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009715 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009716 break;
9717 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009718 case FAST_DOUBLE_ELEMENTS:
9719 // TODO(1810): Decide if it's worthwhile to implement this.
9720 UNREACHABLE();
9721 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009722 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009723 Handle<NumberDictionary> dictionary(
9724 NumberDictionary::cast(array->elements()));
9725 int capacity = dictionary->Capacity();
9726 for (int i = 0; i < capacity; i++) {
9727 Handle<Object> key(dictionary->KeyAt(i));
9728 if (dictionary->IsKey(*key)) {
9729 element_count++;
9730 }
9731 }
9732 break;
9733 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009734 case NON_STRICT_ARGUMENTS_ELEMENTS:
9735 case EXTERNAL_BYTE_ELEMENTS:
9736 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9737 case EXTERNAL_SHORT_ELEMENTS:
9738 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9739 case EXTERNAL_INT_ELEMENTS:
9740 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9741 case EXTERNAL_FLOAT_ELEMENTS:
9742 case EXTERNAL_DOUBLE_ELEMENTS:
9743 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009744 // External arrays are always dense.
9745 return length;
9746 }
9747 // As an estimate, we assume that the prototype doesn't contain any
9748 // inherited elements.
9749 return element_count;
9750}
9751
9752
9753
9754template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009755static void IterateExternalArrayElements(Isolate* isolate,
9756 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009757 bool elements_are_ints,
9758 bool elements_are_guaranteed_smis,
9759 ArrayConcatVisitor* visitor) {
9760 Handle<ExternalArrayClass> array(
9761 ExternalArrayClass::cast(receiver->elements()));
9762 uint32_t len = static_cast<uint32_t>(array->length());
9763
9764 ASSERT(visitor != NULL);
9765 if (elements_are_ints) {
9766 if (elements_are_guaranteed_smis) {
9767 for (uint32_t j = 0; j < len; j++) {
9768 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009769 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009770 visitor->visit(j, e);
9771 }
9772 } else {
9773 for (uint32_t j = 0; j < len; j++) {
9774 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009775 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009776 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9777 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9778 visitor->visit(j, e);
9779 } else {
9780 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009781 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009782 visitor->visit(j, e);
9783 }
9784 }
9785 }
9786 } else {
9787 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009788 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009789 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009790 visitor->visit(j, e);
9791 }
9792 }
9793}
9794
9795
9796// Used for sorting indices in a List<uint32_t>.
9797static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9798 uint32_t a = *ap;
9799 uint32_t b = *bp;
9800 return (a == b) ? 0 : (a < b) ? -1 : 1;
9801}
9802
9803
9804static void CollectElementIndices(Handle<JSObject> object,
9805 uint32_t range,
9806 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009807 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009808 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009809 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009810 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009811 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9812 uint32_t length = static_cast<uint32_t>(elements->length());
9813 if (range < length) length = range;
9814 for (uint32_t i = 0; i < length; i++) {
9815 if (!elements->get(i)->IsTheHole()) {
9816 indices->Add(i);
9817 }
9818 }
9819 break;
9820 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009821 case FAST_DOUBLE_ELEMENTS: {
9822 // TODO(1810): Decide if it's worthwhile to implement this.
9823 UNREACHABLE();
9824 break;
9825 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009826 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009827 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009828 uint32_t capacity = dict->Capacity();
9829 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009830 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009831 Handle<Object> k(dict->KeyAt(j));
9832 if (dict->IsKey(*k)) {
9833 ASSERT(k->IsNumber());
9834 uint32_t index = static_cast<uint32_t>(k->Number());
9835 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009836 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009837 }
9838 }
9839 }
9840 break;
9841 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009842 default: {
9843 int dense_elements_length;
9844 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009845 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009846 dense_elements_length =
9847 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009848 break;
9849 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009850 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009851 dense_elements_length =
9852 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009853 break;
9854 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009855 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009856 dense_elements_length =
9857 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009858 break;
9859 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009860 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009861 dense_elements_length =
9862 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009863 break;
9864 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009865 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009866 dense_elements_length =
9867 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009868 break;
9869 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009870 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009871 dense_elements_length =
9872 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009873 break;
9874 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009875 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009876 dense_elements_length =
9877 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009878 break;
9879 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009880 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009881 dense_elements_length =
9882 ExternalFloatArray::cast(object->elements())->length();
9883 break;
9884 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009885 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009886 dense_elements_length =
9887 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009888 break;
9889 }
9890 default:
9891 UNREACHABLE();
9892 dense_elements_length = 0;
9893 break;
9894 }
9895 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9896 if (range <= length) {
9897 length = range;
9898 // We will add all indices, so we might as well clear it first
9899 // and avoid duplicates.
9900 indices->Clear();
9901 }
9902 for (uint32_t i = 0; i < length; i++) {
9903 indices->Add(i);
9904 }
9905 if (length == range) return; // All indices accounted for already.
9906 break;
9907 }
9908 }
9909
9910 Handle<Object> prototype(object->GetPrototype());
9911 if (prototype->IsJSObject()) {
9912 // The prototype will usually have no inherited element indices,
9913 // but we have to check.
9914 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9915 }
9916}
9917
9918
9919/**
9920 * A helper function that visits elements of a JSArray in numerical
9921 * order.
9922 *
9923 * The visitor argument called for each existing element in the array
9924 * with the element index and the element's value.
9925 * Afterwards it increments the base-index of the visitor by the array
9926 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009927 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009928 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009929static bool IterateElements(Isolate* isolate,
9930 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009931 ArrayConcatVisitor* visitor) {
9932 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9933 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009934 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009935 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009936 // Run through the elements FixedArray and use HasElement and GetElement
9937 // to check the prototype for missing elements.
9938 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9939 int fast_length = static_cast<int>(length);
9940 ASSERT(fast_length <= elements->length());
9941 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009942 HandleScope loop_scope(isolate);
9943 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009944 if (!element_value->IsTheHole()) {
9945 visitor->visit(j, element_value);
9946 } else if (receiver->HasElement(j)) {
9947 // Call GetElement on receiver, not its prototype, or getters won't
9948 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009949 element_value = Object::GetElement(receiver, j);
9950 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009951 visitor->visit(j, element_value);
9952 }
9953 }
9954 break;
9955 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009956 case FAST_DOUBLE_ELEMENTS: {
9957 // TODO(1810): Decide if it's worthwhile to implement this.
9958 UNREACHABLE();
9959 break;
9960 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009961 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009962 Handle<NumberDictionary> dict(receiver->element_dictionary());
9963 List<uint32_t> indices(dict->Capacity() / 2);
9964 // Collect all indices in the object and the prototypes less
9965 // than length. This might introduce duplicates in the indices list.
9966 CollectElementIndices(receiver, length, &indices);
9967 indices.Sort(&compareUInt32);
9968 int j = 0;
9969 int n = indices.length();
9970 while (j < n) {
9971 HandleScope loop_scope;
9972 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009973 Handle<Object> element = Object::GetElement(receiver, index);
9974 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009975 visitor->visit(index, element);
9976 // Skip to next different index (i.e., omit duplicates).
9977 do {
9978 j++;
9979 } while (j < n && indices[j] == index);
9980 }
9981 break;
9982 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009983 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009984 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9985 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009986 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009987 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009988 visitor->visit(j, e);
9989 }
9990 break;
9991 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009992 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009993 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009994 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009995 break;
9996 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009997 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009998 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009999 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010000 break;
10001 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010002 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010003 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010004 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010005 break;
10006 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010007 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010008 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010009 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010010 break;
10011 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010012 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010013 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010014 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010015 break;
10016 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010017 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010018 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010019 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010020 break;
10021 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010022 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010023 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010024 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010025 break;
10026 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010027 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010028 IterateExternalArrayElements<ExternalDoubleArray, double>(
10029 isolate, receiver, false, false, visitor);
10030 break;
10031 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010032 default:
10033 UNREACHABLE();
10034 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010035 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010036 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010037 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010038}
10039
10040
10041/**
10042 * Array::concat implementation.
10043 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010044 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010045 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010046 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010047RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010048 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010049 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010050
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010051 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10052 int argument_count = static_cast<int>(arguments->length()->Number());
10053 RUNTIME_ASSERT(arguments->HasFastElements());
10054 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010055
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010056 // Pass 1: estimate the length and number of elements of the result.
10057 // The actual length can be larger if any of the arguments have getters
10058 // that mutate other arguments (but will otherwise be precise).
10059 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010060
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010061 uint32_t estimate_result_length = 0;
10062 uint32_t estimate_nof_elements = 0;
10063 {
10064 for (int i = 0; i < argument_count; i++) {
10065 HandleScope loop_scope;
10066 Handle<Object> obj(elements->get(i));
10067 uint32_t length_estimate;
10068 uint32_t element_estimate;
10069 if (obj->IsJSArray()) {
10070 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010071 // TODO(1810): Find out if it's worthwhile to properly support
10072 // arbitrary ElementsKinds. For now, pessimistically transition to
10073 // FAST_ELEMENTS.
10074 if (array->HasFastDoubleElements()) {
10075 array = Handle<JSArray>::cast(
10076 TransitionElementsKind(array, FAST_ELEMENTS));
10077 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010078 length_estimate =
10079 static_cast<uint32_t>(array->length()->Number());
10080 element_estimate =
10081 EstimateElementCount(array);
10082 } else {
10083 length_estimate = 1;
10084 element_estimate = 1;
10085 }
10086 // Avoid overflows by capping at kMaxElementCount.
10087 if (JSObject::kMaxElementCount - estimate_result_length <
10088 length_estimate) {
10089 estimate_result_length = JSObject::kMaxElementCount;
10090 } else {
10091 estimate_result_length += length_estimate;
10092 }
10093 if (JSObject::kMaxElementCount - estimate_nof_elements <
10094 element_estimate) {
10095 estimate_nof_elements = JSObject::kMaxElementCount;
10096 } else {
10097 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010098 }
10099 }
10100 }
10101
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010102 // If estimated number of elements is more than half of length, a
10103 // fixed array (fast case) is more time and space-efficient than a
10104 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010105 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010106
10107 Handle<FixedArray> storage;
10108 if (fast_case) {
10109 // The backing storage array must have non-existing elements to
10110 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010111 storage = isolate->factory()->NewFixedArrayWithHoles(
10112 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010113 } else {
10114 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10115 uint32_t at_least_space_for = estimate_nof_elements +
10116 (estimate_nof_elements >> 2);
10117 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010118 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010119 }
10120
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010121 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010122
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010123 for (int i = 0; i < argument_count; i++) {
10124 Handle<Object> obj(elements->get(i));
10125 if (obj->IsJSArray()) {
10126 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010127 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010128 return Failure::Exception();
10129 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010130 } else {
10131 visitor.visit(0, obj);
10132 visitor.increase_index_offset(1);
10133 }
10134 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010135
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010136 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010137}
10138
10139
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010140// This will not allocate (flatten the string), but it may run
10141// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010142RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010143 NoHandleAllocation ha;
10144 ASSERT(args.length() == 1);
10145
10146 CONVERT_CHECKED(String, string, args[0]);
10147 StringInputBuffer buffer(string);
10148 while (buffer.has_more()) {
10149 uint16_t character = buffer.GetNext();
10150 PrintF("%c", character);
10151 }
10152 return string;
10153}
10154
ager@chromium.org5ec48922009-05-05 07:25:34 +000010155// Moves all own elements of an object, that are below a limit, to positions
10156// starting at zero. All undefined values are placed after non-undefined values,
10157// and are followed by non-existing element. Does not change the length
10158// property.
10159// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010160RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010161 ASSERT(args.length() == 2);
10162 CONVERT_CHECKED(JSObject, object, args[0]);
10163 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10164 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010165}
10166
10167
10168// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010169RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010170 ASSERT(args.length() == 2);
10171 CONVERT_CHECKED(JSArray, from, args[0]);
10172 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010173 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010174 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010175 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010176 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10177 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010178 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010179 } else if (new_elements->map() ==
10180 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010181 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010182 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010183 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010184 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010185 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010186 Object* new_map;
10187 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010188 to->set_map(Map::cast(new_map));
10189 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010190 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010191 Object* obj;
10192 { MaybeObject* maybe_obj = from->ResetElements();
10193 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10194 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010195 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010196 return to;
10197}
10198
10199
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010200// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010201RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010202 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010203 CONVERT_CHECKED(JSObject, object, args[0]);
10204 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010205 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010206 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010207 } else if (object->IsJSArray()) {
10208 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010209 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010210 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010211 }
10212}
10213
10214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010215RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010216 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010217
10218 ASSERT_EQ(3, args.length());
10219
ager@chromium.orgac091b72010-05-05 07:34:42 +000010220 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010221 Handle<Object> key1 = args.at<Object>(1);
10222 Handle<Object> key2 = args.at<Object>(2);
10223
10224 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010225 if (!key1->ToArrayIndex(&index1)
10226 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010227 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010228 }
10229
ager@chromium.orgac091b72010-05-05 07:34:42 +000010230 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010231 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010232 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010233 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010234 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010235
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010236 RETURN_IF_EMPTY_HANDLE(isolate,
10237 SetElement(jsobject, index1, tmp2, kStrictMode));
10238 RETURN_IF_EMPTY_HANDLE(isolate,
10239 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010240
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010241 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010242}
10243
10244
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010246// might have elements. Can either return keys (positive integers) or
10247// intervals (pair of a negative integer (-start-1) followed by a
10248// positive (length)) or undefined values.
10249// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010250RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010251 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010252 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010253 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010255 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256 // Create an array and get all the keys into it, then remove all the
10257 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010258 bool threw = false;
10259 Handle<FixedArray> keys =
10260 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10261 if (threw) return Failure::Exception();
10262
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010263 int keys_length = keys->length();
10264 for (int i = 0; i < keys_length; i++) {
10265 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010266 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010267 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010268 // Zap invalid keys.
10269 keys->set_undefined(i);
10270 }
10271 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010272 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010273 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010274 ASSERT(array->HasFastElements() ||
10275 array->HasFastSmiOnlyElements() ||
10276 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010277 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010278 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010279 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010280 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010281 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010282 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010283 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010285 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010287 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010288 }
10289}
10290
10291
10292// DefineAccessor takes an optional final argument which is the
10293// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10294// to the way accessors are implemented, it is set for both the getter
10295// and setter on the first call to DefineAccessor and ignored on
10296// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010297RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10299 // Compute attributes.
10300 PropertyAttributes attributes = NONE;
10301 if (args.length() == 5) {
10302 CONVERT_CHECKED(Smi, attrs, args[4]);
10303 int value = attrs->value();
10304 // Only attribute bits should be set.
10305 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10306 attributes = static_cast<PropertyAttributes>(value);
10307 }
10308
10309 CONVERT_CHECKED(JSObject, obj, args[0]);
10310 CONVERT_CHECKED(String, name, args[1]);
10311 CONVERT_CHECKED(Smi, flag, args[2]);
10312 CONVERT_CHECKED(JSFunction, fun, args[3]);
10313 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10314}
10315
10316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010317RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010318 ASSERT(args.length() == 3);
10319 CONVERT_CHECKED(JSObject, obj, args[0]);
10320 CONVERT_CHECKED(String, name, args[1]);
10321 CONVERT_CHECKED(Smi, flag, args[2]);
10322 return obj->LookupAccessor(name, flag->value() == 0);
10323}
10324
10325
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010326#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010327RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010328 ASSERT(args.length() == 0);
10329 return Execution::DebugBreakHelper();
10330}
10331
10332
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333// Helper functions for wrapping and unwrapping stack frame ids.
10334static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010335 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010336 return Smi::FromInt(id >> 2);
10337}
10338
10339
10340static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10341 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10342}
10343
10344
10345// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010346// args[0]: debug event listener function to set or null or undefined for
10347// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010348// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010349RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010351 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10352 args[0]->IsUndefined() ||
10353 args[0]->IsNull());
10354 Handle<Object> callback = args.at<Object>(0);
10355 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010356 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010357
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010358 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010359}
10360
10361
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010362RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010363 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010364 isolate->stack_guard()->DebugBreak();
10365 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010366}
10367
10368
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010369static MaybeObject* DebugLookupResultValue(Heap* heap,
10370 Object* receiver,
10371 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010372 LookupResult* result,
10373 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010374 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010375 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010376 case NORMAL:
10377 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010378 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010379 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010380 }
10381 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010382 case FIELD:
10383 value =
10384 JSObject::cast(
10385 result->holder())->FastPropertyAt(result->GetFieldIndex());
10386 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010387 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010388 }
10389 return value;
10390 case CONSTANT_FUNCTION:
10391 return result->GetConstantFunction();
10392 case CALLBACKS: {
10393 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010394 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010395 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10396 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010397 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010398 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010399 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010400 maybe_value = heap->isolate()->pending_exception();
10401 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010402 if (caught_exception != NULL) {
10403 *caught_exception = true;
10404 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010405 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010406 }
10407 return value;
10408 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010409 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010410 }
10411 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010412 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010413 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010414 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010415 case CONSTANT_TRANSITION:
10416 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010417 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010418 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010420 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010422 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010423 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010424}
10425
10426
ager@chromium.org32912102009-01-16 10:38:43 +000010427// Get debugger related details for an object property.
10428// args[0]: object holding property
10429// args[1]: name of the property
10430//
10431// The array returned contains the following information:
10432// 0: Property value
10433// 1: Property details
10434// 2: Property value is exception
10435// 3: Getter function if defined
10436// 4: Setter function if defined
10437// Items 2-4 are only filled if the property has either a getter or a setter
10438// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010439RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010440 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010441
10442 ASSERT(args.length() == 2);
10443
10444 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10445 CONVERT_ARG_CHECKED(String, name, 1);
10446
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010447 // Make sure to set the current context to the context before the debugger was
10448 // entered (if the debugger is entered). The reason for switching context here
10449 // is that for some property lookups (accessors and interceptors) callbacks
10450 // into the embedding application can occour, and the embedding application
10451 // could have the assumption that its own global context is the current
10452 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010453 SaveContext save(isolate);
10454 if (isolate->debug()->InDebugger()) {
10455 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010456 }
10457
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010458 // Skip the global proxy as it has no properties and always delegates to the
10459 // real global object.
10460 if (obj->IsJSGlobalProxy()) {
10461 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10462 }
10463
10464
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010465 // Check if the name is trivially convertible to an index and get the element
10466 // if so.
10467 uint32_t index;
10468 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010469 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010470 Object* element_or_char;
10471 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010472 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010473 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10474 return maybe_element_or_char;
10475 }
10476 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010477 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010478 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010479 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010480 }
10481
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010482 // Find the number of objects making up this.
10483 int length = LocalPrototypeChainLength(*obj);
10484
10485 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010486 Handle<JSObject> jsproto = obj;
10487 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010488 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010489 jsproto->LocalLookup(*name, &result);
10490 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010491 // LookupResult is not GC safe as it holds raw object pointers.
10492 // GC can happen later in this code so put the required fields into
10493 // local variables using handles when required for later use.
10494 PropertyType result_type = result.type();
10495 Handle<Object> result_callback_obj;
10496 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010497 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10498 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010499 }
10500 Smi* property_details = result.GetPropertyDetails().AsSmi();
10501 // DebugLookupResultValue can cause GC so details from LookupResult needs
10502 // to be copied to handles before this.
10503 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010504 Object* raw_value;
10505 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010506 DebugLookupResultValue(isolate->heap(), *obj, *name,
10507 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010508 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10509 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010510 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010511
10512 // If the callback object is a fixed array then it contains JavaScript
10513 // getter and/or setter.
10514 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10515 result_callback_obj->IsFixedArray();
10516 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010517 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010518 details->set(0, *value);
10519 details->set(1, property_details);
10520 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010521 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010522 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10523 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10524 }
10525
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010526 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010527 }
10528 if (i < length - 1) {
10529 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10530 }
10531 }
10532
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010533 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534}
10535
10536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010537RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010538 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010539
10540 ASSERT(args.length() == 2);
10541
10542 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10543 CONVERT_ARG_CHECKED(String, name, 1);
10544
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010545 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010546 obj->Lookup(*name, &result);
10547 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010548 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010549 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010550 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010551}
10552
10553
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010554// Return the property type calculated from the property details.
10555// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010556RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010557 ASSERT(args.length() == 1);
10558 CONVERT_CHECKED(Smi, details, args[0]);
10559 PropertyType type = PropertyDetails(details).type();
10560 return Smi::FromInt(static_cast<int>(type));
10561}
10562
10563
10564// Return the property attribute calculated from the property details.
10565// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010566RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010567 ASSERT(args.length() == 1);
10568 CONVERT_CHECKED(Smi, details, args[0]);
10569 PropertyAttributes attributes = PropertyDetails(details).attributes();
10570 return Smi::FromInt(static_cast<int>(attributes));
10571}
10572
10573
10574// Return the property insertion index calculated from the property details.
10575// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010576RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010577 ASSERT(args.length() == 1);
10578 CONVERT_CHECKED(Smi, details, args[0]);
10579 int index = PropertyDetails(details).index();
10580 return Smi::FromInt(index);
10581}
10582
10583
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584// Return property value from named interceptor.
10585// args[0]: object
10586// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010587RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010588 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010589 ASSERT(args.length() == 2);
10590 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10591 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10592 CONVERT_ARG_CHECKED(String, name, 1);
10593
10594 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010595 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010596}
10597
10598
10599// Return element value from indexed interceptor.
10600// args[0]: object
10601// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010602RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010603 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604 ASSERT(args.length() == 2);
10605 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10606 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10607 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10608
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010609 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010610}
10611
10612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010613RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010614 ASSERT(args.length() >= 1);
10615 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010616 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010617 if (isolate->debug()->break_id() == 0 ||
10618 break_id != isolate->debug()->break_id()) {
10619 return isolate->Throw(
10620 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 }
10622
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010623 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010624}
10625
10626
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010627RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010628 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010629 ASSERT(args.length() == 1);
10630
10631 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010632 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010633 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10634 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010635 if (!maybe_result->ToObject(&result)) return maybe_result;
10636 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010637
10638 // Count all frames which are relevant to debugging stack trace.
10639 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010640 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010641 if (id == StackFrame::NO_ID) {
10642 // If there is no JavaScript stack frame count is 0.
10643 return Smi::FromInt(0);
10644 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010645
10646 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10647 n += it.frame()->GetInlineCount();
10648 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010649 return Smi::FromInt(n);
10650}
10651
10652
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010653class FrameInspector {
10654 public:
10655 FrameInspector(JavaScriptFrame* frame,
10656 int inlined_frame_index,
10657 Isolate* isolate)
10658 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10659 // Calculate the deoptimized frame.
10660 if (frame->is_optimized()) {
10661 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10662 frame, inlined_frame_index, isolate);
10663 }
10664 has_adapted_arguments_ = frame_->has_adapted_arguments();
10665 is_optimized_ = frame_->is_optimized();
10666 }
10667
10668 ~FrameInspector() {
10669 // Get rid of the calculated deoptimized frame if any.
10670 if (deoptimized_frame_ != NULL) {
10671 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10672 isolate_);
10673 }
10674 }
10675
10676 int GetParametersCount() {
10677 return is_optimized_
10678 ? deoptimized_frame_->parameters_count()
10679 : frame_->ComputeParametersCount();
10680 }
10681 int expression_count() { return deoptimized_frame_->expression_count(); }
10682 Object* GetFunction() {
10683 return is_optimized_
10684 ? deoptimized_frame_->GetFunction()
10685 : frame_->function();
10686 }
10687 Object* GetParameter(int index) {
10688 return is_optimized_
10689 ? deoptimized_frame_->GetParameter(index)
10690 : frame_->GetParameter(index);
10691 }
10692 Object* GetExpression(int index) {
10693 return is_optimized_
10694 ? deoptimized_frame_->GetExpression(index)
10695 : frame_->GetExpression(index);
10696 }
10697
10698 // To inspect all the provided arguments the frame might need to be
10699 // replaced with the arguments frame.
10700 void SetArgumentsFrame(JavaScriptFrame* frame) {
10701 ASSERT(has_adapted_arguments_);
10702 frame_ = frame;
10703 is_optimized_ = frame_->is_optimized();
10704 ASSERT(!is_optimized_);
10705 }
10706
10707 private:
10708 JavaScriptFrame* frame_;
10709 DeoptimizedFrameInfo* deoptimized_frame_;
10710 Isolate* isolate_;
10711 bool is_optimized_;
10712 bool has_adapted_arguments_;
10713
10714 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10715};
10716
10717
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010718static const int kFrameDetailsFrameIdIndex = 0;
10719static const int kFrameDetailsReceiverIndex = 1;
10720static const int kFrameDetailsFunctionIndex = 2;
10721static const int kFrameDetailsArgumentCountIndex = 3;
10722static const int kFrameDetailsLocalCountIndex = 4;
10723static const int kFrameDetailsSourcePositionIndex = 5;
10724static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010725static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010726static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010727static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010728
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010729
10730static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10731 JavaScriptFrame* frame) {
10732 SaveContext* save = isolate->save_context();
10733 while (save != NULL && !save->IsBelowFrame(frame)) {
10734 save = save->prev();
10735 }
10736 ASSERT(save != NULL);
10737 return save;
10738}
10739
10740
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010741// Return an array with frame details
10742// args[0]: number: break id
10743// args[1]: number: frame index
10744//
10745// The array returned contains the following information:
10746// 0: Frame id
10747// 1: Receiver
10748// 2: Function
10749// 3: Argument count
10750// 4: Local count
10751// 5: Source position
10752// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010753// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010754// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010755// Arguments name, value
10756// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010757// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010758RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010759 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010760 ASSERT(args.length() == 2);
10761
10762 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010763 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010764 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10765 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010766 if (!maybe_check->ToObject(&check)) return maybe_check;
10767 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010769 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010770
10771 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010772 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010773 if (id == StackFrame::NO_ID) {
10774 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010775 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010776 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010777
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010778 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010779
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010781 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010782 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010783 if (index < count + it.frame()->GetInlineCount()) break;
10784 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010785 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010786 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010787
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010788 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010789 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010790 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010791 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010792 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010793
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010794 // Traverse the saved contexts chain to find the active context for the
10795 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010796 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010797
10798 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010799 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010800
10801 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010802 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010803 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010804
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010805 // Check for constructor frame. Inlined frames cannot be construct calls.
10806 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010807 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010808 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010809
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010810 // Get scope info and read from it for local variable information.
10811 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010812 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010813 Handle<ScopeInfo> scope_info(shared->scope_info());
10814 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010815
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010816 // Get the locals names and values into a temporary array.
10817 //
10818 // TODO(1240907): Hide compiler-introduced stack variables
10819 // (e.g. .result)? For users of the debugger, they will probably be
10820 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010821 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010822 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010823
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010824 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010825 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010826 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010827 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010828 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010829 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010830 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010831 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010832 // Get the context containing declarations.
10833 Handle<Context> context(
10834 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010835 for (; i < scope_info->LocalCount(); ++i) {
10836 Handle<String> name(scope_info->LocalName(i));
10837 VariableMode mode;
10838 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010839 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010840 locals->set(i * 2 + 1, context->get(
10841 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 }
10843 }
10844
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010845 // Check whether this frame is positioned at return. If not top
10846 // frame or if the frame is optimized it cannot be at a return.
10847 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010848 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010849 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010850 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010851
10852 // If positioned just before return find the value to be returned and add it
10853 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010854 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010855 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010856 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010857 Address internal_frame_sp = NULL;
10858 while (!it2.done()) {
10859 if (it2.frame()->is_internal()) {
10860 internal_frame_sp = it2.frame()->sp();
10861 } else {
10862 if (it2.frame()->is_java_script()) {
10863 if (it2.frame()->id() == it.frame()->id()) {
10864 // The internal frame just before the JavaScript frame contains the
10865 // value to return on top. A debug break at return will create an
10866 // internal frame to store the return value (eax/rax/r0) before
10867 // entering the debug break exit frame.
10868 if (internal_frame_sp != NULL) {
10869 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010870 Handle<Object>(Memory::Object_at(internal_frame_sp),
10871 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010872 break;
10873 }
10874 }
10875 }
10876
10877 // Indicate that the previous frame was not an internal frame.
10878 internal_frame_sp = NULL;
10879 }
10880 it2.Advance();
10881 }
10882 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010883
10884 // Now advance to the arguments adapter frame (if any). It contains all
10885 // the provided parameters whereas the function frame always have the number
10886 // of arguments matching the functions parameters. The rest of the
10887 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010888 if (it.frame()->has_adapted_arguments()) {
10889 it.AdvanceToArgumentsFrame();
10890 frame_inspector.SetArgumentsFrame(it.frame());
10891 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010892
10893 // Find the number of arguments to fill. At least fill the number of
10894 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010895 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010896 if (argument_count < frame_inspector.GetParametersCount()) {
10897 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010898 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010899#ifdef DEBUG
10900 if (it.frame()->is_optimized()) {
10901 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10902 }
10903#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010904
10905 // Calculate the size of the result.
10906 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010907 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010908 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010909 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010910
10911 // Add the frame id.
10912 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10913
10914 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010915 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010916
10917 // Add the arguments count.
10918 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10919
10920 // Add the locals count
10921 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010922 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010923
10924 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010925 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010926 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10927 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010928 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010929 }
10930
10931 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010932 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010933
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010934 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010935 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010936
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010937 // Add flags to indicate information on whether this frame is
10938 // bit 0: invoked in the debugger context.
10939 // bit 1: optimized frame.
10940 // bit 2: inlined in optimized frame
10941 int flags = 0;
10942 if (*save->context() == *isolate->debug()->debug_context()) {
10943 flags |= 1 << 0;
10944 }
10945 if (it.frame()->is_optimized()) {
10946 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010947 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010948 }
10949 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950
10951 // Fill the dynamic part.
10952 int details_index = kFrameDetailsFirstDynamicIndex;
10953
10954 // Add arguments name and value.
10955 for (int i = 0; i < argument_count; i++) {
10956 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010957 if (i < scope_info->ParameterCount()) {
10958 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010960 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010961 }
10962
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010963 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010964 if (i < it.frame()->ComputeParametersCount()) {
10965 // Get the value from the stack.
10966 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010967 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010968 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010969 }
10970 }
10971
10972 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010973 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010974 details->set(details_index++, locals->get(i));
10975 }
10976
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010977 // Add the value being returned.
10978 if (at_return) {
10979 details->set(details_index++, *return_value);
10980 }
10981
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010982 // Add the receiver (same as in function frame).
10983 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10984 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010985 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010986 if (!receiver->IsJSObject() &&
10987 shared->is_classic_mode() &&
10988 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010989 // If the receiver is not a JSObject and the function is not a
10990 // builtin or strict-mode we have hit an optimization where a
10991 // value object is not converted into a wrapped JS objects. To
10992 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010993 // by creating correct wrapper object based on the calling frame's
10994 // global context.
10995 it.Advance();
10996 Handle<Context> calling_frames_global_context(
10997 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010998 receiver =
10999 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011000 }
11001 details->set(kFrameDetailsReceiverIndex, *receiver);
11002
11003 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011004 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011005}
11006
11007
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011008// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011009static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011010 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011011 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011012 Handle<Context> context,
11013 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011014 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011015 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11016 VariableMode mode;
11017 InitializationFlag init_flag;
11018 int context_index = scope_info->ContextSlotIndex(
11019 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011020
whesse@chromium.org7b260152011-06-20 15:33:18 +000011021 RETURN_IF_EMPTY_HANDLE_VALUE(
11022 isolate,
11023 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011024 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011025 Handle<Object>(context->get(context_index), isolate),
11026 NONE,
11027 kNonStrictMode),
11028 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011029 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011030
11031 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011032}
11033
11034
11035// Create a plain JSObject which materializes the local scope for the specified
11036// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011037static Handle<JSObject> MaterializeLocalScope(
11038 Isolate* isolate,
11039 JavaScriptFrame* frame,
11040 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011041 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011042 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011043 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011044 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011045
11046 // Allocate and initialize a JSObject with all the arguments, stack locals
11047 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011048 Handle<JSObject> local_scope =
11049 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011050
11051 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011052 for (int i = 0; i < scope_info->ParameterCount(); ++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->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011057 Handle<Object>(frame_inspector.GetParameter(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
11063 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011064 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011065 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011066 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011067 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011068 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011069 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011070 NONE,
11071 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011072 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011073 }
11074
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011075 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011076 // Third fill all context locals.
11077 Handle<Context> frame_context(Context::cast(frame->context()));
11078 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011079 if (!CopyContextLocalsToScopeObject(
11080 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011081 return Handle<JSObject>();
11082 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011083
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011084 // Finally copy any properties from the function context extension.
11085 // These will be variables introduced by eval.
11086 if (function_context->closure() == *function) {
11087 if (function_context->has_extension() &&
11088 !function_context->IsGlobalContext()) {
11089 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011090 bool threw = false;
11091 Handle<FixedArray> keys =
11092 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11093 if (threw) return Handle<JSObject>();
11094
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011095 for (int i = 0; i < keys->length(); i++) {
11096 // Names of variables introduced by eval are strings.
11097 ASSERT(keys->get(i)->IsString());
11098 Handle<String> key(String::cast(keys->get(i)));
11099 RETURN_IF_EMPTY_HANDLE_VALUE(
11100 isolate,
11101 SetProperty(local_scope,
11102 key,
11103 GetProperty(ext, key),
11104 NONE,
11105 kNonStrictMode),
11106 Handle<JSObject>());
11107 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011108 }
11109 }
11110 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011111
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112 return local_scope;
11113}
11114
11115
11116// Create a plain JSObject which materializes the closure content for the
11117// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011118static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11119 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011120 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011121
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011122 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011123 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011124
11125 // Allocate and initialize a JSObject with all the content of theis function
11126 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011127 Handle<JSObject> closure_scope =
11128 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011129
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011130 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011131 if (!CopyContextLocalsToScopeObject(
11132 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011133 return Handle<JSObject>();
11134 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011135
11136 // Finally copy any properties from the function context extension. This will
11137 // be variables introduced by eval.
11138 if (context->has_extension()) {
11139 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011140 bool threw = false;
11141 Handle<FixedArray> keys =
11142 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11143 if (threw) return Handle<JSObject>();
11144
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011145 for (int i = 0; i < keys->length(); i++) {
11146 // Names of variables introduced by eval are strings.
11147 ASSERT(keys->get(i)->IsString());
11148 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011149 RETURN_IF_EMPTY_HANDLE_VALUE(
11150 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011151 SetProperty(closure_scope,
11152 key,
11153 GetProperty(ext, key),
11154 NONE,
11155 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011156 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011157 }
11158 }
11159
11160 return closure_scope;
11161}
11162
11163
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011164// Create a plain JSObject which materializes the scope for the specified
11165// catch context.
11166static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11167 Handle<Context> context) {
11168 ASSERT(context->IsCatchContext());
11169 Handle<String> name(String::cast(context->extension()));
11170 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11171 Handle<JSObject> catch_scope =
11172 isolate->factory()->NewJSObject(isolate->object_function());
11173 RETURN_IF_EMPTY_HANDLE_VALUE(
11174 isolate,
11175 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11176 Handle<JSObject>());
11177 return catch_scope;
11178}
11179
11180
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011181// Create a plain JSObject which materializes the block scope for the specified
11182// block context.
11183static Handle<JSObject> MaterializeBlockScope(
11184 Isolate* isolate,
11185 Handle<Context> context) {
11186 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011187 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011188
11189 // Allocate and initialize a JSObject with all the arguments, stack locals
11190 // heap locals and extension properties of the debugged function.
11191 Handle<JSObject> block_scope =
11192 isolate->factory()->NewJSObject(isolate->object_function());
11193
11194 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011195 if (!CopyContextLocalsToScopeObject(
11196 isolate, scope_info, context, block_scope)) {
11197 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011198 }
11199
11200 return block_scope;
11201}
11202
11203
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011204// Iterate over the actual scopes visible from a stack frame. The iteration
11205// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011206// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011207// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011208class ScopeIterator {
11209 public:
11210 enum ScopeType {
11211 ScopeTypeGlobal = 0,
11212 ScopeTypeLocal,
11213 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011214 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011215 ScopeTypeCatch,
11216 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011217 };
11218
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011219 ScopeIterator(Isolate* isolate,
11220 JavaScriptFrame* frame,
11221 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011222 : isolate_(isolate),
11223 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011224 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011225 function_(JSFunction::cast(frame->function())),
11226 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011227 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011228
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011229 // Catch the case when the debugger stops in an internal function.
11230 Handle<SharedFunctionInfo> shared_info(function_->shared());
11231 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11232 if (shared_info->script() == isolate->heap()->undefined_value()) {
11233 while (context_->closure() == *function_) {
11234 context_ = Handle<Context>(context_->previous(), isolate_);
11235 }
11236 return;
11237 }
11238
11239 // Get the debug info (create it if it does not exist).
11240 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11241 // Return if ensuring debug info failed.
11242 return;
11243 }
11244 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11245
11246 // Find the break point where execution has stopped.
11247 BreakLocationIterator break_location_iterator(debug_info,
11248 ALL_BREAK_LOCATIONS);
11249 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11250 if (break_location_iterator.IsExit()) {
11251 // We are within the return sequence. At the momemt it is not possible to
11252 // get a source position which is consistent with the current scope chain.
11253 // Thus all nested with, catch and block contexts are skipped and we only
11254 // provide the function scope.
11255 if (scope_info->HasContext()) {
11256 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11257 } else {
11258 while (context_->closure() == *function_) {
11259 context_ = Handle<Context>(context_->previous(), isolate_);
11260 }
11261 }
11262 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11263 } else {
11264 // Reparse the code and analyze the scopes.
11265 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11266 Handle<Script> script(Script::cast(shared_info->script()));
11267 Scope* scope = NULL;
11268
11269 // Check whether we are in global, eval or function code.
11270 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11271 if (scope_info->Type() != FUNCTION_SCOPE) {
11272 // Global or eval code.
11273 CompilationInfo info(script);
11274 if (scope_info->Type() == GLOBAL_SCOPE) {
11275 info.MarkAsGlobal();
11276 } else {
11277 ASSERT(scope_info->Type() == EVAL_SCOPE);
11278 info.MarkAsEval();
11279 info.SetCallingContext(Handle<Context>(function_->context()));
11280 }
11281 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11282 scope = info.function()->scope();
11283 }
11284 } else {
11285 // Function code
11286 CompilationInfo info(shared_info);
11287 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11288 scope = info.function()->scope();
11289 }
11290 }
11291
11292 // Retrieve the scope chain for the current position.
11293 if (scope != NULL) {
11294 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11295 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11296 } else {
11297 // A failed reparse indicates that the preparser has diverged from the
11298 // parser or that the preparse data given to the initial parse has been
11299 // faulty. We fail in debug mode but in release mode we only provide the
11300 // information we get from the context chain but nothing about
11301 // completely stack allocated scopes or stack allocated locals.
11302 UNREACHABLE();
11303 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011304 }
11305 }
11306
11307 // More scopes?
11308 bool Done() { return context_.is_null(); }
11309
11310 // Move to the next scope.
11311 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011312 ScopeType scope_type = Type();
11313 if (scope_type == ScopeTypeGlobal) {
11314 // The global scope is always the last in the chain.
11315 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011316 context_ = Handle<Context>();
11317 return;
11318 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011319 if (nested_scope_chain_.is_empty()) {
11320 context_ = Handle<Context>(context_->previous(), isolate_);
11321 } else {
11322 if (nested_scope_chain_.last()->HasContext()) {
11323 ASSERT(context_->previous() != NULL);
11324 context_ = Handle<Context>(context_->previous(), isolate_);
11325 }
11326 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011327 }
11328 }
11329
11330 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011331 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011332 if (!nested_scope_chain_.is_empty()) {
11333 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11334 switch (scope_info->Type()) {
11335 case FUNCTION_SCOPE:
11336 ASSERT(context_->IsFunctionContext() ||
11337 !scope_info->HasContext());
11338 return ScopeTypeLocal;
11339 case GLOBAL_SCOPE:
11340 ASSERT(context_->IsGlobalContext());
11341 return ScopeTypeGlobal;
11342 case WITH_SCOPE:
11343 ASSERT(context_->IsWithContext());
11344 return ScopeTypeWith;
11345 case CATCH_SCOPE:
11346 ASSERT(context_->IsCatchContext());
11347 return ScopeTypeCatch;
11348 case BLOCK_SCOPE:
11349 ASSERT(!scope_info->HasContext() ||
11350 context_->IsBlockContext());
11351 return ScopeTypeBlock;
11352 case EVAL_SCOPE:
11353 UNREACHABLE();
11354 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011355 }
11356 if (context_->IsGlobalContext()) {
11357 ASSERT(context_->global()->IsGlobalObject());
11358 return ScopeTypeGlobal;
11359 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011360 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011361 return ScopeTypeClosure;
11362 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011363 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011364 return ScopeTypeCatch;
11365 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011366 if (context_->IsBlockContext()) {
11367 return ScopeTypeBlock;
11368 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011369 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011370 return ScopeTypeWith;
11371 }
11372
11373 // Return the JavaScript object with the content of the current scope.
11374 Handle<JSObject> ScopeObject() {
11375 switch (Type()) {
11376 case ScopeIterator::ScopeTypeGlobal:
11377 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011378 case ScopeIterator::ScopeTypeLocal:
11379 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011380 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011381 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011382 case ScopeIterator::ScopeTypeWith:
11383 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011384 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11385 case ScopeIterator::ScopeTypeCatch:
11386 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011387 case ScopeIterator::ScopeTypeClosure:
11388 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011389 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011390 case ScopeIterator::ScopeTypeBlock:
11391 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011392 }
11393 UNREACHABLE();
11394 return Handle<JSObject>();
11395 }
11396
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011397 Handle<ScopeInfo> CurrentScopeInfo() {
11398 if (!nested_scope_chain_.is_empty()) {
11399 return nested_scope_chain_.last();
11400 } else if (context_->IsBlockContext()) {
11401 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11402 } else if (context_->IsFunctionContext()) {
11403 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11404 }
11405 return Handle<ScopeInfo>::null();
11406 }
11407
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011408 // Return the context for this scope. For the local context there might not
11409 // be an actual context.
11410 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011411 if (Type() == ScopeTypeGlobal ||
11412 nested_scope_chain_.is_empty()) {
11413 return context_;
11414 } else if (nested_scope_chain_.last()->HasContext()) {
11415 return context_;
11416 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011417 return Handle<Context>();
11418 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011419 }
11420
11421#ifdef DEBUG
11422 // Debug print of the content of the current scope.
11423 void DebugPrint() {
11424 switch (Type()) {
11425 case ScopeIterator::ScopeTypeGlobal:
11426 PrintF("Global:\n");
11427 CurrentContext()->Print();
11428 break;
11429
11430 case ScopeIterator::ScopeTypeLocal: {
11431 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011432 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011433 if (!CurrentContext().is_null()) {
11434 CurrentContext()->Print();
11435 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011436 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011437 if (extension->IsJSContextExtensionObject()) {
11438 extension->Print();
11439 }
11440 }
11441 }
11442 break;
11443 }
11444
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011445 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011446 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011447 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011448 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011449
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011450 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011451 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011452 CurrentContext()->extension()->Print();
11453 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011454 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011455
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011456 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011457 PrintF("Closure:\n");
11458 CurrentContext()->Print();
11459 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011460 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011461 if (extension->IsJSContextExtensionObject()) {
11462 extension->Print();
11463 }
11464 }
11465 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011466
11467 default:
11468 UNREACHABLE();
11469 }
11470 PrintF("\n");
11471 }
11472#endif
11473
11474 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011475 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011476 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011477 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011478 Handle<JSFunction> function_;
11479 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011480 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011481
11482 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11483};
11484
11485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011486RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011487 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011488 ASSERT(args.length() == 2);
11489
11490 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011491 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011492 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11493 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011494 if (!maybe_check->ToObject(&check)) return maybe_check;
11495 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011496 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11497
11498 // Get the frame where the debugging is performed.
11499 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011500 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011501 JavaScriptFrame* frame = it.frame();
11502
11503 // Count the visible scopes.
11504 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011505 for (ScopeIterator it(isolate, frame, 0);
11506 !it.Done();
11507 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011508 n++;
11509 }
11510
11511 return Smi::FromInt(n);
11512}
11513
11514
11515static const int kScopeDetailsTypeIndex = 0;
11516static const int kScopeDetailsObjectIndex = 1;
11517static const int kScopeDetailsSize = 2;
11518
11519// Return an array with scope details
11520// args[0]: number: break id
11521// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011522// args[2]: number: inlined frame index
11523// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011524//
11525// The array returned contains the following information:
11526// 0: Scope type
11527// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011528RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011529 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011530 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011531
11532 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011533 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011534 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11535 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011536 if (!maybe_check->ToObject(&check)) return maybe_check;
11537 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011538 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011539 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11540 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011541
11542 // Get the frame where the debugging is performed.
11543 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011544 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011545 JavaScriptFrame* frame = frame_it.frame();
11546
11547 // Find the requested scope.
11548 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011549 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011550 for (; !it.Done() && n < index; it.Next()) {
11551 n++;
11552 }
11553 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011554 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011555 }
11556
11557 // Calculate the size of the result.
11558 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011559 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011560
11561 // Fill in scope details.
11562 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011563 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011564 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011565 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011566
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011567 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011568}
11569
11570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011571RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011572 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011573 ASSERT(args.length() == 0);
11574
11575#ifdef DEBUG
11576 // Print the scopes for the top frame.
11577 StackFrameLocator locator;
11578 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011579 for (ScopeIterator it(isolate, frame, 0);
11580 !it.Done();
11581 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011582 it.DebugPrint();
11583 }
11584#endif
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
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011589RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011591 ASSERT(args.length() == 1);
11592
11593 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011594 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011595 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11596 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011597 if (!maybe_result->ToObject(&result)) return maybe_result;
11598 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011599
11600 // Count all archived V8 threads.
11601 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011602 for (ThreadState* thread =
11603 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011604 thread != NULL;
11605 thread = thread->Next()) {
11606 n++;
11607 }
11608
11609 // Total number of threads is current thread and archived threads.
11610 return Smi::FromInt(n + 1);
11611}
11612
11613
11614static const int kThreadDetailsCurrentThreadIndex = 0;
11615static const int kThreadDetailsThreadIdIndex = 1;
11616static const int kThreadDetailsSize = 2;
11617
11618// Return an array with thread details
11619// args[0]: number: break id
11620// args[1]: number: thread index
11621//
11622// The array returned contains the following information:
11623// 0: Is current thread?
11624// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011625RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011627 ASSERT(args.length() == 2);
11628
11629 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011630 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011631 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11632 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011633 if (!maybe_check->ToObject(&check)) return maybe_check;
11634 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011635 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11636
11637 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011638 Handle<FixedArray> details =
11639 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011640
11641 // Thread index 0 is current thread.
11642 if (index == 0) {
11643 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011644 details->set(kThreadDetailsCurrentThreadIndex,
11645 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011646 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011647 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011648 } else {
11649 // Find the thread with the requested index.
11650 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011651 ThreadState* thread =
11652 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011653 while (index != n && thread != NULL) {
11654 thread = thread->Next();
11655 n++;
11656 }
11657 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011658 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011659 }
11660
11661 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011662 details->set(kThreadDetailsCurrentThreadIndex,
11663 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011664 details->set(kThreadDetailsThreadIdIndex,
11665 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011666 }
11667
11668 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011669 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011670}
11671
11672
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011673// Sets the disable break state
11674// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011675RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011676 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011677 ASSERT(args.length() == 1);
11678 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011679 isolate->debug()->set_disable_break(disable_break);
11680 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011681}
11682
11683
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011684RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011685 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011686 ASSERT(args.length() == 1);
11687
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011688 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11689 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011690 // Find the number of break points
11691 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011692 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011693 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011694 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011695 Handle<FixedArray>::cast(break_locations));
11696}
11697
11698
11699// Set a break point in a function
11700// args[0]: function
11701// args[1]: number: break source position (within the function source)
11702// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011703RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011704 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011705 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011706 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11707 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011708 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11709 RUNTIME_ASSERT(source_position >= 0);
11710 Handle<Object> break_point_object_arg = args.at<Object>(2);
11711
11712 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011713 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11714 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011715
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011716 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011717}
11718
11719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011720Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11721 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011722 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011723 // Iterate the heap looking for SharedFunctionInfo generated from the
11724 // script. The inner most SharedFunctionInfo containing the source position
11725 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011726 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011727 // which is found is not compiled it is compiled and the heap is iterated
11728 // again as the compilation might create inner functions from the newly
11729 // compiled function and the actual requested break point might be in one of
11730 // these functions.
11731 bool done = false;
11732 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011733 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011734 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011735 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011736 { // Extra scope for iterator and no-allocation.
11737 isolate->heap()->EnsureHeapIsIterable();
11738 AssertNoAllocation no_alloc_during_heap_iteration;
11739 HeapIterator iterator;
11740 for (HeapObject* obj = iterator.next();
11741 obj != NULL; obj = iterator.next()) {
11742 if (obj->IsSharedFunctionInfo()) {
11743 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11744 if (shared->script() == *script) {
11745 // If the SharedFunctionInfo found has the requested script data and
11746 // contains the source position it is a candidate.
11747 int start_position = shared->function_token_position();
11748 if (start_position == RelocInfo::kNoPosition) {
11749 start_position = shared->start_position();
11750 }
11751 if (start_position <= position &&
11752 position <= shared->end_position()) {
11753 // If there is no candidate or this function is within the current
11754 // candidate this is the new candidate.
11755 if (target.is_null()) {
11756 target_start_position = start_position;
11757 target = shared;
11758 } else {
11759 if (target_start_position == start_position &&
11760 shared->end_position() == target->end_position()) {
11761 // If a top-level function contain only one function
11762 // declartion the source for the top-level and the
11763 // function is the same. In that case prefer the non
11764 // top-level function.
11765 if (!shared->is_toplevel()) {
11766 target_start_position = start_position;
11767 target = shared;
11768 }
11769 } else if (target_start_position <= start_position &&
11770 shared->end_position() <= target->end_position()) {
11771 // This containment check includes equality as a function
11772 // inside a top-level function can share either start or end
11773 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011774 target_start_position = start_position;
11775 target = shared;
11776 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011777 }
11778 }
11779 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011780 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011781 } // End for loop.
11782 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011783
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011785 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011786 }
11787
11788 // If the candidate found is compiled we are done. NOTE: when lazy
11789 // compilation of inner functions is introduced some additional checking
11790 // needs to be done here to compile inner functions.
11791 done = target->is_compiled();
11792 if (!done) {
11793 // If the candidate is not compiled compile it to reveal any inner
11794 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011795 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011796 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011797 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011798
11799 return *target;
11800}
11801
11802
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011803// Changes the state of a break point in a script and returns source position
11804// where break point was set. NOTE: Regarding performance see the NOTE for
11805// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011806// args[0]: script to set break point in
11807// args[1]: number: break source position (within the script source)
11808// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011809RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011810 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011811 ASSERT(args.length() == 3);
11812 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11813 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11814 RUNTIME_ASSERT(source_position >= 0);
11815 Handle<Object> break_point_object_arg = args.at<Object>(2);
11816
11817 // Get the script from the script wrapper.
11818 RUNTIME_ASSERT(wrapper->value()->IsScript());
11819 Handle<Script> script(Script::cast(wrapper->value()));
11820
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011821 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011822 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011823 if (!result->IsUndefined()) {
11824 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11825 // Find position within function. The script position might be before the
11826 // source position of the first function.
11827 int position;
11828 if (shared->start_position() > source_position) {
11829 position = 0;
11830 } else {
11831 position = source_position - shared->start_position();
11832 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011833 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011834 position += shared->start_position();
11835 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011836 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011837 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011838}
11839
11840
11841// Clear a break point
11842// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011843RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011844 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011845 ASSERT(args.length() == 1);
11846 Handle<Object> break_point_object_arg = args.at<Object>(0);
11847
11848 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011849 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011851 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011852}
11853
11854
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011855// Change the state of break on exceptions.
11856// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11857// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011858RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011859 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011860 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011861 RUNTIME_ASSERT(args[0]->IsNumber());
11862 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011863
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011864 // If the number doesn't match an enum value, the ChangeBreakOnException
11865 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011866 ExceptionBreakType type =
11867 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011868 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011869 isolate->debug()->ChangeBreakOnException(type, enable);
11870 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011871}
11872
11873
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011874// Returns the state of break on exceptions
11875// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011876RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011878 ASSERT(args.length() == 1);
11879 RUNTIME_ASSERT(args[0]->IsNumber());
11880
11881 ExceptionBreakType type =
11882 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011883 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011884 return Smi::FromInt(result);
11885}
11886
11887
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011888// Prepare for stepping
11889// args[0]: break id for checking execution state
11890// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011891// args[2]: number of times to perform the step, for step out it is the number
11892// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011893RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011894 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011895 ASSERT(args.length() == 3);
11896 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011897 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011898 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11899 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011900 if (!maybe_check->ToObject(&check)) return maybe_check;
11901 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011902 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011903 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011904 }
11905
11906 // Get the step action and check validity.
11907 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11908 if (step_action != StepIn &&
11909 step_action != StepNext &&
11910 step_action != StepOut &&
11911 step_action != StepInMin &&
11912 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011913 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011914 }
11915
11916 // Get the number of steps.
11917 int step_count = NumberToInt32(args[2]);
11918 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011919 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011920 }
11921
ager@chromium.orga1645e22009-09-09 19:27:10 +000011922 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011923 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011924
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011925 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011926 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11927 step_count);
11928 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011929}
11930
11931
11932// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011933RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011934 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011935 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011936 isolate->debug()->ClearStepping();
11937 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011938}
11939
11940
11941// Creates a copy of the with context chain. The copy of the context chain is
11942// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011943static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11944 Handle<JSFunction> function,
11945 Handle<Context> base,
11946 JavaScriptFrame* frame,
11947 int inlined_frame_index) {
11948 HandleScope scope(isolate);
11949 List<Handle<ScopeInfo> > scope_chain;
11950 List<Handle<Context> > context_chain;
11951
11952 ScopeIterator it(isolate, frame, inlined_frame_index);
11953 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11954 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11955 ASSERT(!it.Done());
11956 scope_chain.Add(it.CurrentScopeInfo());
11957 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011958 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011959
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011960 // At the end of the chain. Return the base context to link to.
11961 Handle<Context> context = base;
11962
11963 // Iteratively copy and or materialize the nested contexts.
11964 while (!scope_chain.is_empty()) {
11965 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11966 Handle<Context> current = context_chain.RemoveLast();
11967 ASSERT(!(scope_info->HasContext() & current.is_null()));
11968
11969 if (scope_info->Type() == CATCH_SCOPE) {
11970 Handle<String> name(String::cast(current->extension()));
11971 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11972 context =
11973 isolate->factory()->NewCatchContext(function,
11974 context,
11975 name,
11976 thrown_object);
11977 } else if (scope_info->Type() == BLOCK_SCOPE) {
11978 // Materialize the contents of the block scope into a JSObject.
11979 Handle<JSObject> block_scope_object =
11980 MaterializeBlockScope(isolate, current);
11981 if (block_scope_object.is_null()) {
11982 return Handle<Context>::null();
11983 }
11984 // Allocate a new function context for the debug evaluation and set the
11985 // extension object.
11986 Handle<Context> new_context =
11987 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11988 function);
11989 new_context->set_extension(*block_scope_object);
11990 new_context->set_previous(*context);
11991 context = new_context;
11992 } else {
11993 ASSERT(scope_info->Type() == WITH_SCOPE);
11994 ASSERT(current->IsWithContext());
11995 Handle<JSObject> extension(JSObject::cast(current->extension()));
11996 context =
11997 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011998 }
erikcorry0ad885c2011-11-21 13:51:57 +000011999 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012000
12001 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012002}
12003
12004
12005// Helper function to find or create the arguments object for
12006// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012007static Handle<Object> GetArgumentsObject(Isolate* isolate,
12008 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012009 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012010 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012011 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012012 Handle<Context> function_context) {
12013 // Try to find the value of 'arguments' to pass as parameter. If it is not
12014 // found (that is the debugged function does not reference 'arguments' and
12015 // does not support eval) then create an 'arguments' object.
12016 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012017 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012018 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012019 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012020 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012021 }
12022 }
12023
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012024 if (scope_info->HasHeapAllocatedLocals()) {
12025 VariableMode mode;
12026 InitializationFlag init_flag;
12027 index = scope_info->ContextSlotIndex(
12028 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012029 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012030 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012031 }
12032 }
12033
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012034 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
12035
12036 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012037 Handle<JSObject> arguments =
12038 isolate->factory()->NewArgumentsObject(function, length);
12039 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012040
12041 AssertNoAllocation no_gc;
12042 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012043 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012044 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012045 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012046 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012047 return arguments;
12048}
12049
12050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012051static const char kSourceStr[] =
12052 "(function(arguments,__source__){return eval(__source__);})";
12053
12054
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012055// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012056// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012057// extension part has all the parameters and locals of the function on the
12058// stack frame. A function which calls eval with the code to evaluate is then
12059// compiled in this context and called in this context. As this context
12060// replaces the context of the function on the stack frame a new (empty)
12061// function is created as well to be used as the closure for the context.
12062// This function and the context acts as replacements for the function on the
12063// stack frame presenting the same view of the values of parameters and
12064// local variables as if the piece of JavaScript was evaluated at the point
12065// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012066RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012067 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012068
12069 // Check the execution state and decode arguments frame and source to be
12070 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012071 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012072 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012073 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12074 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012075 if (!maybe_check_result->ToObject(&check_result)) {
12076 return maybe_check_result;
12077 }
12078 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012079 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012080 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12081 CONVERT_ARG_CHECKED(String, source, 3);
12082 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12083 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012084
12085 // Handle the processing of break.
12086 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012087
12088 // Get the frame where the debugging is performed.
12089 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012090 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012091 JavaScriptFrame* frame = it.frame();
12092 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012093 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012094
12095 // Traverse the saved contexts chain to find the active context for the
12096 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012097 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12098
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012099 SaveContext savex(isolate);
12100 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012101
12102 // Create the (empty) function replacing the function on the stack frame for
12103 // the purpose of evaluating in the context created below. It is important
12104 // that this function does not describe any parameters and local variables
12105 // in the context. If it does then this will cause problems with the lookup
12106 // in Context::Lookup, where context slots for parameters and local variables
12107 // are looked at before the extension object.
12108 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012109 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12110 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012111 go_between->set_context(function->context());
12112#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012113 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12114 ASSERT(go_between_scope_info->ParameterCount() == 0);
12115 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012116#endif
12117
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012118 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012119 Handle<JSObject> local_scope = MaterializeLocalScope(
12120 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012121 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012122
12123 // Allocate a new context for the debug evaluation and set the extension
12124 // object build.
12125 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012126 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12127 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012128 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012129 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012130 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012131 Handle<Context> function_context;
12132 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012133 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012134 function_context = Handle<Context>(frame_context->declaration_context());
12135 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012136 context = CopyNestedScopeContextChain(isolate,
12137 go_between,
12138 context,
12139 frame,
12140 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012141
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012142 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012143 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012144 context =
12145 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012146 }
12147
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012148 // Wrap the evaluation statement in a new function compiled in the newly
12149 // created context. The function has one parameter which has to be called
12150 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012151 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012152 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012153
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012154 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012155 isolate->factory()->NewStringFromAscii(
12156 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012157
12158 // Currently, the eval code will be executed in non-strict mode,
12159 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012160 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012161 Compiler::CompileEval(function_source,
12162 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012163 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012164 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012165 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012166 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012167 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012168 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012169
12170 // Invoke the result of the compilation to get the evaluation function.
12171 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012172 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012173 Handle<Object> evaluation_function =
12174 Execution::Call(compiled_function, receiver, 0, NULL,
12175 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012176 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012177
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012178 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012179 frame,
12180 inlined_frame_index,
12181 function,
12182 scope_info,
12183 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184
12185 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012186 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012187 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012188 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12189 receiver,
12190 ARRAY_SIZE(argv),
12191 argv,
12192 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012193 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012194
12195 // Skip the global proxy as it has no properties and always delegates to the
12196 // real global object.
12197 if (result->IsJSGlobalProxy()) {
12198 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12199 }
12200
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012201 return *result;
12202}
12203
12204
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012205RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012206 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012207
12208 // Check the execution state and decode arguments frame and source to be
12209 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012210 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012211 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012212 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12213 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012214 if (!maybe_check_result->ToObject(&check_result)) {
12215 return maybe_check_result;
12216 }
12217 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012218 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012219 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012220 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012221
12222 // Handle the processing of break.
12223 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012224
12225 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012226 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012227 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012228 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012229 top = top->prev();
12230 }
12231 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012232 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012233 }
12234
12235 // Get the global context now set to the top context from before the
12236 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012237 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012238
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012239 bool is_global = true;
12240
12241 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012242 // Create a new with context with the additional context information between
12243 // the context of the debugged function and the eval code to be executed.
12244 context = isolate->factory()->NewWithContext(
12245 Handle<JSFunction>(context->closure()),
12246 context,
12247 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012248 is_global = false;
12249 }
12250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012251 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012252 // Currently, the eval code will be executed in non-strict mode,
12253 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012254 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012255 Compiler::CompileEval(source,
12256 context,
12257 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012258 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012259 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012260 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012261 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012262 Handle<JSFunction>(
12263 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12264 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012265
12266 // Invoke the result of the compilation to get the evaluation function.
12267 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012268 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269 Handle<Object> result =
12270 Execution::Call(compiled_function, receiver, 0, NULL,
12271 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012272 // Clear the oneshot breakpoints so that the debugger does not step further.
12273 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012274 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012275 return *result;
12276}
12277
12278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012279RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012280 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012281 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012282
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012283 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012284 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012285
12286 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012287 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012288 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12289 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12290 // because using
12291 // instances->set(i, *GetScriptWrapper(script))
12292 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12293 // already have deferenced the instances handle.
12294 Handle<JSValue> wrapper = GetScriptWrapper(script);
12295 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012296 }
12297
12298 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012299 Handle<JSObject> result =
12300 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012301 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012302 return *result;
12303}
12304
12305
12306// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012307static int DebugReferencedBy(HeapIterator* iterator,
12308 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012309 Object* instance_filter, int max_references,
12310 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012311 JSFunction* arguments_function) {
12312 NoHandleAllocation ha;
12313 AssertNoAllocation no_alloc;
12314
12315 // Iterate the heap.
12316 int count = 0;
12317 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012318 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012319 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012320 (max_references == 0 || count < max_references)) {
12321 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012322 if (heap_obj->IsJSObject()) {
12323 // Skip context extension objects and argument arrays as these are
12324 // checked in the context of functions using them.
12325 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012326 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012327 obj->map()->constructor() == arguments_function) {
12328 continue;
12329 }
12330
12331 // Check if the JS object has a reference to the object looked for.
12332 if (obj->ReferencesObject(target)) {
12333 // Check instance filter if supplied. This is normally used to avoid
12334 // references from mirror objects (see Runtime_IsInPrototypeChain).
12335 if (!instance_filter->IsUndefined()) {
12336 Object* V = obj;
12337 while (true) {
12338 Object* prototype = V->GetPrototype();
12339 if (prototype->IsNull()) {
12340 break;
12341 }
12342 if (instance_filter == prototype) {
12343 obj = NULL; // Don't add this object.
12344 break;
12345 }
12346 V = prototype;
12347 }
12348 }
12349
12350 if (obj != NULL) {
12351 // Valid reference found add to instance array if supplied an update
12352 // count.
12353 if (instances != NULL && count < instances_size) {
12354 instances->set(count, obj);
12355 }
12356 last = obj;
12357 count++;
12358 }
12359 }
12360 }
12361 }
12362
12363 // Check for circular reference only. This can happen when the object is only
12364 // referenced from mirrors and has a circular reference in which case the
12365 // object is not really alive and would have been garbage collected if not
12366 // referenced from the mirror.
12367 if (count == 1 && last == target) {
12368 count = 0;
12369 }
12370
12371 // Return the number of referencing objects found.
12372 return count;
12373}
12374
12375
12376// Scan the heap for objects with direct references to an object
12377// args[0]: the object to find references to
12378// args[1]: constructor function for instances to exclude (Mirror)
12379// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012380RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012381 ASSERT(args.length() == 3);
12382
12383 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012384 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12385 // The heap iterator reserves the right to do a GC to make the heap iterable.
12386 // Due to the GC above we know it won't need to do that, but it seems cleaner
12387 // to get the heap iterator constructed before we start having unprotected
12388 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012389
12390 // Check parameters.
12391 CONVERT_CHECKED(JSObject, target, args[0]);
12392 Object* instance_filter = args[1];
12393 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12394 instance_filter->IsJSObject());
12395 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12396 RUNTIME_ASSERT(max_references >= 0);
12397
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012399 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012400 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012401 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012402 JSFunction* arguments_function =
12403 JSFunction::cast(arguments_boilerplate->map()->constructor());
12404
12405 // Get the number of referencing objects.
12406 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012407 HeapIterator heap_iterator;
12408 count = DebugReferencedBy(&heap_iterator,
12409 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012410 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012411
12412 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012413 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012414 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012415 if (!maybe_object->ToObject(&object)) return maybe_object;
12416 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012417 FixedArray* instances = FixedArray::cast(object);
12418
12419 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012420 // AllocateFixedArray above does not make the heap non-iterable.
12421 ASSERT(HEAP->IsHeapIterable());
12422 HeapIterator heap_iterator2;
12423 count = DebugReferencedBy(&heap_iterator2,
12424 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012425 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012426
12427 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012428 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012429 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012430 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012431 if (!maybe_result->ToObject(&result)) return maybe_result;
12432 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012433}
12434
12435
12436// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012437static int DebugConstructedBy(HeapIterator* iterator,
12438 JSFunction* constructor,
12439 int max_references,
12440 FixedArray* instances,
12441 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012442 AssertNoAllocation no_alloc;
12443
12444 // Iterate the heap.
12445 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012446 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012447 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012448 (max_references == 0 || count < max_references)) {
12449 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012450 if (heap_obj->IsJSObject()) {
12451 JSObject* obj = JSObject::cast(heap_obj);
12452 if (obj->map()->constructor() == constructor) {
12453 // Valid reference found add to instance array if supplied an update
12454 // count.
12455 if (instances != NULL && count < instances_size) {
12456 instances->set(count, obj);
12457 }
12458 count++;
12459 }
12460 }
12461 }
12462
12463 // Return the number of referencing objects found.
12464 return count;
12465}
12466
12467
12468// Scan the heap for objects constructed by a specific function.
12469// args[0]: the constructor to find instances of
12470// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012471RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012472 ASSERT(args.length() == 2);
12473
12474 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012475 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012476
12477 // Check parameters.
12478 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12479 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12480 RUNTIME_ASSERT(max_references >= 0);
12481
12482 // Get the number of referencing objects.
12483 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012484 HeapIterator heap_iterator;
12485 count = DebugConstructedBy(&heap_iterator,
12486 constructor,
12487 max_references,
12488 NULL,
12489 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012490
12491 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012492 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012493 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012494 if (!maybe_object->ToObject(&object)) return maybe_object;
12495 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012496 FixedArray* instances = FixedArray::cast(object);
12497
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012498 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012499 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012500 HeapIterator heap_iterator2;
12501 count = DebugConstructedBy(&heap_iterator2,
12502 constructor,
12503 max_references,
12504 instances,
12505 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012506
12507 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012508 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012509 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12510 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012511 if (!maybe_result->ToObject(&result)) return maybe_result;
12512 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012513 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012514}
12515
12516
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012517// Find the effective prototype object as returned by __proto__.
12518// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012519RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012520 ASSERT(args.length() == 1);
12521
12522 CONVERT_CHECKED(JSObject, obj, args[0]);
12523
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012524 // Use the __proto__ accessor.
12525 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012526}
12527
12528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012529RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012530 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012531 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012532 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012533}
12534
12535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012536RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012537#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012538 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012539 ASSERT(args.length() == 1);
12540 // Get the function and make sure it is compiled.
12541 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012542 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012543 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012544 return Failure::Exception();
12545 }
12546 func->code()->PrintLn();
12547#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012548 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012549}
ager@chromium.org9085a012009-05-11 19:22:57 +000012550
12551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012552RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012553#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012554 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012555 ASSERT(args.length() == 1);
12556 // Get the function and make sure it is compiled.
12557 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012558 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012559 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012560 return Failure::Exception();
12561 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012562 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012563#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012564 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012565}
12566
12567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012568RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012569 NoHandleAllocation ha;
12570 ASSERT(args.length() == 1);
12571
12572 CONVERT_CHECKED(JSFunction, f, args[0]);
12573 return f->shared()->inferred_name();
12574}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012575
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012576
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012577static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12578 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012579 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012580 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012581 int counter = 0;
12582 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012583 for (HeapObject* obj = iterator->next();
12584 obj != NULL;
12585 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012586 ASSERT(obj != NULL);
12587 if (!obj->IsSharedFunctionInfo()) {
12588 continue;
12589 }
12590 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12591 if (shared->script() != script) {
12592 continue;
12593 }
12594 if (counter < buffer_size) {
12595 buffer->set(counter, shared);
12596 }
12597 counter++;
12598 }
12599 return counter;
12600}
12601
12602// For a script finds all SharedFunctionInfo's in the heap that points
12603// to this script. Returns JSArray of SharedFunctionInfo wrapped
12604// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012605RUNTIME_FUNCTION(MaybeObject*,
12606 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012607 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012608 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012609 CONVERT_CHECKED(JSValue, script_value, args[0]);
12610
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012611
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012612 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12613
12614 const int kBufferSize = 32;
12615
12616 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012617 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012618 int number;
12619 {
12620 isolate->heap()->EnsureHeapIsIterable();
12621 AssertNoAllocation no_allocations;
12622 HeapIterator heap_iterator;
12623 Script* scr = *script;
12624 FixedArray* arr = *array;
12625 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12626 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012627 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012628 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012629 isolate->heap()->EnsureHeapIsIterable();
12630 AssertNoAllocation no_allocations;
12631 HeapIterator heap_iterator;
12632 Script* scr = *script;
12633 FixedArray* arr = *array;
12634 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012635 }
12636
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012637 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012638 result->set_length(Smi::FromInt(number));
12639
12640 LiveEdit::WrapSharedFunctionInfos(result);
12641
12642 return *result;
12643}
12644
12645// For a script calculates compilation information about all its functions.
12646// The script source is explicitly specified by the second argument.
12647// The source of the actual script is not used, however it is important that
12648// all generated code keeps references to this particular instance of script.
12649// Returns a JSArray of compilation infos. The array is ordered so that
12650// each function with all its descendant is always stored in a continues range
12651// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012652RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012653 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012654 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012655 CONVERT_CHECKED(JSValue, script, args[0]);
12656 CONVERT_ARG_CHECKED(String, source, 1);
12657 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12658
12659 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12660
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012661 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012662 return Failure::Exception();
12663 }
12664
12665 return result;
12666}
12667
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012668// Changes the source of the script to a new_source.
12669// If old_script_name is provided (i.e. is a String), also creates a copy of
12670// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012671RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012672 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012673 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012674 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12675 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012676 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012677
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012678 CONVERT_CHECKED(Script, original_script_pointer,
12679 original_script_value->value());
12680 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012681
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012682 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12683 new_source,
12684 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012685
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012686 if (old_script->IsScript()) {
12687 Handle<Script> script_handle(Script::cast(old_script));
12688 return *(GetScriptWrapper(script_handle));
12689 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012690 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012691 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012692}
12693
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012695RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012696 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012697 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012698 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12699 return LiveEdit::FunctionSourceUpdated(shared_info);
12700}
12701
12702
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012703// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012704RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012705 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012706 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012707 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12708 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12709
ager@chromium.orgac091b72010-05-05 07:34:42 +000012710 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012711}
12712
12713// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012714RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012715 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012716 HandleScope scope(isolate);
12717 Handle<Object> function_object(args[0], isolate);
12718 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012719
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012720 if (function_object->IsJSValue()) {
12721 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12722 if (script_object->IsJSValue()) {
12723 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012724 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012725 }
12726
12727 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12728 } else {
12729 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12730 // and we check it in this function.
12731 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012732
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012733 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012734}
12735
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012736
12737// In a code of a parent function replaces original function as embedded object
12738// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012739RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012740 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012741 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012742
12743 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12744 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12745 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12746
12747 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12748 subst_wrapper);
12749
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012750 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012751}
12752
12753
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012754// Updates positions of a shared function info (first parameter) according
12755// to script source change. Text change is described in second parameter as
12756// array of groups of 3 numbers:
12757// (change_begin, change_end, change_end_new_position).
12758// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012759RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012760 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012761 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012762 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12763 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12764
ager@chromium.orgac091b72010-05-05 07:34:42 +000012765 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012766}
12767
12768
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012769// For array of SharedFunctionInfo's (each wrapped in JSValue)
12770// checks that none of them have activations on stacks (of any thread).
12771// Returns array of the same length with corresponding results of
12772// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012773RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012774 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012775 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012776 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012777 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012778
ager@chromium.org357bf652010-04-12 11:30:10 +000012779 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012780}
12781
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012782// Compares 2 strings line-by-line, then token-wise and returns diff in form
12783// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12784// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012785RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012786 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012787 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012788 CONVERT_ARG_CHECKED(String, s1, 0);
12789 CONVERT_ARG_CHECKED(String, s2, 1);
12790
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012791 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012792}
12793
12794
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012795// A testing entry. Returns statement position which is the closest to
12796// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012797RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012798 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012799 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012800 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12801 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12802
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012803 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012804
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012805 if (code->kind() != Code::FUNCTION &&
12806 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012807 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012808 }
12809
12810 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012811 int closest_pc = 0;
12812 int distance = kMaxInt;
12813 while (!it.done()) {
12814 int statement_position = static_cast<int>(it.rinfo()->data());
12815 // Check if this break point is closer that what was previously found.
12816 if (source_position <= statement_position &&
12817 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012818 closest_pc =
12819 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012820 distance = statement_position - source_position;
12821 // Check whether we can't get any closer.
12822 if (distance == 0) break;
12823 }
12824 it.next();
12825 }
12826
12827 return Smi::FromInt(closest_pc);
12828}
12829
12830
ager@chromium.org357bf652010-04-12 11:30:10 +000012831// Calls specified function with or without entering the debugger.
12832// This is used in unit tests to run code as if debugger is entered or simply
12833// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012834RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012835 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012836 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012837 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12838 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12839
12840 Handle<Object> result;
12841 bool pending_exception;
12842 {
12843 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012844 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012845 &pending_exception);
12846 } else {
12847 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012848 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012849 &pending_exception);
12850 }
12851 }
12852 if (!pending_exception) {
12853 return *result;
12854 } else {
12855 return Failure::Exception();
12856 }
12857}
12858
12859
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012860// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012861RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012862 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012863 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012864 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12865 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012866 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012867}
12868
12869
12870// Performs a GC.
12871// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012872RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012873 isolate->heap()->CollectAllGarbage(true);
12874 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012875}
12876
12877
12878// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012879RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012880 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012881 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012882 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012883 }
12884 return Smi::FromInt(usage);
12885}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012886
12887
12888// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012889RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012890#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012891 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012892#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012893 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012894#endif
12895}
12896
12897
12898// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012899RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012900#ifdef LIVE_OBJECT_LIST
12901 return LiveObjectList::Capture();
12902#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012903 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012904#endif
12905}
12906
12907
12908// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012909RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012910#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012911 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012912 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012913 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012914#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012915 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012916#endif
12917}
12918
12919
12920// Generates the response to a debugger request for a dump of the objects
12921// contained in the difference between the captured live object lists
12922// specified by id1 and id2.
12923// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12924// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012925RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012926#ifdef LIVE_OBJECT_LIST
12927 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012928 CONVERT_SMI_ARG_CHECKED(id1, 0);
12929 CONVERT_SMI_ARG_CHECKED(id2, 1);
12930 CONVERT_SMI_ARG_CHECKED(start, 2);
12931 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012932 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12933 EnterDebugger enter_debugger;
12934 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12935#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012936 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012937#endif
12938}
12939
12940
12941// Gets the specified object as requested by the debugger.
12942// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012943RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012944#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012945 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012946 Object* result = LiveObjectList::GetObj(obj_id);
12947 return result;
12948#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012949 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012950#endif
12951}
12952
12953
12954// Gets the obj id for the specified address if valid.
12955// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012956RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012957#ifdef LIVE_OBJECT_LIST
12958 HandleScope scope;
12959 CONVERT_ARG_CHECKED(String, address, 0);
12960 Object* result = LiveObjectList::GetObjId(address);
12961 return result;
12962#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012963 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012964#endif
12965}
12966
12967
12968// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012969RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012970#ifdef LIVE_OBJECT_LIST
12971 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012972 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012973 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12974 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12975 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12976 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12977 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12978
12979 Handle<JSObject> instance_filter;
12980 if (args[1]->IsJSObject()) {
12981 instance_filter = args.at<JSObject>(1);
12982 }
12983 bool verbose = false;
12984 if (args[2]->IsBoolean()) {
12985 verbose = args[2]->IsTrue();
12986 }
12987 int start = 0;
12988 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012989 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012990 }
12991 int limit = Smi::kMaxValue;
12992 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012993 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012994 }
12995
12996 return LiveObjectList::GetObjRetainers(obj_id,
12997 instance_filter,
12998 verbose,
12999 start,
13000 limit,
13001 filter_obj);
13002#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013003 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013004#endif
13005}
13006
13007
13008// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013009RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013010#ifdef LIVE_OBJECT_LIST
13011 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013012 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13013 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013014 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13015
13016 Handle<JSObject> instance_filter;
13017 if (args[2]->IsJSObject()) {
13018 instance_filter = args.at<JSObject>(2);
13019 }
13020
13021 Object* result =
13022 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13023 return result;
13024#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013025 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013026#endif
13027}
13028
13029
13030// Generates the response to a debugger request for a list of all
13031// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013032RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013033#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013034 CONVERT_SMI_ARG_CHECKED(start, 0);
13035 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013036 return LiveObjectList::Info(start, count);
13037#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013038 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013039#endif
13040}
13041
13042
13043// Gets a dump of the specified object as requested by the debugger.
13044// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013045RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013046#ifdef LIVE_OBJECT_LIST
13047 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013048 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013049 Object* result = LiveObjectList::PrintObj(obj_id);
13050 return result;
13051#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013052 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013053#endif
13054}
13055
13056
13057// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013058RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013059#ifdef LIVE_OBJECT_LIST
13060 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013061 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013062#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013063 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013064#endif
13065}
13066
13067
13068// Generates the response to a debugger request for a summary of the types
13069// of objects in the difference between the captured live object lists
13070// specified by id1 and id2.
13071// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13072// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013073RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013074#ifdef LIVE_OBJECT_LIST
13075 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013076 CONVERT_SMI_ARG_CHECKED(id1, 0);
13077 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013078 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13079
13080 EnterDebugger enter_debugger;
13081 return LiveObjectList::Summarize(id1, id2, filter_obj);
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
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013087#endif // ENABLE_DEBUGGER_SUPPORT
13088
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013089
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013090RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013091 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013092 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013093 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013094}
13095
13096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013097RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013098 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013099 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013100 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013101}
13102
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013103
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013104// Finds the script object from the script data. NOTE: This operation uses
13105// heap traversal to find the function generated for the source position
13106// for the requested break point. For lazily compiled functions several heap
13107// traversals might be required rendering this operation as a rather slow
13108// operation. However for setting break points which is normally done through
13109// some kind of user interaction the performance is not crucial.
13110static Handle<Object> Runtime_GetScriptFromScriptName(
13111 Handle<String> script_name) {
13112 // Scan the heap for Script objects to find the script with the requested
13113 // script data.
13114 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013115 script_name->GetHeap()->EnsureHeapIsIterable();
13116 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013117 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013118 HeapObject* obj = NULL;
13119 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013120 // If a script is found check if it has the script data requested.
13121 if (obj->IsScript()) {
13122 if (Script::cast(obj)->name()->IsString()) {
13123 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13124 script = Handle<Script>(Script::cast(obj));
13125 }
13126 }
13127 }
13128 }
13129
13130 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013131 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013132
13133 // Return the script found.
13134 return GetScriptWrapper(script);
13135}
13136
13137
13138// Get the script object from script data. NOTE: Regarding performance
13139// see the NOTE for GetScriptFromScriptData.
13140// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013141RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013142 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013143
13144 ASSERT(args.length() == 1);
13145
13146 CONVERT_CHECKED(String, script_name, args[0]);
13147
13148 // Find the requested script.
13149 Handle<Object> result =
13150 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13151 return *result;
13152}
13153
13154
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013155// Determines whether the given stack frame should be displayed in
13156// a stack trace. The caller is the error constructor that asked
13157// for the stack trace to be collected. The first time a construct
13158// call to this function is encountered it is skipped. The seen_caller
13159// in/out parameter is used to remember if the caller has been seen
13160// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013161static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13162 Object* caller,
13163 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013164 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013165 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013166 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013167 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013168 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13169 Object* raw_fun = frame->function();
13170 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013171 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013172 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013173 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013174 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013175 *seen_caller = true;
13176 return false;
13177 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013178 // Skip all frames until we've seen the caller.
13179 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013180 // Also, skip non-visible built-in functions and any call with the builtins
13181 // object as receiver, so as to not reveal either the builtins object or
13182 // an internal function.
13183 // The --builtins-in-stack-traces command line flag allows including
13184 // internal call sites in the stack trace for debugging purposes.
13185 if (!FLAG_builtins_in_stack_traces) {
13186 JSFunction* fun = JSFunction::cast(raw_fun);
13187 if (frame->receiver()->IsJSBuiltinsObject() ||
13188 (fun->IsBuiltin() && !fun->shared()->native())) {
13189 return false;
13190 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013191 }
13192 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013193}
13194
13195
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013196// Collect the raw data for a stack trace. Returns an array of 4
13197// element segments each containing a receiver, function, code and
13198// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013199RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013200 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013201 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013202 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013204 HandleScope scope(isolate);
13205 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013206
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013207 limit = Max(limit, 0); // Ensure that limit is not negative.
13208 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013209 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013210 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013211
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013212 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013213 // If the caller parameter is a function we skip frames until we're
13214 // under it before starting to collect.
13215 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013216 int cursor = 0;
13217 int frames_seen = 0;
13218 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013219 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013220 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013221 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013222 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013223 // Set initial size to the maximum inlining level + 1 for the outermost
13224 // function.
13225 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013226 frame->Summarize(&frames);
13227 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013228 if (cursor + 4 > elements->length()) {
13229 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13230 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013231 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013232 for (int i = 0; i < cursor; i++) {
13233 new_elements->set(i, elements->get(i));
13234 }
13235 elements = new_elements;
13236 }
13237 ASSERT(cursor + 4 <= elements->length());
13238
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013239 Handle<Object> recv = frames[i].receiver();
13240 Handle<JSFunction> fun = frames[i].function();
13241 Handle<Code> code = frames[i].code();
13242 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013243 elements->set(cursor++, *recv);
13244 elements->set(cursor++, *fun);
13245 elements->set(cursor++, *code);
13246 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013247 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013248 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013249 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013250 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013251 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013252 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013253 return *result;
13254}
13255
13256
ager@chromium.org3811b432009-10-28 14:53:37 +000013257// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013258RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013259 ASSERT_EQ(args.length(), 0);
13260
13261 NoHandleAllocation ha;
13262
13263 const char* version_string = v8::V8::GetVersion();
13264
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013265 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13266 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013267}
13268
13269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013270RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013271 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013272 OS::PrintError("abort: %s\n",
13273 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013274 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013275 OS::Abort();
13276 UNREACHABLE();
13277 return NULL;
13278}
13279
13280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013281RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013282 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013283 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013284 Object* key = args[1];
13285
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013286 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013287 Object* o = cache->get(finger_index);
13288 if (o == key) {
13289 // The fastest case: hit the same place again.
13290 return cache->get(finger_index + 1);
13291 }
13292
13293 for (int i = finger_index - 2;
13294 i >= JSFunctionResultCache::kEntriesIndex;
13295 i -= 2) {
13296 o = cache->get(i);
13297 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013298 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013299 return cache->get(i + 1);
13300 }
13301 }
13302
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013303 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013304 ASSERT(size <= cache->length());
13305
13306 for (int i = size - 2; i > finger_index; i -= 2) {
13307 o = cache->get(i);
13308 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013309 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013310 return cache->get(i + 1);
13311 }
13312 }
13313
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013314 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013315 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013316
13317 Handle<JSFunctionResultCache> cache_handle(cache);
13318 Handle<Object> key_handle(key);
13319 Handle<Object> value;
13320 {
13321 Handle<JSFunction> factory(JSFunction::cast(
13322 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13323 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013324 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013325 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013326 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013327 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013328 value = Execution::Call(factory,
13329 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013330 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013331 argv,
13332 &pending_exception);
13333 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013334 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013335
13336#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013337 if (FLAG_verify_heap) {
13338 cache_handle->JSFunctionResultCacheVerify();
13339 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013340#endif
13341
13342 // Function invocation may have cleared the cache. Reread all the data.
13343 finger_index = cache_handle->finger_index();
13344 size = cache_handle->size();
13345
13346 // If we have spare room, put new data into it, otherwise evict post finger
13347 // entry which is likely to be the least recently used.
13348 int index = -1;
13349 if (size < cache_handle->length()) {
13350 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13351 index = size;
13352 } else {
13353 index = finger_index + JSFunctionResultCache::kEntrySize;
13354 if (index == cache_handle->length()) {
13355 index = JSFunctionResultCache::kEntriesIndex;
13356 }
13357 }
13358
13359 ASSERT(index % 2 == 0);
13360 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13361 ASSERT(index < cache_handle->length());
13362
13363 cache_handle->set(index, *key_handle);
13364 cache_handle->set(index + 1, *value);
13365 cache_handle->set_finger_index(index);
13366
13367#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013368 if (FLAG_verify_heap) {
13369 cache_handle->JSFunctionResultCacheVerify();
13370 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013371#endif
13372
13373 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013374}
13375
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013376
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013377RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013378 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013379 CONVERT_ARG_CHECKED(String, type, 0);
13380 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013381 return *isolate->factory()->NewJSMessageObject(
13382 type,
13383 arguments,
13384 0,
13385 0,
13386 isolate->factory()->undefined_value(),
13387 isolate->factory()->undefined_value(),
13388 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013389}
13390
13391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013392RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013393 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13394 return message->type();
13395}
13396
13397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013398RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013399 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13400 return message->arguments();
13401}
13402
13403
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013404RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013405 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13406 return Smi::FromInt(message->start_position());
13407}
13408
13409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013410RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013411 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13412 return message->script();
13413}
13414
13415
kasper.lund44510672008-07-25 07:37:58 +000013416#ifdef DEBUG
13417// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13418// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013419RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013420 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013421 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013422#define COUNT_ENTRY(Name, argc, ressize) + 1
13423 int entry_count = 0
13424 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13425 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13426 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13427#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013428 Factory* factory = isolate->factory();
13429 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013430 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013431 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013432#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013433 { \
13434 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013435 Handle<String> name; \
13436 /* Inline runtime functions have an underscore in front of the name. */ \
13437 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013438 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013439 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13440 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013441 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013442 Vector<const char>(#Name, StrLength(#Name))); \
13443 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013444 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013445 pair_elements->set(0, *name); \
13446 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013447 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013448 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013449 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013450 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013451 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013452 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013453 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013454 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013455#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013456 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013457 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013458 return *result;
13459}
kasper.lund44510672008-07-25 07:37:58 +000013460#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013461
13462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013463RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013464 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013465 CONVERT_CHECKED(String, format, args[0]);
13466 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013467 String::FlatContent format_content = format->GetFlatContent();
13468 RUNTIME_ASSERT(format_content.IsAscii());
13469 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013470 LOGGER->LogRuntime(chars, elms);
13471 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013472}
13473
13474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013475RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013476 UNREACHABLE(); // implemented as macro in the parser
13477 return NULL;
13478}
13479
13480
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013481#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13482 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13483 CONVERT_CHECKED(JSObject, obj, args[0]); \
13484 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13485 }
13486
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013487ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013488ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13489ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13490ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13491ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13492ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13493ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13494ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13495ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13496ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13497ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13498ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13499ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13500ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13501
13502#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13503
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013504
13505RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13506 ASSERT(args.length() == 2);
13507 CONVERT_CHECKED(JSObject, obj1, args[0]);
13508 CONVERT_CHECKED(JSObject, obj2, args[1]);
13509 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13510}
13511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013512// ----------------------------------------------------------------------------
13513// Implementation of Runtime
13514
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013515#define F(name, number_of_args, result_size) \
13516 { Runtime::k##name, Runtime::RUNTIME, #name, \
13517 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013518
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013519
13520#define I(name, number_of_args, result_size) \
13521 { Runtime::kInline##name, Runtime::INLINE, \
13522 "_" #name, NULL, number_of_args, result_size },
13523
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013524static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013525 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013526 INLINE_FUNCTION_LIST(I)
13527 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013528};
13529
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013530
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013531MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13532 Object* dictionary) {
13533 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013534 ASSERT(dictionary != NULL);
13535 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13536 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013537 Object* name_symbol;
13538 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013539 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013540 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13541 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013542 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013543 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13544 String::cast(name_symbol),
13545 Smi::FromInt(i),
13546 PropertyDetails(NONE, NORMAL));
13547 if (!maybe_dictionary->ToObject(&dictionary)) {
13548 // Non-recoverable failure. Calling code must restart heap
13549 // initialization.
13550 return maybe_dictionary;
13551 }
13552 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013553 }
13554 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013555}
13556
13557
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013558const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13559 Heap* heap = name->GetHeap();
13560 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013561 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013562 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013563 int function_index = Smi::cast(smi_index)->value();
13564 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013565 }
13566 return NULL;
13567}
13568
13569
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013570const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013571 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13572}
13573
13574
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013575void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013576 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013577 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013578 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013579 if (isolate->heap()->new_space()->AddFreshPage()) {
13580 return;
13581 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013582 // Try to do a garbage collection; ignore it if it fails. The C
13583 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013584 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013585 } else {
13586 // Handle last resort GC and make sure to allow future allocations
13587 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013588 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013589 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013590 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013591}
13592
13593
13594} } // namespace v8::internal